Merge remote-tracking branch 'origin/4.18'
diff --git a/.asf.yaml b/.asf.yaml
index a0ba915..e16eb20 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -27,11 +27,16 @@
     - infrastructure
     - java
     - python
-    - hosting
     - kvm
+    - libvirt
     - vsphere
+    - vmware
     - xenserver
     - xcp-ng
+    - orchestration
+    - virtualization
+    - virtual-machine
+    - kubernetes
 
   features:
     wiki: true
@@ -44,6 +49,11 @@
     rebase: false
 
   collaborators:
+    - kiranchavala
+    - rajujith
+    - alexandremattioli
+    - vishesh92
+    - soreana
     - acs-robot
 
   protected_branches: ~
diff --git a/.github/linters/.flake8 b/.github/linters/.flake8
index 6a2235d..1c239ac 100644
--- a/.github/linters/.flake8
+++ b/.github/linters/.flake8
@@ -20,6 +20,8 @@
 # E242 Tab after ','
 # E273 Tab after keyword
 # E274 Tab before keyword
+# E742 Do not define classes named 'I', 'O', or 'l'
+# E743 Do not define functions named 'I', 'O', or 'l'
 # E901 SyntaxError or IndentationError
 # E902 IOError
 # W291 Trailing whitespace
@@ -28,4 +30,4 @@
 # W391 Blank line at end of file
 
 [flake8]
-select = E223,E224,E242,E273,E274,E901,E902,W291,W292,W293,W391
+select = E223,E224,E242,E273,E274,E742,E743,E901,E902,W291,W292,W293,W391
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 94ebf10..d0061cb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -80,7 +80,8 @@
                   smoke/test_metrics_api
                   smoke/test_migration
                   smoke/test_multipleips_per_nic
-                  smoke/test_nested_virtualization",
+                  smoke/test_nested_virtualization
+                  smoke/test_set_sourcenat",
                 "smoke/test_network
                   smoke/test_network_acl
                   smoke/test_network_ipv6
@@ -124,6 +125,7 @@
                   smoke/test_usage
                   smoke/test_usage_events
                   smoke/test_vm_deployment_planner
+                  smoke/test_vm_schedule
                   smoke/test_vm_life_cycle
                   smoke/test_vm_lifecycle_unmanage_import
                   smoke/test_vm_snapshot_kvm
diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml
index 778acf0..1ef7b65 100644
--- a/.github/workflows/codecov.yml
+++ b/.github/workflows/codecov.yml
@@ -33,6 +33,8 @@
     runs-on: ubuntu-22.04
     steps:
       - uses: actions/checkout@v3
+        with:
+          fetch-depth: 0
 
       - name: Set up JDK11
         uses: actions/setup-java@v3
diff --git a/.github/workflows/main-sonar-check.yml b/.github/workflows/main-sonar-check.yml
index d036577..f82819a 100644
--- a/.github/workflows/main-sonar-check.yml
+++ b/.github/workflows/main-sonar-check.yml
@@ -22,6 +22,10 @@
     branches:
       - main
 
+permissions:
+  contents: read # to fetch code (actions/checkout)
+  pull-requests: write # for sonar to comment on pull-request
+
 jobs:
   build:
     if: github.repository == 'apache/cloudstack'
diff --git a/.github/workflows/sonar-check.yml b/.github/workflows/sonar-check.yml
index 196cbc9..53c7802 100644
--- a/.github/workflows/sonar-check.yml
+++ b/.github/workflows/sonar-check.yml
@@ -20,7 +20,8 @@
 on: [pull_request]
 
 permissions:
-  contents: read
+  contents: read # to fetch code (actions/checkout)
+  pull-requests: write # for sonar to comment on pull-request
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 773507c..7501478 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -36,7 +36,7 @@
       #- id: check-yaml
       #- id: detect-private-key
       - id: end-of-file-fixer
-        files: \.(java|md|py|txt|yaml|yml)$
+        exclude: \.vhd$
       #- id: fix-byte-order-marker
       - id: mixed-line-ending
         files: \.(java|md|py|txt|yaml|yml)$
diff --git a/CHANGES.md b/CHANGES.md
index 6d6a268..ef498f8 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,7 +2,7 @@
 Apache CloudStack CHANGES
 =========================
 
-Full release notes for each release are located in the project's documentation [website](http://docs.cloudstack.apache.org/projects/cloudstack-release-notes)
+Full release notes for each release are located in the project's documentation [website](https://docs.cloudstack.apache.org/en/latest/releasenotes/index.html)
 
 Version 4.5.0
 -------------
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ec3bb87..cdfbfe7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -42,7 +42,7 @@
 
 On your computer, follow these steps to setup a local repository for working on ACS:
 
-``` bash
+```bash
 $ git clone https://github.com/YOUR_ACCOUNT/cloudstack.git
 $ cd cloudstack
 $ git remote add upstream https://github.com/apache/cloudstack.git
@@ -60,7 +60,7 @@
 
 It is best practice to create a new branch each time you want to contribute to the project and only track the changes for that pull request in this branch.
 
-``` bash
+```bash
 $ git checkout -b feature_x
    (make your changes)
 $ git status
@@ -82,7 +82,7 @@
 2. Synchronize your local `main` branch with the `upstream/main` so you have all the latest changes from the project
 3. Rebase the latest project code into your `feature_x` branch so it is up-to-date with the upstream code
 
-``` bash
+```bash
 $ git checkout main
 $ git fetch upstream
 $ git rebase upstream/main
@@ -102,7 +102,7 @@
 
 > **IMPORTANT:** Make sure you have rebased your `feature_x` branch to include the latest code from `upstream/main` _before_ you do this.
 
-``` bash
+```bash
 $ git push origin main
 $ git push origin feature_x
 ```
@@ -128,7 +128,7 @@
 
 You can delete these deprecated branches with the following:
 
-``` bash
+```bash
 $ git checkout main
 $ git branch -D feature_x
 $ git push origin :feature_x
diff --git a/LICENSE b/LICENSE
index 48d8526..8be7d80 100644
--- a/LICENSE
+++ b/LICENSE
@@ -624,4 +624,3 @@
         from The Apache Software Foundation  http://www.apache.org/ 
             EasySSLProtocolSocketFactory.java 
             EasyX509TrustManager.java 
-
diff --git a/README.md b/README.md
index e56857e..57cd8b8 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,7 @@
 ## Documentation
 
 * [Project Documentation](https://docs.cloudstack.apache.org)
-* [Release notes](https://docs.cloudstack.apache.org/projects/cloudstack-release-notes)
+* [Release notes](https://docs.cloudstack.apache.org/en/latest/releasenotes/index.html)
 * Developer [wiki](https://cwiki.apache.org/confluence/display/CLOUDSTACK/Home)
 * Design [documents](https://cwiki.apache.org/confluence/display/CLOUDSTACK/Design)
 * API [documentation](https://cloudstack.apache.org/api.html)
@@ -135,7 +135,7 @@
 reside may have restrictions on the import, possession, use, and/or re-export to another
 country, of encryption software. BEFORE using any encryption software, please check your
 country's laws, regulations and policies concerning the import, possession, or use, and
-re-export of encryption software, to see if this is permitted. See http://www.wassenaar.org/
+re-export of encryption software, to see if this is permitted. See [The Wassenaar Arrangement](http://www.wassenaar.org/) 
 for more information.
 
 The U.S. Government Department of Commerce, Bureau of Industry and Security (BIS), has
diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties
index 27c0e387..9174da7 100644
--- a/agent/conf/agent.properties
+++ b/agent/conf/agent.properties
@@ -398,3 +398,7 @@
 
 # The number of iothreads. There should be only 1 or 2 IOThreads per VM CPU (default is 1). The recommended number of iothreads is 1
 # iothreads=1
+
+# The path of an executable file/script for host health check for CloudStack to Auto Disable/Enable the host
+# depending on the return value of the file/script
+# agent.health.check.script.path=
diff --git a/agent/pom.xml b/agent/pom.xml
index c93b4e2..5fe88c8 100644
--- a/agent/pom.xml
+++ b/agent/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
     </parent>
     <dependencies>
         <dependency>
diff --git a/agent/src/main/java/com/cloud/agent/dhcp/DhcpProtocolParserServer.java b/agent/src/main/java/com/cloud/agent/dhcp/DhcpProtocolParserServer.java
index 5d75acf..0ee9fd6 100644
--- a/agent/src/main/java/com/cloud/agent/dhcp/DhcpProtocolParserServer.java
+++ b/agent/src/main/java/com/cloud/agent/dhcp/DhcpProtocolParserServer.java
@@ -52,7 +52,6 @@
                     byte[] buf = new byte[bufferSize];
                     DatagramPacket dgp = new DatagramPacket(buf, buf.length);
                     dhcpSocket.receive(dgp);
-                    // _executor.execute(new DhcpPacketParser(buf));
                 }
             } catch (IOException e) {
                 s_logger.debug(e.getMessage());
diff --git a/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java b/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java
index 5c7f4ed..75248fb 100644
--- a/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java
+++ b/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java
@@ -312,6 +312,9 @@
      */
     public static final Property<String> OPENVSWITCH_DPDK_OVS_PATH = new Property<>("openvswitch.dpdk.ovs.path", null, String.class);
 
+    public static final Property<String> HEALTH_CHECK_SCRIPT_PATH =
+            new Property<>("agent.health.check.script.path", null, String.class);
+
     /**
      * Sets the hypervisor type.<br>
      * Possible values: kvm | lxc <br>
diff --git a/agent/src/test/java/com/cloud/agent/AgentShellTest.java b/agent/src/test/java/com/cloud/agent/AgentShellTest.java
index 27bc3dc..f715177 100644
--- a/agent/src/test/java/com/cloud/agent/AgentShellTest.java
+++ b/agent/src/test/java/com/cloud/agent/AgentShellTest.java
@@ -26,20 +26,21 @@
 
 import com.cloud.agent.properties.AgentProperties;
 import com.cloud.agent.properties.AgentPropertiesFileHandler;
+import org.junit.After;
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 
 import com.cloud.utils.StringUtils;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 import org.mockito.Spy;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
-@RunWith(PowerMockRunner.class)
+@RunWith(MockitoJUnitRunner.class)
 public class AgentShellTest {
 
     @InjectMocks
@@ -58,6 +59,18 @@
     @Mock
     UUID uuidMock;
 
+    MockedStatic<AgentPropertiesFileHandler> agentPropertiesFileHandlerMocked;
+
+    @Before
+    public void setUp() throws Exception {
+         agentPropertiesFileHandlerMocked = Mockito.mockStatic(AgentPropertiesFileHandler.class, Mockito.CALLS_REAL_METHODS);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        agentPropertiesFileHandlerMocked.close();
+    }
+
     @Test
     public void parseCommand() throws ConfigurationException {
         AgentShell shell = new AgentShell();
@@ -106,44 +119,35 @@
     }
 
     @Test
-    @PrepareForTest(AgentPropertiesFileHandler.class)
     public void getPortOrWorkersTestValueIsNullGetFromProperty() {
         int expected = 195;
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
-        PowerMockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn(expected);
+        agentPropertiesFileHandlerMocked.when(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn(expected);
 
         int result = agentShellSpy.getPortOrWorkers(null, propertyIntegerMock);
         Assert.assertEquals(expected, result);
     }
 
     @Test
-    @PrepareForTest(AgentPropertiesFileHandler.class)
     public void getPortOrWorkersTestValueIsNotAValidIntegerReturnDefaultFromProperty() {
         int expected = 42;
-
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
         Mockito.doReturn(expected).when(propertyIntegerMock).getDefaultValue();
 
         int result = agentShellSpy.getPortOrWorkers("test", propertyIntegerMock);
         Assert.assertEquals(expected, result);
 
-        PowerMockito.verifyStatic(AgentPropertiesFileHandler.class, Mockito.never());
-        AgentPropertiesFileHandler.getPropertyValue(Mockito.any());
+        agentPropertiesFileHandlerMocked.verify(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any()), Mockito.never());
     }
 
     @Test
-    @PrepareForTest(AgentPropertiesFileHandler.class)
     public void getPortOrWorkersTestValueIsAValidIntegerReturnValue() {
         int expected = 42;
 
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
         Mockito.doReturn(79).when(propertyIntegerMock).getDefaultValue();
 
         int result = agentShellSpy.getPortOrWorkers(String.valueOf(expected), propertyIntegerMock);
         Assert.assertEquals(expected, result);
 
-        PowerMockito.verifyStatic(AgentPropertiesFileHandler.class, Mockito.never());
-        AgentPropertiesFileHandler.getPropertyValue(Mockito.any());
+        agentPropertiesFileHandlerMocked.verify(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any()), Mockito.never());
     }
 
     @Test
@@ -183,41 +187,34 @@
     }
 
     @Test
-    @PrepareForTest(AgentPropertiesFileHandler.class)
     public void getZoneOrPodTestValueIsNullAndPropertyStartsAndEndsWithAtSignReturnPropertyDefaultValue() {
         String expected = "default";
-
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
-        PowerMockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn("test");
+        agentPropertiesFileHandlerMocked.when(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn("test");
 
         Mockito.doReturn(true).when(agentShellSpy).isValueStartingAndEndingWithAtSign(Mockito.any());
         Mockito.doReturn(expected).when(propertyStringMock).getDefaultValue();
 
         String result = agentShellSpy.getZoneOrPod(null, propertyStringMock);
         Assert.assertEquals(expected, result);
+
     }
 
     @Test
-    @PrepareForTest(AgentPropertiesFileHandler.class)
     public void getZoneOrPodTestValueIsNullAndPropertyDoesNotStartAndEndWithAtSignReturnPropertyDefaultValue() {
         String expected = "test";
 
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
-        PowerMockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn(expected);
+        agentPropertiesFileHandlerMocked.when(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn(expected);
 
         Mockito.doReturn(false).when(agentShellSpy).isValueStartingAndEndingWithAtSign(Mockito.any());
-        Mockito.doReturn("default").when(propertyStringMock).getDefaultValue();
 
         String result = agentShellSpy.getZoneOrPod(null, propertyStringMock);
         Assert.assertEquals(expected, result);
     }
 
     @Test
-    @PrepareForTest(AgentPropertiesFileHandler.class)
     public void getZoneOrPodTestValueIsNotNullAndStartsAndEndsWithAtSignReturnPropertyDefaultValue() {
         String expected = "default";
 
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
 
         Mockito.doReturn(true).when(agentShellSpy).isValueStartingAndEndingWithAtSign(Mockito.any());
         Mockito.doReturn(expected).when(propertyStringMock).getDefaultValue();
@@ -225,25 +222,20 @@
         String result = agentShellSpy.getZoneOrPod("test", propertyStringMock);
         Assert.assertEquals(expected, result);
 
-        PowerMockito.verifyStatic(AgentPropertiesFileHandler.class, Mockito.never());
-        AgentPropertiesFileHandler.getPropertyValue(Mockito.any());
+        agentPropertiesFileHandlerMocked.verify(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any()), Mockito.never());
     }
 
     @Test
-    @PrepareForTest(AgentPropertiesFileHandler.class)
     public void getZoneOrPodTestValueIsNotNullAndDoesNotStartAndEndWithAtSignReturnPropertyDefaultValue() {
         String expected = "test";
 
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
 
         Mockito.doReturn(false).when(agentShellSpy).isValueStartingAndEndingWithAtSign(Mockito.any());
-        Mockito.doReturn("default").when(propertyStringMock).getDefaultValue();
 
         String result = agentShellSpy.getZoneOrPod(expected, propertyStringMock);
         Assert.assertEquals(expected, result);
 
-        PowerMockito.verifyStatic(AgentPropertiesFileHandler.class, Mockito.never());
-        AgentPropertiesFileHandler.getPropertyValue(Mockito.any());
+        agentPropertiesFileHandlerMocked.verify(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any()), Mockito.never());
     }
 
     @Test
@@ -255,12 +247,10 @@
     }
 
     @Test
-    @PrepareForTest(AgentPropertiesFileHandler.class)
     public void getGuidTestGuidIsNullReturnProperty() throws ConfigurationException {
         String expected = "test";
 
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
-        PowerMockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn(expected);
+        agentPropertiesFileHandlerMocked.when(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn(expected);
 
         String result = agentShellSpy.getGuid(null);
 
@@ -268,34 +258,34 @@
     }
 
     @Test
-    @PrepareForTest({AgentShell.class, AgentPropertiesFileHandler.class})
     public void getGuidTestGuidAndPropertyAreNullIsDeveloperGenerateNewUuid() throws ConfigurationException {
         String expected = "test";
 
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class, UUID.class);
-        PowerMockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn(null, true);
-        PowerMockito.when(UUID.randomUUID()).thenReturn(uuidMock);
+        agentPropertiesFileHandlerMocked.when(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn(null, true);
+        MockedStatic<UUID> uuidMocked = Mockito.mockStatic(UUID.class);
+        uuidMocked.when(() -> UUID.randomUUID()).thenReturn(uuidMock);
         Mockito.doReturn(expected).when(uuidMock).toString();
 
         String result = agentShellSpy.getGuid(null);
 
         Assert.assertEquals(expected, result);
+        uuidMocked.close();
     }
 
     @Test(expected = ConfigurationException.class)
-    @PrepareForTest(AgentPropertiesFileHandler.class)
     public void getGuidTestGuidAndPropertyAreNullIsNotDeveloperThrowConfigurationException() throws ConfigurationException {
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
-        PowerMockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn(null, false);
+
+        agentPropertiesFileHandlerMocked.when(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn(null, false);
 
         agentShellSpy.getGuid(null);
     }
 
     @Test
-    @PrepareForTest(AgentPropertiesFileHandler.class)
     public void setHostTestValueIsNotNullAndStartsAndEndsWithAtSignThrowConfigurationException(){
         Mockito.doReturn(true).when(agentShellSpy).isValueStartingAndEndingWithAtSign(Mockito.any());
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
+
+
+
 
         boolean error = false;
 
@@ -309,16 +299,14 @@
             throw new AssertionError("This test expects a ConfigurationException.");
         }
 
-        PowerMockito.verifyStatic(AgentPropertiesFileHandler.class, Mockito.never());
-        AgentPropertiesFileHandler.getPropertyValue(Mockito.any());
+        agentPropertiesFileHandlerMocked.verify(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any()), Mockito.never());
     }
 
     @Test
-    @PrepareForTest(AgentPropertiesFileHandler.class)
     public void setHostTestValueIsNullPropertyStartsAndEndsWithAtSignThrowConfigurationException(){
         Mockito.doReturn(true).when(agentShellSpy).isValueStartingAndEndingWithAtSign(Mockito.any());
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
-        PowerMockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn("test");
+
+        agentPropertiesFileHandlerMocked.when(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn("test");
 
         boolean error = false;
 
@@ -332,37 +320,32 @@
             throw new AssertionError("This test expects a ConfigurationException.");
         }
 
-        PowerMockito.verifyStatic(AgentPropertiesFileHandler.class);
-        AgentPropertiesFileHandler.getPropertyValue(Mockito.any());
+        agentPropertiesFileHandlerMocked.verify(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any()));
     }
 
     @Test
-    @PrepareForTest(AgentPropertiesFileHandler.class)
     public void setHostTestValueIsNotNullAndDoesNotStartAndEndWithAtSignSetHosts() throws ConfigurationException {
         String expected = "test";
         Mockito.doReturn(false).when(agentShellSpy).isValueStartingAndEndingWithAtSign(Mockito.any());
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
 
         agentShellSpy.setHost(expected);
 
-        PowerMockito.verifyStatic(AgentPropertiesFileHandler.class, Mockito.never());
-        AgentPropertiesFileHandler.getPropertyValue(Mockito.any());
+        agentPropertiesFileHandlerMocked.verify(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any()), Mockito.never());
 
         Mockito.verify(agentShellSpy).setHosts(expected);
     }
 
     @Test
-    @PrepareForTest(AgentPropertiesFileHandler.class)
     public void setHostTestValueIsNullPropertyDoesNotStartAndEndWithAtSignSetHosts() throws ConfigurationException {
         String expected = "test";
 
         Mockito.doReturn(false).when(agentShellSpy).isValueStartingAndEndingWithAtSign(Mockito.any());
-        PowerMockito.mockStatic(AgentPropertiesFileHandler.class);
-        PowerMockito.when(AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn(expected);
+
+        agentPropertiesFileHandlerMocked.when(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any())).thenReturn(expected);
 
         agentShellSpy.setHost(null);
 
-        PowerMockito.verifyStatic(AgentPropertiesFileHandler.class);
+        agentPropertiesFileHandlerMocked.verify(() -> AgentPropertiesFileHandler.getPropertyValue(Mockito.any()));
         AgentPropertiesFileHandler.getPropertyValue(Mockito.any());
 
         Mockito.verify(agentShellSpy).setHosts(expected);
diff --git a/agent/src/test/java/com/cloud/agent/properties/AgentPropertiesFileHandlerTest.java b/agent/src/test/java/com/cloud/agent/properties/AgentPropertiesFileHandlerTest.java
index 1a73bf2..749f0f1 100644
--- a/agent/src/test/java/com/cloud/agent/properties/AgentPropertiesFileHandlerTest.java
+++ b/agent/src/test/java/com/cloud/agent/properties/AgentPropertiesFileHandlerTest.java
@@ -24,18 +24,17 @@
 import java.io.IOException;
 import java.util.Properties;
 import junit.framework.TestCase;
-import org.apache.commons.beanutils.ConvertUtils;
+import org.junit.After;
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({PropertiesUtil.class, ConvertUtils.class})
+@RunWith(MockitoJUnitRunner.class)
 public class AgentPropertiesFileHandlerTest extends TestCase {
 
     @Mock
@@ -53,14 +52,27 @@
     @Mock
     Properties propertiesMock;
 
+    MockedStatic<PropertiesUtil> propertiesUtilMocked;
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        propertiesUtilMocked = Mockito.mockStatic(PropertiesUtil.class);
+    }
+
+    @Override
+    @After
+    public void tearDown() throws Exception {
+        propertiesUtilMocked.close();
+    }
+
     @Test
     public void getPropertyValueTestFileNotFoundReturnDefaultValueNull() throws Exception{
         String expectedResult = null;
 
         AgentProperties.Property<String> agentPropertiesStringMock = new AgentProperties.Property<String>("Test-null", null, String.class);
 
-        PowerMockito.mockStatic(PropertiesUtil.class);
-        PowerMockito.doReturn(null).when(PropertiesUtil.class, "findConfigFile", Mockito.anyString());
+        propertiesUtilMocked.when(() -> PropertiesUtil.findConfigFile(Mockito.anyString())).thenReturn(null);
 
         String result = AgentPropertiesFileHandler.getPropertyValue(agentPropertiesStringMock);
 
@@ -72,8 +84,7 @@
         String expectedResult = "default value";
         Mockito.doReturn(expectedResult).when(agentPropertiesStringMock).getDefaultValue();
 
-        PowerMockito.mockStatic(PropertiesUtil.class);
-        PowerMockito.doReturn(null).when(PropertiesUtil.class, "findConfigFile", Mockito.anyString());
+        propertiesUtilMocked.when(() -> PropertiesUtil.findConfigFile(Mockito.anyString())).thenReturn(null);
 
         String result = AgentPropertiesFileHandler.getPropertyValue(agentPropertiesStringMock);
 
@@ -85,9 +96,8 @@
         String expectedResult = "default value";
         Mockito.doReturn(expectedResult).when(agentPropertiesStringMock).getDefaultValue();
 
-        PowerMockito.mockStatic(PropertiesUtil.class);
-        PowerMockito.doReturn(fileMock).when(PropertiesUtil.class, "findConfigFile", Mockito.anyString());
-        PowerMockito.doThrow(new IOException()).when(PropertiesUtil.class, "loadFromFile", Mockito.any());
+        propertiesUtilMocked.when(() -> PropertiesUtil.findConfigFile(Mockito.anyString())).thenReturn(fileMock);
+        propertiesUtilMocked.when(() -> PropertiesUtil.loadFromFile(Mockito.any())).thenThrow(new IOException());
 
         String result = AgentPropertiesFileHandler.getPropertyValue(agentPropertiesStringMock);
 
@@ -100,10 +110,9 @@
         Mockito.doReturn(expectedResult).when(agentPropertiesStringMock).getDefaultValue();
         Mockito.doReturn("name").when(agentPropertiesStringMock).getName();
 
-        PowerMockito.mockStatic(PropertiesUtil.class);
-        PowerMockito.doReturn(fileMock).when(PropertiesUtil.class, "findConfigFile", Mockito.anyString());
-        PowerMockito.doReturn(propertiesMock).when(PropertiesUtil.class, "loadFromFile", Mockito.any());
-        PowerMockito.doReturn("").when(propertiesMock).getProperty(Mockito.anyString());
+        propertiesUtilMocked.when(() -> PropertiesUtil.findConfigFile(Mockito.anyString())).thenReturn(fileMock);
+        propertiesUtilMocked.when(() -> PropertiesUtil.loadFromFile(Mockito.any())).thenReturn(propertiesMock);
+        propertiesUtilMocked.when(() -> propertiesMock.getProperty(Mockito.anyString())).thenReturn("");
 
         String result = AgentPropertiesFileHandler.getPropertyValue(agentPropertiesStringMock);
 
@@ -116,10 +125,9 @@
         Mockito.doReturn(expectedResult).when(agentPropertiesStringMock).getDefaultValue();
         Mockito.doReturn("name").when(agentPropertiesStringMock).getName();
 
-        PowerMockito.mockStatic(PropertiesUtil.class);
-        PowerMockito.doReturn(fileMock).when(PropertiesUtil.class, "findConfigFile", Mockito.anyString());
-        PowerMockito.doReturn(propertiesMock).when(PropertiesUtil.class, "loadFromFile", Mockito.any());
-        PowerMockito.doReturn(null).when(propertiesMock).getProperty(Mockito.anyString());
+        propertiesUtilMocked.when(() -> PropertiesUtil.findConfigFile(Mockito.anyString())).thenReturn(fileMock);
+        propertiesUtilMocked.when(() -> PropertiesUtil.loadFromFile(Mockito.any())).thenReturn(propertiesMock);
+        propertiesUtilMocked.when(() -> propertiesMock.getProperty(Mockito.anyString())).thenReturn(null);
 
         String result = AgentPropertiesFileHandler.getPropertyValue(agentPropertiesStringMock);
 
@@ -132,9 +140,8 @@
         Mockito.doReturn("default value").when(agentPropertiesStringMock).getDefaultValue();
         Mockito.doReturn("name").when(agentPropertiesStringMock).getName();
 
-        PowerMockito.mockStatic(PropertiesUtil.class);
-        PowerMockito.doReturn(fileMock).when(PropertiesUtil.class, "findConfigFile", Mockito.anyString());
-        PowerMockito.doReturn(propertiesMock).when(PropertiesUtil.class, "loadFromFile", Mockito.any());
+        propertiesUtilMocked.when(() -> PropertiesUtil.findConfigFile(Mockito.anyString())).thenReturn(fileMock);
+        propertiesUtilMocked.when(() -> PropertiesUtil.loadFromFile(Mockito.any())).thenReturn(propertiesMock);
         Mockito.doReturn(expectedResult).when(propertiesMock).getProperty(Mockito.anyString());
 
         String result = AgentPropertiesFileHandler.getPropertyValue(agentPropertiesStringMock);
@@ -148,9 +155,8 @@
 
         AgentProperties.Property<String> agentPropertiesStringMock = new AgentProperties.Property<String>("Test-null", null, String.class);
 
-        PowerMockito.mockStatic(PropertiesUtil.class);
-        PowerMockito.doReturn(fileMock).when(PropertiesUtil.class, "findConfigFile", Mockito.anyString());
-        PowerMockito.doReturn(propertiesMock).when(PropertiesUtil.class, "loadFromFile", Mockito.any());
+        propertiesUtilMocked.when(() -> PropertiesUtil.findConfigFile(Mockito.anyString())).thenReturn(fileMock);
+        propertiesUtilMocked.when(() -> PropertiesUtil.loadFromFile(Mockito.any())).thenReturn(propertiesMock);
         Mockito.doReturn(expectedResult).when(propertiesMock).getProperty(Mockito.anyString());
 
         String result = AgentPropertiesFileHandler.getPropertyValue(agentPropertiesStringMock);
@@ -165,9 +171,8 @@
         Mockito.doReturn("name").when(agentPropertiesIntegerMock).getName();
         Mockito.doReturn(Integer.class).when(agentPropertiesIntegerMock).getTypeClass();
 
-        PowerMockito.mockStatic(PropertiesUtil.class);
-        PowerMockito.doReturn(fileMock).when(PropertiesUtil.class, "findConfigFile", Mockito.anyString());
-        PowerMockito.doReturn(propertiesMock).when(PropertiesUtil.class, "loadFromFile", Mockito.any());
+        propertiesUtilMocked.when(() -> PropertiesUtil.findConfigFile(Mockito.anyString())).thenReturn(fileMock);
+        propertiesUtilMocked.when(() -> PropertiesUtil.loadFromFile(Mockito.any())).thenReturn(propertiesMock);
         Mockito.doReturn(String.valueOf(expectedResult)).when(propertiesMock).getProperty(Mockito.anyString());
 
         Integer result = AgentPropertiesFileHandler.getPropertyValue(agentPropertiesIntegerMock);
@@ -182,9 +187,8 @@
         Mockito.doReturn("name").when(agentPropertiesLongMock).getName();
         Mockito.doReturn(Long.class).when(agentPropertiesLongMock).getTypeClass();
 
-        PowerMockito.mockStatic(PropertiesUtil.class);
-        PowerMockito.doReturn(fileMock).when(PropertiesUtil.class, "findConfigFile", Mockito.anyString());
-        PowerMockito.doReturn(propertiesMock).when(PropertiesUtil.class, "loadFromFile", Mockito.any());
+        propertiesUtilMocked.when(() -> PropertiesUtil.findConfigFile(Mockito.anyString())).thenReturn(fileMock);
+        propertiesUtilMocked.when(() -> PropertiesUtil.loadFromFile(Mockito.any())).thenReturn(propertiesMock);
         Mockito.doReturn(String.valueOf(expectedResult)).when(propertiesMock).getProperty(Mockito.anyString());
 
         Long result = AgentPropertiesFileHandler.getPropertyValue(agentPropertiesLongMock);
diff --git a/agent/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/agent/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d4
--- /dev/null
+++ b/agent/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/api/pom.xml b/api/pom.xml
index 1428bee..ff9083a 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
     </parent>
     <dependencies>
         <dependency>
diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java
index f7678d9..484dc9b 100644
--- a/api/src/main/java/com/cloud/event/EventTypes.java
+++ b/api/src/main/java/com/cloud/event/EventTypes.java
@@ -84,6 +84,7 @@
 import com.cloud.vm.Nic;
 import com.cloud.vm.NicSecondaryIp;
 import com.cloud.vm.VirtualMachine;
+import org.apache.cloudstack.vm.schedule.VMSchedule;
 
 public class EventTypes {
 
@@ -111,6 +112,17 @@
     public static final String EVENT_VM_UNMANAGE = "VM.UNMANAGE";
     public static final String EVENT_VM_RECOVER = "VM.RECOVER";
 
+    // VM Schedule
+    public static final String EVENT_VM_SCHEDULE_CREATE = "VM.SCHEDULE.CREATE";
+    public static final String EVENT_VM_SCHEDULE_UPDATE = "VM.SCHEDULE.UPDATE";
+    public static final String EVENT_VM_SCHEDULE_DELETE = "VM.SCHEDULE.DELETE";
+
+    public static final String EVENT_VM_SCHEDULE_START = "VM.SCHEDULE.START";
+    public static final String EVENT_VM_SCHEDULE_STOP = "VM.SCHEDULE.STOP";
+    public static final String EVENT_VM_SCHEDULE_REBOOT = "VM.SCHEDULE.REBOOT";
+    public static final String EVENT_VM_SCHEDULE_FORCE_STOP = "VM.SCHEDULE.FORCE.STOP";
+    public static final String EVENT_VM_SCHEDULE_FORCE_REBOOT = "VM.SCHEDULE.FORCE.REBOOT";
+
     // Domain Router
     public static final String EVENT_ROUTER_CREATE = "ROUTER.CREATE";
     public static final String EVENT_ROUTER_DESTROY = "ROUTER.DESTROY";
@@ -655,6 +667,7 @@
     public static final String EVENT_GUEST_OS_MAPPING_ADD = "GUEST.OS.MAPPING.ADD";
     public static final String EVENT_GUEST_OS_MAPPING_REMOVE = "GUEST.OS.MAPPING.REMOVE";
     public static final String EVENT_GUEST_OS_MAPPING_UPDATE = "GUEST.OS.MAPPING.UPDATE";
+    public static final String EVENT_GUEST_OS_HYPERVISOR_NAME_FETCH = "GUEST.OS.HYPERVISOR.NAME.FETCH";
 
     public static final String EVENT_NIC_SECONDARY_IP_ASSIGN = "NIC.SECONDARY.IP.ASSIGN";
     public static final String EVENT_NIC_SECONDARY_IP_UNASSIGN = "NIC.SECONDARY.IP.UNASSIGN";
@@ -716,6 +729,16 @@
         entityEventDetails.put(EVENT_VM_IMPORT, VirtualMachine.class);
         entityEventDetails.put(EVENT_VM_UNMANAGE, VirtualMachine.class);
 
+        // VMSchedule
+        entityEventDetails.put(EVENT_VM_SCHEDULE_CREATE, VMSchedule.class);
+        entityEventDetails.put(EVENT_VM_SCHEDULE_DELETE, VMSchedule.class);
+        entityEventDetails.put(EVENT_VM_SCHEDULE_UPDATE, VMSchedule.class);
+        entityEventDetails.put(EVENT_VM_SCHEDULE_START, VMSchedule.class);
+        entityEventDetails.put(EVENT_VM_SCHEDULE_STOP, VMSchedule.class);
+        entityEventDetails.put(EVENT_VM_SCHEDULE_REBOOT, VMSchedule.class);
+        entityEventDetails.put(EVENT_VM_SCHEDULE_FORCE_STOP, VMSchedule.class);
+        entityEventDetails.put(EVENT_VM_SCHEDULE_FORCE_REBOOT, VMSchedule.class);
+
         entityEventDetails.put(EVENT_ROUTER_CREATE, VirtualRouter.class);
         entityEventDetails.put(EVENT_ROUTER_DESTROY, VirtualRouter.class);
         entityEventDetails.put(EVENT_ROUTER_START, VirtualRouter.class);
@@ -1092,6 +1115,7 @@
         entityEventDetails.put(EVENT_GUEST_OS_MAPPING_ADD, GuestOSHypervisor.class);
         entityEventDetails.put(EVENT_GUEST_OS_MAPPING_REMOVE, GuestOSHypervisor.class);
         entityEventDetails.put(EVENT_GUEST_OS_MAPPING_UPDATE, GuestOSHypervisor.class);
+        entityEventDetails.put(EVENT_GUEST_OS_HYPERVISOR_NAME_FETCH, GuestOSHypervisor.class);
         entityEventDetails.put(EVENT_NIC_SECONDARY_IP_ASSIGN, NicSecondaryIp.class);
         entityEventDetails.put(EVENT_NIC_SECONDARY_IP_UNASSIGN, NicSecondaryIp.class);
         entityEventDetails.put(EVENT_NIC_SECONDARY_IP_CONFIGURE, NicSecondaryIp.class);
diff --git a/api/src/main/java/com/cloud/network/Network.java b/api/src/main/java/com/cloud/network/Network.java
index a2633ec7..458169c 100644
--- a/api/src/main/java/com/cloud/network/Network.java
+++ b/api/src/main/java/com/cloud/network/Network.java
@@ -256,7 +256,7 @@
 
     public static class Capability {
 
-        private static List<Capability> supportedCapabilities = new ArrayList<Capability>();
+        private static List<Capability> supportedCapabilities = new ArrayList<>();
 
         public static final Capability SupportedProtocols = new Capability("SupportedProtocols");
         public static final Capability SupportedLBAlgorithms = new Capability("SupportedLbAlgorithms");
diff --git a/api/src/main/java/com/cloud/network/vpc/VpcService.java b/api/src/main/java/com/cloud/network/vpc/VpcService.java
index 362a110..2cdc034 100644
--- a/api/src/main/java/com/cloud/network/vpc/VpcService.java
+++ b/api/src/main/java/com/cloud/network/vpc/VpcService.java
@@ -23,7 +23,9 @@
 import org.apache.cloudstack.api.command.user.vpc.CreateVPCCmd;
 import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd;
 import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd;
+import org.apache.cloudstack.api.command.user.vpc.ListVPCsCmd;
 import org.apache.cloudstack.api.command.user.vpc.RestartVPCCmd;
+import org.apache.cloudstack.api.command.user.vpc.UpdateVPCCmd;
 
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientAddressCapacityException;
@@ -37,7 +39,6 @@
 
 public interface VpcService {
 
-    public Vpc createVpc(CreateVPCCmd cmd) throws ResourceAllocationException;
     /**
      * Persists VPC record in the database
      *
@@ -48,15 +49,26 @@
      * @param displayText
      * @param cidr
      * @param networkDomain TODO
+     * @param ip4Dns1
+     * @param ip4Dns2
      * @param displayVpc TODO
      * @return
      * @throws ResourceAllocationException TODO
      */
-    public Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, String displayText, String cidr, String networkDomain,
-                         String dns1, String dns2, String ip6Dns1, String ip6Dns2, Boolean displayVpc, Integer publicMtu)
+    Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, String displayText, String cidr, String networkDomain,
+                  String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2, Boolean displayVpc, Integer publicMtu)
             throws ResourceAllocationException;
 
     /**
+     * Persists VPC record in the database
+     *
+     * @param cmd the command with specification data for the new vpc
+     * @return a data object describing the new vpc
+     * @throws ResourceAllocationException the resources for this VPC cannot be allocated
+     */
+    Vpc createVpc(CreateVPCCmd cmd) throws ResourceAllocationException;
+
+    /**
      * Deletes a VPC
      *
      * @param vpcId
@@ -65,48 +77,48 @@
      * @throws ResourceUnavailableException
      * @throws ConcurrentOperationException
      */
-    public boolean deleteVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException;
+    boolean deleteVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException;
+
+    /**
+     * Persists VPC record in the database
+     *
+     * @param cmd the command with specification data for updating the vpc
+     * @return a data object describing the new vpc state
+     * @throws ResourceUnavailableException if during restart some resources may not be available
+     * @throws InsufficientCapacityException if for instance no address space, compute or storage is sufficiently available
+     */
+    Vpc updateVpc(UpdateVPCCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException;
 
     /**
      * Updates VPC with new name/displayText
      *
-     * @param vpcId
-     * @param vpcName
-     * @param displayText
-     * @param customId    TODO
-     * @param displayVpc  TODO
-     * @param mtu
-     * @return
+     * @param vpcId the ID of the Vpc to update
+     * @param vpcName The new name to give the vpc
+     * @param displayText the new display text to use for describing the VPC
+     * @param customId A new custom (external) ID to associate this VPC with
+     * @param displayVpc should this VPC be displayed on public lists
+     * @param mtu what maximal transfer unit to us in this VPCs networks
+     * @param sourceNatIp the source NAT address to use for this VPC (must already be associated with the VPC)
+     * @return an object describing the current state of the VPC
+     * @throws ResourceUnavailableException if during restart some resources may not be available
+     * @throws InsufficientCapacityException if for instance no address space, compute or storage is sufficiently available
      */
-    public Vpc updateVpc(long vpcId, String vpcName, String displayText, String customId, Boolean displayVpc, Integer mtu);
+    Vpc updateVpc(long vpcId, String vpcName, String displayText, String customId, Boolean displayVpc, Integer mtu, String sourceNatIp) throws ResourceUnavailableException, InsufficientCapacityException;
+
+    /**
+     * Lists VPC(s) based on the parameters passed to the API call
+     *
+     * @param cmd object containing the search specs
+     * @return the List of VPCs
+     */
+    Pair<List<? extends Vpc>, Integer> listVpcs(ListVPCsCmd cmd);
 
     /**
      * Lists VPC(s) based on the parameters passed to the method call
-     *
-     * @param id
-     * @param vpcName
-     * @param displayText
-     * @param supportedServicesStr
-     * @param cidr
-     * @param state TODO
-     * @param accountName
-     * @param domainId
-     * @param keyword
-     * @param startIndex
-     * @param pageSizeVal
-     * @param zoneId TODO
-     * @param isRecursive TODO
-     * @param listAll TODO
-     * @param restartRequired TODO
-     * @param tags TODO
-     * @param projectId TODO
-     * @param display TODO
-     * @param vpc
-     * @return
      */
-    public Pair<List<? extends Vpc>, Integer> listVpcs(Long id, String vpcName, String displayText, List<String> supportedServicesStr, String cidr, Long vpcOffId, String state,
-            String accountName, Long domainId, String keyword, Long startIndex, Long pageSizeVal, Long zoneId, Boolean isRecursive, Boolean listAll, Boolean restartRequired,
-            Map<String, String> tags, Long projectId, Boolean display);
+    Pair<List<? extends Vpc>, Integer> listVpcs(Long id, String vpcName, String displayText, List<String> supportedServicesStr, String cidr, Long vpcOffId, String state,
+                                                String accountName, Long domainId, String keyword, Long startIndex, Long pageSizeVal, Long zoneId, Boolean isRecursive, Boolean listAll, Boolean restartRequired,
+                                                Map<String, String> tags, Long projectId, Boolean display);
 
     /**
      * Starts VPC which includes starting VPC provider and applying all the networking rules on the backend
@@ -130,17 +142,17 @@
      */
     boolean shutdownVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException;
 
+    boolean restartVpc(RestartVPCCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
+
     /**
      * Restarts the VPC. VPC gets shutdown and started as a part of it
      *
-     * @param id
-     * @param cleanUp
-     * @param makeredundant
-     * @return
-     * @throws InsufficientCapacityException
+     * @param networkId the network to restart
+     * @param cleanup throw away the existing VR and rebuild a new one?
+     * @param makeRedundant create two VRs for this network
+     * @return success or not
+     * @throws InsufficientCapacityException when there is no suitable deployment plan possible
      */
-    boolean restartVpc(RestartVPCCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
-
     boolean restartVpc(Long networkId, boolean cleanup, boolean makeRedundant, boolean livePatch, User user) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
 
     /**
@@ -154,23 +166,12 @@
     /**
      * Persists VPC private gateway in the Database.
      *
-     *
-     * @param vpcId TODO
-     * @param physicalNetworkId
-     * @param vlan
-     * @param ipAddress
-     * @param gateway
-     * @param netmask
-     * @param gatewayOwnerId
-     * @param networkOfferingId
-     * @param isSourceNat
-     * @param aclId
-     * @return
+     * @return data object describing the private gateway
      * @throws InsufficientCapacityException
      * @throws ConcurrentOperationException
      * @throws ResourceAllocationException
      */
-    public PrivateGateway createVpcPrivateGateway(CreatePrivateGatewayCmd command) throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException;
+    PrivateGateway createVpcPrivateGateway(CreatePrivateGatewayCmd command) throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException;
 
     /**
      * Applies VPC private gateway on the backend, so it becomes functional
@@ -181,12 +182,12 @@
      * @throws ResourceUnavailableException
      * @throws ConcurrentOperationException
      */
-    public PrivateGateway applyVpcPrivateGateway(long gatewayId, boolean destroyOnFailure) throws ConcurrentOperationException, ResourceUnavailableException;
+    PrivateGateway applyVpcPrivateGateway(long gatewayId, boolean destroyOnFailure) throws ConcurrentOperationException, ResourceUnavailableException;
 
     /**
      * Deletes VPC private gateway
      *
-     * @param id
+     * @param gatewayId
      * @return
      * @throws ResourceUnavailableException
      * @throws ConcurrentOperationException
@@ -199,7 +200,7 @@
      * @param listPrivateGatewaysCmd
      * @return
      */
-    public Pair<List<PrivateGateway>, Integer> listPrivateGateway(ListPrivateGatewaysCmd listPrivateGatewaysCmd);
+    Pair<List<PrivateGateway>, Integer> listPrivateGateway(ListPrivateGatewaysCmd listPrivateGatewaysCmd);
 
     /**
      * Returns Static Route found by Id
@@ -216,7 +217,7 @@
      * @return
      * @throws ResourceUnavailableException
      */
-    public boolean applyStaticRoutesForVpc(long vpcId) throws ResourceUnavailableException;
+    boolean applyStaticRoutesForVpc(long vpcId) throws ResourceUnavailableException;
 
     /**
      * Deletes static route from the backend and the database
@@ -225,7 +226,7 @@
      * @return TODO
      * @throws ResourceUnavailableException
      */
-    public boolean revokeStaticRoute(long routeId) throws ResourceUnavailableException;
+    boolean revokeStaticRoute(long routeId) throws ResourceUnavailableException;
 
     /**
      * Persists static route entry in the Database
@@ -234,15 +235,15 @@
      * @param cidr
      * @return
      */
-    public StaticRoute createStaticRoute(long gatewayId, String cidr) throws NetworkRuleConflictException;
+    StaticRoute createStaticRoute(long gatewayId, String cidr) throws NetworkRuleConflictException;
 
     /**
      * Lists static routes based on parameters passed to the call
      *
-     * @param listStaticRoutesCmd
+     * @param cmd Command object with parameters for { @see ListStaticRoutesCmd }
      * @return
      */
-    public Pair<List<? extends StaticRoute>, Integer> listStaticRoutes(ListStaticRoutesCmd cmd);
+    Pair<List<? extends StaticRoute>, Integer> listStaticRoutes(ListStaticRoutesCmd cmd);
 
     /**
      * Associates IP address from the Public network, to the VPC
@@ -262,6 +263,5 @@
      * @param routeId
      * @return
      */
-    public boolean applyStaticRoute(long routeId) throws ResourceUnavailableException;
-
+    boolean applyStaticRoute(long routeId) throws ResourceUnavailableException;
 }
diff --git a/api/src/main/java/com/cloud/projects/ProjectService.java b/api/src/main/java/com/cloud/projects/ProjectService.java
index f93b3c5..5080cb5 100644
--- a/api/src/main/java/com/cloud/projects/ProjectService.java
+++ b/api/src/main/java/com/cloud/projects/ProjectService.java
@@ -78,9 +78,9 @@
 
     Project findByNameAndDomainId(String name, long domainId);
 
-    Project updateProject(long id, String displayText, String newOwnerName) throws ResourceAllocationException;
+    Project updateProject(long id, String name, String displayText, String newOwnerName) throws ResourceAllocationException;
 
-    Project updateProject(long id, String displayText, String newOwnerName, Long userId, Role newRole) throws ResourceAllocationException;
+    Project updateProject(long id, String name, String displayText, String newOwnerName, Long userId, Role newRole) throws ResourceAllocationException;
 
     boolean addAccountToProject(long projectId, String accountName, String email, Long projectRoleId, Role projectRoleType);
 
diff --git a/api/src/main/java/com/cloud/resource/ResourceService.java b/api/src/main/java/com/cloud/resource/ResourceService.java
index e2b84ba..2757c91 100644
--- a/api/src/main/java/com/cloud/resource/ResourceService.java
+++ b/api/src/main/java/com/cloud/resource/ResourceService.java
@@ -49,6 +49,8 @@
      */
     Host updateHost(UpdateHostCmd cmd) throws NoTransitionException;
 
+    Host autoUpdateHostAllocationState(Long hostId, ResourceState.Event resourceEvent) throws NoTransitionException;
+
     Host cancelMaintenance(CancelMaintenanceCmd cmd);
 
     Host reconnectHost(ReconnectHostCmd cmd) throws AgentUnavailableException;
diff --git a/api/src/main/java/com/cloud/server/ManagementService.java b/api/src/main/java/com/cloud/server/ManagementService.java
index df44ec6..14d46e0 100644
--- a/api/src/main/java/com/cloud/server/ManagementService.java
+++ b/api/src/main/java/com/cloud/server/ManagementService.java
@@ -27,6 +27,7 @@
 import org.apache.cloudstack.api.command.admin.config.UpdateHypervisorCapabilitiesCmd;
 import org.apache.cloudstack.api.command.admin.guest.AddGuestOsCmd;
 import org.apache.cloudstack.api.command.admin.guest.AddGuestOsMappingCmd;
+import org.apache.cloudstack.api.command.admin.guest.GetHypervisorGuestOsNamesCmd;
 import org.apache.cloudstack.api.command.admin.guest.ListGuestOsMappingCmd;
 import org.apache.cloudstack.api.command.admin.guest.RemoveGuestOsCmd;
 import org.apache.cloudstack.api.command.admin.guest.RemoveGuestOsMappingCmd;
@@ -189,6 +190,12 @@
     GuestOSHypervisor getAddedGuestOsMapping(Long guestOsHypervisorId);
 
     /**
+     * Get hypervisor guest OS names
+     *
+     * @return the hypervisor guest OS name that can be used for mapping, with guest OS name, and the name of guest OS specific to hypervisor
+     */
+    List<Pair<String, String>> getHypervisorGuestOsNames(GetHypervisorGuestOsNamesCmd getHypervisorGuestOsNamesCmd);
+    /**
      * Adds a new guest OS
      *
      * @return A VO containing the new guest OS, with its category ID, name and display name
diff --git a/api/src/main/java/com/cloud/storage/Volume.java b/api/src/main/java/com/cloud/storage/Volume.java
index 57db35f..4a14197 100644
--- a/api/src/main/java/com/cloud/storage/Volume.java
+++ b/api/src/main/java/com/cloud/storage/Volume.java
@@ -57,7 +57,8 @@
         UploadInProgress("Volume upload is in progress"),
         UploadError("Volume upload encountered some error"),
         UploadAbandoned("Volume upload is abandoned since the upload was never initiated within a specified time"),
-        Attaching("The volume is attaching to a VM from Ready state.");
+        Attaching("The volume is attaching to a VM from Ready state."),
+        Restoring("The volume is being restored from backup.");
 
         String _description;
 
@@ -133,6 +134,11 @@
             s_fsm.addTransition(new StateMachine2.Transition<State, Event>(Attaching, Event.OperationSucceeded, Ready, null));
             s_fsm.addTransition(new StateMachine2.Transition<State, Event>(Attaching, Event.OperationFailed, Ready, null));
             s_fsm.addTransition(new StateMachine2.Transition<State, Event>(Destroy, Event.RecoverRequested, Ready, null));
+            s_fsm.addTransition(new StateMachine2.Transition<State, Event>(Ready, Event.RestoreRequested, Restoring, null));
+            s_fsm.addTransition(new StateMachine2.Transition<State, Event>(Expunged, Event.RestoreRequested, Restoring, null));
+            s_fsm.addTransition(new StateMachine2.Transition<State, Event>(Destroy, Event.RestoreRequested, Restoring, null));
+            s_fsm.addTransition(new StateMachine2.Transition<State, Event>(Restoring, Event.RestoreSucceeded, Ready, null));
+            s_fsm.addTransition(new StateMachine2.Transition<State, Event>(Restoring, Event.RestoreFailed, Ready, null));
         }
     }
 
@@ -156,7 +162,10 @@
         ExpungingRequested,
         ResizeRequested,
         AttachRequested,
-        OperationTimeout;
+        OperationTimeout,
+        RestoreRequested,
+        RestoreSucceeded,
+        RestoreFailed;
     }
 
     /**
diff --git a/api/src/main/java/com/cloud/storage/VolumeApiService.java b/api/src/main/java/com/cloud/storage/VolumeApiService.java
index e5c938b..09a3a33 100644
--- a/api/src/main/java/com/cloud/storage/VolumeApiService.java
+++ b/api/src/main/java/com/cloud/storage/VolumeApiService.java
@@ -21,6 +21,7 @@
 import java.net.MalformedURLException;
 import java.util.Map;
 
+import com.cloud.utils.fsm.NoTransitionException;
 import org.apache.cloudstack.api.command.user.volume.AssignVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.ChangeOfferingForVolumeCmd;
@@ -174,4 +175,6 @@
     Volume changeDiskOfferingForVolume(ChangeOfferingForVolumeCmd cmd) throws ResourceAllocationException;
 
     void publishVolumeCreationUsageEvent(Volume volume);
+
+    boolean stateTransitTo(Volume vol, Volume.Event event) throws NoTransitionException;
 }
diff --git a/api/src/main/java/com/cloud/vm/UserVmService.java b/api/src/main/java/com/cloud/vm/UserVmService.java
index b9fa2ee..d58b75b 100644
--- a/api/src/main/java/com/cloud/vm/UserVmService.java
+++ b/api/src/main/java/com/cloud/vm/UserVmService.java
@@ -404,10 +404,7 @@
     /**
      * Creates a vm group.
      *
-     * @param name
-     *            - name of the group
-     * @param accountId
-     *            - accountId
+     * @param cmd The command specifying domain ID, account name, group name, and project ID
      */
     InstanceGroup createVmGroup(CreateVMGroupCmd cmd);
 
@@ -446,16 +443,10 @@
 
     /**
      * Migrate the given VM to the destination host provided. The API returns the migrated VM if migration succeeds.
-     * Only Root
-     * Admin can migrate a VM.
+     * Only Root Admin can migrate a VM.
      *
-     * @param destinationStorage
-     *            TODO
-     * @param Long
-     *            vmId
-     *            vmId of The VM to migrate
-     * @param Host
-     *            destinationHost to migrate the VM
+     * @param vmId The ID of the VM to be migrated
+     * @param destinationHost The destination host to where the VM will be migrated
      *
      * @return VirtualMachine migrated VM
      * @throws ManagementServerException
@@ -474,14 +465,9 @@
      * Migrate the given VM with its volumes to the destination host. The API returns the migrated VM if it succeeds.
      * Only root admin can migrate a VM.
      *
-     * @param destinationStorage
-     *            TODO
-     * @param Long
-     *            vmId of The VM to migrate
-     * @param Host
-     *            destinationHost to migrate the VM
-     * @param Map
-     *            A map of volume to which pool it should be migrated
+     * @param vmId The ID of the VM to be migrated
+     * @param destinationHost The destination host to where the VM will be migrated
+     * @param volumeToPool A map of volume to which pool it should be migrated
      *
      * @return VirtualMachine migrated VM
      * @throws ManagementServerException
@@ -515,7 +501,7 @@
     /**
      * Finds and returns an encrypted password for a VM.
      *
-     * @param  userVmId
+     * @param  vmId
      * @return Base64 encoded userdata
      */
     String getVmUserData(long vmId);
diff --git a/api/src/main/java/com/cloud/vm/VirtualMachine.java b/api/src/main/java/com/cloud/vm/VirtualMachine.java
index 7a0715f..34c7a42 100644
--- a/api/src/main/java/com/cloud/vm/VirtualMachine.java
+++ b/api/src/main/java/com/cloud/vm/VirtualMachine.java
@@ -57,7 +57,8 @@
         Migrating(true, "VM is being migrated.  host id holds to from host"),
         Error(false, "VM is in error"),
         Unknown(false, "VM state is unknown."),
-        Shutdown(false, "VM state is shutdown from inside");
+        Shutdown(false, "VM state is shutdown from inside"),
+        Restoring(true, "VM is being restored from backup");
 
         private final boolean _transitional;
         String _description;
@@ -126,6 +127,11 @@
             s_fsm.addTransition(new Transition<State, Event>(State.Expunging, VirtualMachine.Event.ExpungeOperation, State.Expunging,null));
             s_fsm.addTransition(new Transition<State, Event>(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging, null));
             s_fsm.addTransition(new Transition<State, Event>(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging, null));
+            s_fsm.addTransition(new Transition<State, Event>(State.Stopped, Event.RestoringRequested, State.Restoring, null));
+            s_fsm.addTransition(new Transition<State, Event>(State.Expunging, Event.RestoringRequested, State.Restoring, null));
+            s_fsm.addTransition(new Transition<State, Event>(State.Destroyed, Event.RestoringRequested, State.Restoring, null));
+            s_fsm.addTransition(new Transition<State, Event>(State.Restoring, Event.RestoringSuccess, State.Stopped, null));
+            s_fsm.addTransition(new Transition<State, Event>(State.Restoring, Event.RestoringFailed, State.Stopped, null));
 
             s_fsm.addTransition(new Transition<State, Event>(State.Starting, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, Arrays.asList(new Impact[]{Impact.USAGE})));
             s_fsm.addTransition(new Transition<State, Event>(State.Stopping, VirtualMachine.Event.FollowAgentPowerOnReport, State.Running, null));
@@ -210,6 +216,9 @@
         AgentReportMigrated,
         RevertRequested,
         SnapshotRequested,
+        RestoringRequested,
+        RestoringFailed,
+        RestoringSuccess,
 
         // added for new VMSync logic
         FollowAgentPowerOnReport,
diff --git a/api/src/main/java/com/cloud/vm/VmDetailConstants.java b/api/src/main/java/com/cloud/vm/VmDetailConstants.java
index dd0a5d7..add2518 100644
--- a/api/src/main/java/com/cloud/vm/VmDetailConstants.java
+++ b/api/src/main/java/com/cloud/vm/VmDetailConstants.java
@@ -48,6 +48,10 @@
     String IOTHREADS = "iothreads";
     String IO_POLICY = "io.policy";
 
+    // KVM specific, the number of queues for multiqueue NICs
+    String NIC_MULTIQUEUE_NUMBER = "nic.multiqueue.number";
+    String NIC_PACKED_VIRTQUEUES_ENABLED = "nic.packed.virtqueues.enabled";
+
     // Mac OSX guest specific (internal)
     String SMC_PRESENT = "smc.present";
     String FIRMWARE = "firmware";
diff --git a/api/src/main/java/org/apache/cloudstack/acl/Role.java b/api/src/main/java/org/apache/cloudstack/acl/Role.java
index c25d7a9..5e5ffd5 100644
--- a/api/src/main/java/org/apache/cloudstack/acl/Role.java
+++ b/api/src/main/java/org/apache/cloudstack/acl/Role.java
@@ -23,4 +23,5 @@
 public interface Role extends RoleEntity, InternalIdentity, Identity {
     RoleType getRoleType();
     boolean isDefault();
+    boolean isPublicRole();
 }
diff --git a/api/src/main/java/org/apache/cloudstack/acl/RoleService.java b/api/src/main/java/org/apache/cloudstack/acl/RoleService.java
index 578c13e..9becce6 100644
--- a/api/src/main/java/org/apache/cloudstack/acl/RoleService.java
+++ b/api/src/main/java/org/apache/cloudstack/acl/RoleService.java
@@ -38,15 +38,17 @@
      *  Moreover, we will check if the requested role is of 'Admin' type; roles with 'Admin' type should only be visible to 'root admins'.
      *  Therefore, if a non-'root admin' user tries to search for an 'Admin' role, this method will return null.
      */
+    Role findRole(Long id, boolean removePrivateRoles);
+
     Role findRole(Long id);
 
-    Role createRole(String name, RoleType roleType, String description);
+    Role createRole(String name, RoleType roleType, String description, boolean publicRole);
 
-    Role createRole(String name, Role role, String description);
+    Role createRole(String name, Role role, String description, boolean publicRole);
 
-    Role importRole(String name, RoleType roleType, String description, List<Map<String, Object>> rules, boolean forced);
+    Role importRole(String name, RoleType roleType, String description, List<Map<String, Object>> rules, boolean forced, boolean isPublicRole);
 
-    Role updateRole(Role role, String name, RoleType roleType, String description);
+    Role updateRole(Role role, String name, RoleType roleType, String description, Boolean publicRole);
 
     boolean deleteRole(Role role);
 
diff --git a/api/src/main/java/org/apache/cloudstack/annotation/AnnotationService.java b/api/src/main/java/org/apache/cloudstack/annotation/AnnotationService.java
index c72fba2..51c6286 100644
--- a/api/src/main/java/org/apache/cloudstack/annotation/AnnotationService.java
+++ b/api/src/main/java/org/apache/cloudstack/annotation/AnnotationService.java
@@ -45,7 +45,7 @@
         SERVICE_OFFERING(false), DISK_OFFERING(false), NETWORK_OFFERING(false),
         ZONE(false), POD(false), CLUSTER(false), HOST(false), DOMAIN(false),
         PRIMARY_STORAGE(false), SECONDARY_STORAGE(false), VR(false), SYSTEM_VM(false),
-        AUTOSCALE_VM_GROUP(true);
+        AUTOSCALE_VM_GROUP(true), MANAGEMENT_SERVER(false),;
 
         private final boolean usersAllowed;
 
@@ -77,6 +77,7 @@
             list.add(EntityType.SECONDARY_STORAGE);
             list.add(EntityType.VR);
             list.add(EntityType.SYSTEM_VM);
+            list.add(EntityType.MANAGEMENT_SERVER);
             if (roleType != RoleType.DomainAdmin) {
                 list.add(EntityType.DOMAIN);
                 list.add(EntityType.SERVICE_OFFERING);
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiCommandResourceType.java b/api/src/main/java/org/apache/cloudstack/api/ApiCommandResourceType.java
index 0a7ece7..9267ca6 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiCommandResourceType.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiCommandResourceType.java
@@ -77,7 +77,8 @@
     Pod(com.cloud.dc.Pod.class),
     VmSnapshot(com.cloud.vm.snapshot.VMSnapshot.class),
     Role(org.apache.cloudstack.acl.Role.class),
-    VpnCustomerGateway(com.cloud.network.Site2SiteCustomerGateway.class);
+    VpnCustomerGateway(com.cloud.network.Site2SiteCustomerGateway.class),
+    ManagementServer(org.apache.cloudstack.management.ManagementServerHost.class);
 
     private final Class<?> clazz;
 
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 9f0418a..3e0e652 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -32,6 +32,7 @@
     public static final String ALLOCATED_ONLY = "allocatedonly";
     public static final String ANNOTATION = "annotation";
     public static final String API_KEY = "apikey";
+    public static final String ARCHIVED = "archived";
     public static final String ASYNC_BACKUP = "asyncbackup";
     public static final String AUTO_SELECT = "autoselect";
     public static final String USER_API_KEY = "userapikey";
@@ -247,6 +248,7 @@
     public static final String IP_AVAILABLE = "ipavailable";
     public static final String IP_LIMIT = "iplimit";
     public static final String IP_TOTAL = "iptotal";
+    public static final String IS_CONTROL_NODE = "iscontrolnode";
     public static final String IS_CLEANUP_REQUIRED = "iscleanuprequired";
     public static final String IS_DYNAMIC = "isdynamic";
     public static final String IS_EDGE = "isedge";
@@ -298,6 +300,8 @@
     public static final String NIC = "nic";
     public static final String NIC_NETWORK_LIST = "nicnetworklist";
     public static final String NIC_IP_ADDRESS_LIST = "nicipaddresslist";
+    public static final String NIC_MULTIQUEUE_NUMBER = "nicmultiqueuenumber";
+    public static final String NIC_PACKED_VIRTQUEUES_ENABLED = "nicpackedvirtqueuesenabled";
     public static final String NEW_START_IP = "newstartip";
     public static final String NEW_END_IP = "newendip";
     public static final String NUM_RETRIES = "numretries";
@@ -310,10 +314,14 @@
     public static final String OPTIONS = "options";
     public static final String OS_CATEGORY_ID = "oscategoryid";
     public static final String OS_CATEGORY_NAME = "oscategoryname";
+    public static final String OS_NAME = "osname";
     public static final String OS_ID = "osid";
     public static final String OS_TYPE_ID = "ostypeid";
     public static final String OS_DISPLAY_NAME = "osdisplayname";
     public static final String OS_NAME_FOR_HYPERVISOR = "osnameforhypervisor";
+    public static final String GUEST_OS_LIST = "guestoslist";
+    public static final String GUEST_OS_COUNT = "guestoscount";
+    public static final String OS_MAPPING_CHECK_ENABLED = "osmappingcheckenabled";
     public static final String OUTOFBANDMANAGEMENT_POWERSTATE = "outofbandmanagementpowerstate";
     public static final String OUTOFBANDMANAGEMENT_ENABLED = "outofbandmanagementenabled";
     public static final String OUTPUT = "output";
@@ -365,6 +373,7 @@
     public static final String RESOURCE_TYPE = "resourcetype";
     public static final String RESOURCE_TYPE_NAME = "resourcetypename";
     public static final String RESPONSE = "response";
+    public static final String RETRIEVE_ONLY_RESOURCE_COUNT = "retrieveonlyresourcecount";
     public static final String REVERTABLE = "revertable";
     public static final String REVOKED = "revoked";
     public static final String REGISTERED = "registered";
@@ -457,6 +466,7 @@
     public static final String VIRTUAL_MACHINE_NAME = "virtualmachinename";
     public static final String VIRTUAL_MACHINE_ID_IP = "vmidipmap";
     public static final String VIRTUAL_MACHINE_COUNT = "virtualmachinecount";
+    public static final String VIRTUAL_MACHINE_TYPE = "virtualmachinetype";
     public static final String VIRTUAL_MACHINES = "virtualmachines";
     public static final String USAGE_ID = "usageid";
     public static final String USAGE_TYPE = "usagetype";
@@ -522,6 +532,7 @@
     public static final String PRIVATE_NETWORK_ID = "privatenetworkid";
     public static final String ALLOCATION_STATE = "allocationstate";
     public static final String MANAGED_STATE = "managedstate";
+    public static final String MANAGEMENT_SERVER_ID = "managementserverid";
     public static final String STORAGE_ID = "storageid";
     public static final String PING_STORAGE_SERVER_IP = "pingstorageserverip";
     public static final String PING_DIR = "pingdir";
@@ -1017,11 +1028,20 @@
     public static final String LOGOUT = "logout";
     public static final String LIST_IDPS = "listIdps";
 
+    public static final String READY_FOR_SHUTDOWN = "readyforshutdown";
+    public static final String SHUTDOWN_TRIGGERED = "shutdowntriggered";
+    public static final String PENDING_JOBS_COUNT = "pendingjobscount";
+
     public static final String PUBLIC_MTU = "publicmtu";
     public static final String PRIVATE_MTU = "privatemtu";
     public static final String MTU = "mtu";
+    public static final String AUTO_ENABLE_KVM_HOST = "autoenablekvmhost";
     public static final String LIST_APIS = "listApis";
 
+    public static final String SOURCE_NAT_IP = "sourcenatipaddress";
+    public static final String SOURCE_NAT_IP_ID = "sourcenatipaddressid";
+    public static final String HAS_RULES = "hasrules";
+
     /**
      * This enum specifies IO Drivers, each option controls specific policies on I/O.
      * Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).
diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseListRetrieveOnlyResourceCountCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseListRetrieveOnlyResourceCountCmd.java
new file mode 100644
index 0000000..0e8e136
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/BaseListRetrieveOnlyResourceCountCmd.java
@@ -0,0 +1,28 @@
+// 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.commons.lang3.BooleanUtils;
+
+public abstract class BaseListRetrieveOnlyResourceCountCmd extends BaseListTaggedResourcesCmd {
+    @Parameter(name = ApiConstants.RETRIEVE_ONLY_RESOURCE_COUNT, type = CommandType.BOOLEAN, description = "makes the API's response contains only the resource count")
+    private Boolean retrieveOnlyResourceCount;
+
+    public Boolean getRetrieveOnlyResourceCount() {
+        return BooleanUtils.toBooleanDefaultIfNull(retrieveOnlyResourceCount, false);
+    }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java
index 31f06df..88b3571 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java
@@ -62,6 +62,7 @@
 import org.apache.cloudstack.api.response.HostForMigrationResponse;
 import org.apache.cloudstack.api.response.HostResponse;
 import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse;
+import org.apache.cloudstack.api.response.HypervisorGuestOsNamesResponse;
 import org.apache.cloudstack.api.response.IPAddressResponse;
 import org.apache.cloudstack.api.response.ImageStoreResponse;
 import org.apache.cloudstack.api.response.InstanceGroupResponse;
@@ -463,6 +464,8 @@
 
     GuestOsMappingResponse createGuestOSMappingResponse(GuestOSHypervisor osHypervisor);
 
+    HypervisorGuestOsNamesResponse createHypervisorGuestOSNamesResponse(List<Pair<String, String>> hypervisorGuestOsNames);
+
     SnapshotScheduleResponse createSnapshotScheduleResponse(SnapshotSchedule sched);
 
     UsageRecordResponse createUsageResponse(Usage usageRecord);
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java
index 2b88003..8a469df 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/CreateRoleCmd.java
@@ -48,6 +48,10 @@
             description = "ID of the role to be cloned from. Either roleid or type must be passed in")
     private Long roleId;
 
+    @Parameter(name = ApiConstants.IS_PUBLIC, type = CommandType.BOOLEAN, description = "Indicates whether the role will be visible to all users (public) or only to root admins (private)." +
+            " If this parameter is not specified during the creation of the role its value will be defaulted to true (public).")
+    private boolean publicRole = true;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -60,6 +64,9 @@
         return roleId;
     }
 
+    public boolean isPublicRole() {
+        return publicRole;
+    }
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
@@ -81,10 +88,10 @@
             }
 
             CallContext.current().setEventDetails("Role: " + getRoleName() + ", from role: " + getRoleId() + ", description: " + getRoleDescription());
-            role = roleService.createRole(getRoleName(), existingRole, getRoleDescription());
+            role = roleService.createRole(getRoleName(), existingRole, getRoleDescription(), isPublicRole());
         } else {
             CallContext.current().setEventDetails("Role: " + getRoleName() + ", type: " + getRoleType() + ", description: " + getRoleDescription());
-            role = roleService.createRole(getRoleName(), getRoleType(), getRoleDescription());
+            role = roleService.createRole(getRoleName(), getRoleType(), getRoleDescription(), isPublicRole());
         }
 
         if (role == null) {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ImportRoleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ImportRoleCmd.java
index 4f3e9d1..058650c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ImportRoleCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ImportRoleCmd.java
@@ -64,6 +64,10 @@
             description = "Force create a role with the same name. This overrides the role type, description and rule permissions for the existing role. Default is false.")
     private Boolean forced;
 
+    @Parameter(name = ApiConstants.IS_PUBLIC, type = CommandType.BOOLEAN, description = "Indicates whether the role will be visible to all users (public) or only to root admins (private)." +
+            " If this parameter is not specified during the creation of the role its value will be defaulted to true (public).")
+    private boolean publicRole = true;
+
     @Inject
     ApiServerService _apiServer;
 
@@ -114,6 +118,10 @@
         return (forced != null) ? forced : false;
     }
 
+    public boolean isPublicRole() {
+        return publicRole;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
@@ -130,7 +138,7 @@
         }
 
         CallContext.current().setEventDetails("Role: " + getRoleName() + ", type: " + getRoleType() + ", description: " + getRoleDescription());
-        Role role = roleService.importRole(getRoleName(), getRoleType(), getRoleDescription(), getRules(), isForced());
+        Role role = roleService.importRole(getRoleName(), getRoleType(), getRoleDescription(), getRules(), isForced(), isPublicRole());
         if (role == null) {
             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to import role");
         }
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java
index b55dc80..fef2b27 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ListRolesCmd.java
@@ -92,6 +92,7 @@
             roleResponse.setRoleType(role.getRoleType());
             roleResponse.setDescription(role.getDescription());
             roleResponse.setIsDefault(role.isDefault());
+            roleResponse.setPublicRole(role.isPublicRole());
             roleResponse.setObjectName("role");
             roleResponses.add(roleResponse);
         }
@@ -104,7 +105,7 @@
     public void execute() {
         Pair<List<Role>, Integer> roles;
         if (getId() != null && getId() > 0L) {
-            roles = new Pair<List<Role>, Integer>(Collections.singletonList(roleService.findRole(getId())), 1);
+            roles = new Pair<>(Collections.singletonList(roleService.findRole(getId(), true)), 1);
         } else if (StringUtils.isNotBlank(getName()) || StringUtils.isNotBlank(getKeyword())) {
             roles = roleService.findRolesByName(getName(), getKeyword(), getStartIndex(), getPageSizeVal());
         } else if (getRoleType() != null) {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/RoleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/RoleCmd.java
index e652918..4c317d0 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/RoleCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/RoleCmd.java
@@ -58,6 +58,7 @@
         response.setRoleName(role.getName());
         response.setRoleType(role.getRoleType());
         response.setDescription(role.getDescription());
+        response.setPublicRole(role.isPublicRole());
         response.setResponseName(getCommandName());
         response.setObjectName("role");
         setResponseObject(response);
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java
index 227aaf5..7d002cd 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/UpdateRoleCmd.java
@@ -52,6 +52,9 @@
     @Parameter(name = ApiConstants.DESCRIPTION, type = BaseCmd.CommandType.STRING, description = "The description of the role")
     private String roleDescription;
 
+    @Parameter(name = ApiConstants.IS_PUBLIC, type = CommandType.BOOLEAN, description = "Indicates whether the role will be visible to all users (public) or only to root admins (private).")
+    private Boolean publicRole;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -64,6 +67,10 @@
         return roleName;
     }
 
+    public Boolean isPublicRole() {
+        return publicRole;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
@@ -80,7 +87,7 @@
             throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role id provided");
         }
         CallContext.current().setEventDetails("Role: " + getRoleName() + ", type:" + getRoleType() + ", description: " + getRoleDescription());
-        role = roleService.updateRole(role, getRoleName(), getRoleType(), getRoleDescription());
+        role = roleService.updateRole(role, getRoleName(), getRoleType(), getRoleDescription(), isPublicRole());
         setupResponse(role);
     }
 
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/AddGuestOsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/AddGuestOsCmd.java
index 2b95c20..af74874 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/AddGuestOsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/AddGuestOsCmd.java
@@ -16,6 +16,7 @@
 // under the License.
 package org.apache.cloudstack.api.command.admin.guest;
 
+import org.apache.commons.collections.MapUtils;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.api.APICommand;
@@ -79,7 +80,7 @@
 
     public Map getDetails() {
         Map<String, String> detailsMap = new HashMap<String, String>();
-        if (!details.isEmpty()) {
+        if (!MapUtils.isEmpty(details)) {
             Collection<?> servicesCollection = details.values();
             Iterator<?> iter = servicesCollection.iterator();
             while (iter.hasNext()) {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/AddGuestOsMappingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/AddGuestOsMappingCmd.java
index 6d9ac52..0ddd219 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/AddGuestOsMappingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/AddGuestOsMappingCmd.java
@@ -16,6 +16,7 @@
 // under the License.
 package org.apache.cloudstack.api.command.admin.guest;
 
+import org.apache.commons.lang3.BooleanUtils;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.api.APICommand;
@@ -51,12 +52,18 @@
     @Parameter(name = ApiConstants.HYPERVISOR, type = CommandType.STRING, required = true, description = "Hypervisor type. One of : XenServer, KVM, VMWare")
     private String hypervisor;
 
-    @Parameter(name = ApiConstants.HYPERVISOR_VERSION, type = CommandType.STRING, required = true, description = "Hypervisor version to create the mapping for. Use 'default' for default versions")
+    @Parameter(name = ApiConstants.HYPERVISOR_VERSION, type = CommandType.STRING, required = true, description = "Hypervisor version to create the mapping. Use 'default' for default versions. Please check hypervisor capabilities for correct version")
     private String hypervisorVersion;
 
     @Parameter(name = ApiConstants.OS_NAME_FOR_HYPERVISOR, type = CommandType.STRING, required = true, description = "OS name specific to the hypervisor")
     private String osNameForHypervisor;
 
+    @Parameter(name = ApiConstants.OS_MAPPING_CHECK_ENABLED, type = CommandType.BOOLEAN, required = false, description = "When set to true, checks for the correct guest os mapping name in the provided hypervisor (supports VMware and XenServer only. At least one hypervisor host with the version specified must be available. Default version will not work.)", since = "4.19.0")
+    private Boolean osMappingCheckEnabled;
+
+    @Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, required = false, description = "Forces add user defined guest os mapping, overrides any existing user defined mapping", since = "4.19.0")
+    private Boolean forced;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -81,6 +88,14 @@
         return osNameForHypervisor;
     }
 
+    public Boolean getOsMappingCheckEnabled() {
+        return BooleanUtils.toBooleanDefaultIfNull(osMappingCheckEnabled, false);
+    }
+
+    public boolean isForced() {
+        return BooleanUtils.toBooleanDefaultIfNull(forced, false);
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/GetHypervisorGuestOsNamesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/GetHypervisorGuestOsNamesCmd.java
new file mode 100644
index 0000000..7951770
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/GetHypervisorGuestOsNamesCmd.java
@@ -0,0 +1,106 @@
+// 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.command.admin.guest;
+
+import java.util.List;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiArgValidator;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.HypervisorGuestOsNamesResponse;
+import org.apache.log4j.Logger;
+
+import com.cloud.event.EventTypes;
+import com.cloud.user.Account;
+import com.cloud.utils.Pair;
+
+@APICommand(name = GetHypervisorGuestOsNamesCmd.APINAME, description = "Gets the guest OS names in the hypervisor", responseObject = HypervisorGuestOsNamesResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0", authorized = {RoleType.Admin})
+public class GetHypervisorGuestOsNamesCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = Logger.getLogger(GetHypervisorGuestOsNamesCmd.class.getName());
+
+    public static final String APINAME = "getHypervisorGuestOsNames";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name = ApiConstants.HYPERVISOR, type = CommandType.STRING, required = true, description = "Hypervisor type. One of : VMware, XenServer",
+            validations = {ApiArgValidator.NotNullOrEmpty})
+    private String hypervisor;
+
+    @Parameter(name = ApiConstants.HYPERVISOR_VERSION, type = CommandType.STRING, required = true, description = "Hypervisor version to get the guest os names (atleast one hypervisor host with the version specified must be available)",
+            validations = {ApiArgValidator.NotNullOrEmpty})
+    private String hypervisorVersion;
+
+    @Parameter(name = ApiConstants.KEYWORD, type = CommandType.STRING, required = false, description = "Keyword for guest os name")
+    private String keyword;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public String getHypervisor() {
+        return hypervisor;
+    }
+
+    public String getHypervisorVersion() {
+        return hypervisorVersion;
+    }
+
+    public String getKeyword() {
+        return keyword;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+
+    @Override
+    public void execute() {
+        List<Pair<String, String>> hypervisorGuestOsNames = _mgr.getHypervisorGuestOsNames(this);
+        HypervisorGuestOsNamesResponse response = _responseGenerator.createHypervisorGuestOSNamesResponse(hypervisorGuestOsNames);
+        response.setHypervisor(getHypervisor());
+        response.setHypervisorVersion(getHypervisorVersion());
+        response.setResponseName(getCommandName());
+        setResponseObject(response);
+    }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_GUEST_OS_HYPERVISOR_NAME_FETCH;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Getting guest OS names from hypervisor: " + getHypervisor() + ", version: " + getHypervisorVersion();
+    }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/ListGuestOsMappingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/ListGuestOsMappingCmd.java
index 70c039f..29ae0b4 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/ListGuestOsMappingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/ListGuestOsMappingCmd.java
@@ -48,6 +48,12 @@
     @Parameter(name = ApiConstants.OS_TYPE_ID, type = CommandType.UUID, entityType = GuestOSResponse.class, required = false, description = "list mapping by Guest OS Type UUID")
     private Long osTypeId;
 
+    @Parameter(name = ApiConstants.OS_DISPLAY_NAME, type = CommandType.STRING, required = false, description = "list Guest OS mapping by OS display name")
+    private String osDisplayName;
+
+    @Parameter(name = ApiConstants.OS_NAME_FOR_HYPERVISOR, type = CommandType.STRING, required = false, description = "list Guest OS mapping by OS mapping name with hypervisor")
+    private String osNameForHypervisor;
+
     @Parameter(name = ApiConstants.HYPERVISOR, type = CommandType.STRING, required = false, description = "list Guest OS mapping by hypervisor")
     private String hypervisor;
 
@@ -66,6 +72,14 @@
         return osTypeId;
     }
 
+    public String getOsDisplayName() {
+        return osDisplayName;
+    }
+
+    public String getOsNameForHypervisor() {
+        return osNameForHypervisor;
+    }
+
     public String getHypervisor() {
         return hypervisor;
     }
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsCmd.java
index 1168bf0..f9639f7 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsCmd.java
@@ -16,6 +16,7 @@
 // under the License.
 package org.apache.cloudstack.api.command.admin.guest;
 
+import org.apache.commons.collections.MapUtils;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.api.APICommand;
@@ -53,7 +54,7 @@
     @Parameter(name = ApiConstants.OS_DISPLAY_NAME, type = CommandType.STRING, required = true, description = "Unique display name for Guest OS")
     private String osDisplayName;
 
-    @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, required = true, description = "Map of (key/value pairs)")
+    @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, required = false, description = "Map of (key/value pairs)")
     private Map details;
 
 
@@ -71,7 +72,7 @@
 
     public Map getDetails() {
         Map<String, String> detailsMap = new HashMap<String, String>();;
-        if (!details.isEmpty()) {
+        if (MapUtils.isNotEmpty(detailsMap)) {
             Collection<?> servicesCollection = details.values();
             Iterator<?> iter = servicesCollection.iterator();
             while (iter.hasNext()) {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsMappingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsMappingCmd.java
index 679ec35..c83be13 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsMappingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/guest/UpdateGuestOsMappingCmd.java
@@ -16,6 +16,7 @@
 // under the License.
 package org.apache.cloudstack.api.command.admin.guest;
 
+import org.apache.commons.lang3.BooleanUtils;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.api.APICommand;
@@ -47,6 +48,9 @@
     @Parameter(name = ApiConstants.OS_NAME_FOR_HYPERVISOR, type = CommandType.STRING, required = true, description = "Hypervisor specific name for this Guest OS")
     private String osNameForHypervisor;
 
+    @Parameter(name = ApiConstants.OS_MAPPING_CHECK_ENABLED, type = CommandType.BOOLEAN, required = false, description = "When set to true, checks for the correct guest os mapping name in the provided hypervisor (supports VMware and XenServer only. At least one hypervisor host with the version specified must be available. Default version will not work.)", since = "4.19.0")
+    private Boolean osMappingCheckEnabled;
+
 /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -59,6 +63,10 @@
         return osNameForHypervisor;
     }
 
+    public Boolean getOsMappingCheckEnabled() {
+        return BooleanUtils.toBooleanDefaultIfNull(osMappingCheckEnabled, false);
+    }
+
     @Override
     public void execute() {
         GuestOSHypervisor guestOsMapping = _mgr.updateGuestOsMapping(this);
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java
index 5ca53c0..e3ff130 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java
@@ -19,7 +19,6 @@
 import com.cloud.host.Host;
 import com.cloud.user.Account;
 import org.apache.cloudstack.acl.RoleType;
-import org.apache.cloudstack.annotation.AnnotationService;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
@@ -117,9 +116,6 @@
         Host result;
         try {
             result = _resourceService.updateHost(this);
-            if(getAnnotation() != null) {
-                annotationService.addAnnotation(getAnnotation(), AnnotationService.EntityType.HOST, result.getUuid(), true);
-            }
             HostResponse hostResponse = _responseGenerator.createHostResponse(result);
             hostResponse.setResponseName(getCommandName());
             this.setResponseObject(hostResponse);
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java
index ac6dee1..8bf6fce 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java
@@ -28,6 +28,7 @@
 import org.apache.cloudstack.api.response.DomainResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.api.APICommand;
@@ -58,7 +59,7 @@
     @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "the name of the network offering")
     private String networkOfferingName;
 
-    @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, required = true, description = "the display text of the network offering")
+    @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, description = "the display text of the network offering, defaults to the value of 'name'.")
     private String displayText;
 
     @Parameter(name = ApiConstants.TRAFFIC_TYPE,
@@ -182,7 +183,7 @@
     }
 
     public String getDisplayText() {
-        return displayText;
+        return StringUtils.isEmpty(displayText) ? networkOfferingName : displayText;
     }
 
     public String getTags() {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java
index 304b290..c2d8b3b 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java
@@ -36,6 +36,7 @@
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.offering.DiskOffering;
@@ -56,7 +57,7 @@
     @Parameter(name = ApiConstants.DISK_SIZE, type = CommandType.LONG, required = false, description = "size of the disk offering in GB (1GB = 1,073,741,824 bytes)")
     private Long diskSize;
 
-    @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, required = true, description = "alternate display text of the disk offering", length = 4096)
+    @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, description = "An alternate display text of the disk offering, defaults to 'name'.", length = 4096)
     private String displayText;
 
     @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "name of the disk offering")
@@ -179,7 +180,7 @@
     }
 
     public String getDisplayText() {
-        return displayText;
+        return StringUtils.isEmpty(displayText) ? offeringName : displayText;
     }
 
     public String getOfferingName() {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java
index 24f5682..d947f6f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java
@@ -59,7 +59,7 @@
     @Parameter(name = ApiConstants.CPU_SPEED, type = CommandType.INTEGER, required = false, description = "the CPU speed of the service offering in MHz.")
     private Integer cpuSpeed;
 
-    @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, required = true, description = "the display text of the service offering")
+    @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, description = "The display text of the service offering, defaults to 'name'.")
     private String displayText;
 
     @Parameter(name = ApiConstants.PROVISIONINGTYPE, type = CommandType.STRING, description = "provisioning type used to create volumes. Valid values are thin, sparse, fat.")
@@ -258,10 +258,7 @@
     }
 
     public String getDisplayText() {
-        if (StringUtils.isEmpty(displayText)) {
-            throw new InvalidParameterValueException("Failed to create service offering because the offering display text has not been spified.");
-        }
-        return displayText;
+        return StringUtils.isEmpty(displayText) ? serviceOfferingName : displayText;
     }
 
     public String getProvisioningType() {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java
index 731cb67..549d02b 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java
@@ -83,6 +83,12 @@
                "<1b331390-59f2-4796-9993-bf11c6e76225>&migrateto[2].pool=<41fdb564-9d3b-447d-88ed-7628f7640cbc>")
     private Map migrateVolumeTo;
 
+    @Parameter(name = ApiConstants.AUTO_SELECT,
+            since = "4.19.0",
+            type = CommandType.BOOLEAN,
+            description = "Automatically select a destination host for a running instance, if hostId is not specified. false by default")
+    private Boolean autoSelect;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -144,31 +150,39 @@
         return ApiCommandResourceType.VirtualMachine;
     }
 
+    private Host getDestinationHost() {
+        if (getHostId() == null) {
+            return null;
+        }
+        Host destinationHost = _resourceService.getHost(getHostId());
+        // OfflineVmwareMigration: destination host would have to not be a required parameter for stopped VMs
+        if (destinationHost == null) {
+            s_logger.error(String.format("Unable to find the host with ID [%s].", getHostId()));
+            throw new InvalidParameterValueException("Unable to find the specified host to migrate the VM.");
+        }
+        return destinationHost;
+    }
+
     @Override
     public void execute() {
-        if (hostId == null && MapUtils.isEmpty(migrateVolumeTo)) {
-            throw new InvalidParameterValueException(String.format("Either %s or %s must be passed for migrating the VM.", ApiConstants.HOST_ID, ApiConstants.MIGRATE_TO));
+        if (hostId == null && MapUtils.isEmpty(migrateVolumeTo) && !Boolean.TRUE.equals(autoSelect)) {
+            throw new InvalidParameterValueException(String.format("Either %s or %s must be passed or %s must be true for migrating the VM.", ApiConstants.HOST_ID, ApiConstants.MIGRATE_TO, ApiConstants.AUTO_SELECT));
         }
 
         VirtualMachine virtualMachine = _userVmService.getVm(getVirtualMachineId());
-        if (!VirtualMachine.State.Running.equals(virtualMachine.getState()) && hostId != null) {
+        if (!VirtualMachine.State.Running.equals(virtualMachine.getState()) && (hostId != null || Boolean.TRUE.equals(autoSelect))) {
             throw new InvalidParameterValueException(String.format("%s is not in the Running state to migrate it to the new host.", virtualMachine));
         }
 
-        if (!VirtualMachine.State.Stopped.equals(virtualMachine.getState()) && hostId == null) {
-            throw new InvalidParameterValueException(String.format("%s is not in the Stopped state to migrate, use the %s parameter to migrate it to a new host.",
-                    virtualMachine, ApiConstants.HOST_ID));
+        if (!VirtualMachine.State.Stopped.equals(virtualMachine.getState()) && hostId == null && Boolean.FALSE.equals(autoSelect)) {
+            throw new InvalidParameterValueException(String.format("%s is not in the Stopped state to migrate, use the %s or %s parameter to migrate it to a new host.",
+                    virtualMachine, ApiConstants.HOST_ID,ApiConstants.AUTO_SELECT));
         }
 
         try {
             VirtualMachine migratedVm = null;
-            if (hostId != null) {
-                Host destinationHost = _resourceService.getHost(getHostId());
-                // OfflineVmwareMigration: destination host would have to not be a required parameter for stopped VMs
-                if (destinationHost == null) {
-                    s_logger.error(String.format("Unable to find the host with ID [%s].", getHostId()));
-                    throw new InvalidParameterValueException("Unable to find the specified host to migrate the VM.");
-                }
+            if (getHostId() != null || Boolean.TRUE.equals(autoSelect)) {
+                Host destinationHost = getDestinationHost();
                 migratedVm = _userVmService.migrateVirtualMachineWithVolume(getVirtualMachineId(), destinationHost, getVolumeToPool());
             } else if (MapUtils.isNotEmpty(migrateVolumeTo)) {
                 migratedVm = _userVmService.vmStorageMigration(getVirtualMachineId(), getVolumeToPool());
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java
index f1c2a5b..b69e7f4 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java
@@ -28,6 +28,7 @@
 import org.apache.cloudstack.api.response.DomainResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.api.APICommand;
@@ -56,7 +57,7 @@
     @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "the name of the vpc offering")
     private String vpcOfferingName;
 
-    @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, required = true, description = "the display text of " + "the vpc offering")
+    @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, description = "the display text of the vpc offering, defaults to the 'name'")
     private String displayText;
 
     @Parameter(name = ApiConstants.SUPPORTED_SERVICES,
@@ -115,7 +116,7 @@
     }
 
     public String getDisplayText() {
-        return displayText;
+        return StringUtils.isEmpty(displayText) ? vpcOfferingName : displayText;
     }
 
     public List<String> getSupportedServices() {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java
index e456074..22eb70c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java
@@ -25,7 +25,7 @@
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiCommandResourceType;
 import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.BaseListTaggedResourcesCmd;
+import org.apache.cloudstack.api.BaseListRetrieveOnlyResourceCountCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ResponseObject.ResponseView;
 import org.apache.cloudstack.api.command.user.UserCmd;
@@ -42,7 +42,7 @@
 
 @APICommand(name = "listPublicIpAddresses", description = "Lists all public IP addresses", responseObject = IPAddressResponse.class, responseView = ResponseView.Restricted,
  requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, entityType = { IpAddress.class })
-public class ListPublicIpAddressesCmd extends BaseListTaggedResourcesCmd implements UserCmd {
+public class ListPublicIpAddressesCmd extends BaseListRetrieveOnlyResourceCountCmd implements UserCmd {
     public static final Logger s_logger = Logger.getLogger(ListPublicIpAddressesCmd.class.getName());
 
     private static final String s_name = "listpublicipaddressesresponse";
@@ -173,10 +173,6 @@
         return forVirtualNetwork;
     }
 
-    public Boolean getForLoadBalancing() {
-        return forLoadBalancing;
-    }
-
     public String getState() {
         return state;
     }
@@ -192,12 +188,15 @@
     @Override
     public void execute() {
         Pair<List<? extends IpAddress>, Integer> result = _mgr.searchForIPAddresses(this);
-        ListResponse<IPAddressResponse> response = new ListResponse<IPAddressResponse>();
-        List<IPAddressResponse> ipAddrResponses = new ArrayList<IPAddressResponse>();
-        for (IpAddress ipAddress : result.first()) {
-            IPAddressResponse ipResponse = _responseGenerator.createIPAddressResponse(getResponseView(), ipAddress);
-            ipResponse.setObjectName("publicipaddress");
-            ipAddrResponses.add(ipResponse);
+        ListResponse<IPAddressResponse> response = new ListResponse<>();
+        List<IPAddressResponse> ipAddrResponses = new ArrayList<>();
+
+        if (!getRetrieveOnlyResourceCount()) {
+            for (IpAddress ipAddress : result.first()) {
+                IPAddressResponse ipResponse = _responseGenerator.createIPAddressResponse(getResponseView(), ipAddress);
+                ipResponse.setObjectName("publicipaddress");
+                ipAddrResponses.add(ipResponse);
+            }
         }
 
         response.setResponses(ipAddrResponses, result.second());
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmGroupCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmGroupCmd.java
index b4f152e..cdbe153 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmGroupCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/autoscale/CreateAutoScaleVmGroupCmd.java
@@ -232,7 +232,7 @@
                 responseObject.setResponseName(getCommandName());
             }
         } catch (Exception ex) {
-            // TODO what will happen if Resource Layer fails in a step inbetween
+            // TODO what will happen if Resource Layer fails in a step in between
             s_logger.warn("Failed to create autoscale vm group", ex);
         } finally {
             if (!success || vmGroup == null) {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/event/ListEventsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/event/ListEventsCmd.java
index 202bd36..89f1c70 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/event/ListEventsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/event/ListEventsCmd.java
@@ -72,6 +72,9 @@
     @Parameter(name = ApiConstants.RESOURCE_TYPE, type = CommandType.STRING, description = "the type of the resource associated with the event", since="4.17.0")
     private String resourceType;
 
+    @Parameter(name = ApiConstants.ARCHIVED, type = CommandType.BOOLEAN, description = "true to list archived events otherwise false", since="4.19.0")
+    private Boolean archived;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -116,6 +119,10 @@
         return resourceType;
     }
 
+    public boolean getArchived() {
+        return archived != null && archived;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
index 47018b3..ecab393 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
@@ -34,6 +34,7 @@
 import org.apache.cloudstack.api.response.TemplateResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.context.CallContext;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.exception.ResourceAllocationException;
@@ -55,8 +56,7 @@
 
     @Parameter(name = ApiConstants.DISPLAY_TEXT,
                type = CommandType.STRING,
-               required = true,
-               description = "the display text of the ISO. This is usually used for display purposes.",
+               description = "the display text of the ISO, defaults to the 'name'",
                length = 4096)
     private String displayText;
 
@@ -133,7 +133,7 @@
     }
 
     public String getDisplayText() {
-        return displayText;
+        return StringUtils.isEmpty(displayText) ? isoName : displayText;
     }
 
     public void setDisplayText(String displayText) {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/job/ListAsyncJobsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/job/ListAsyncJobsCmd.java
index d2574ff..783d78f 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/job/ListAsyncJobsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/job/ListAsyncJobsCmd.java
@@ -24,6 +24,7 @@
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.response.AsyncJobResponse;
 import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.ManagementServerResponse;
 
 @APICommand(name = "listAsyncJobs", description = "Lists all pending asynchronous jobs for the account.", responseObject = AsyncJobResponse.class,
         requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@@ -36,6 +37,9 @@
     @Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, description = "The start date of the async job (use format \"yyyy-MM-dd'T'HH:mm:ss'+'SSSS\")")
     private Date startDate;
 
+    @Parameter(name = ApiConstants.MANAGEMENT_SERVER_ID, type = CommandType.UUID, entityType = ManagementServerResponse.class, description = "The id of the management server", since="4.19")
+    private Long managementServerId;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -44,6 +48,10 @@
         return startDate;
     }
 
+    public Long getManagementServerId() {
+        return managementServerId;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLBStickinessPolicyCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLBStickinessPolicyCmd.java
index 45e6f81..66a1598 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLBStickinessPolicyCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLBStickinessPolicyCmd.java
@@ -68,7 +68,7 @@
     @Parameter(name = ApiConstants.METHOD_NAME,
                type = CommandType.STRING,
                required = true,
-               description = "name of the load balancer stickiness policy method, possible values can be obtained from listNetworks API")
+               description = "name of the load balancer stickiness policy method, possible values are LbCookie, AppCookie, SourceBased")
     private String stickinessMethodName;
 
     @Parameter(name = ApiConstants.PARAM_LIST, type = CommandType.MAP, description = "param list. Example: param[0].name=cookiename&param[0].value=LBCookie ")
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
index 5b814e7..2315999 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java
@@ -16,7 +16,7 @@
 // under the License.
 package org.apache.cloudstack.api.command.user.network;
 
-import com.cloud.network.NetworkService;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.acl.RoleType;
@@ -43,10 +43,10 @@
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.network.Network;
+import com.cloud.network.NetworkService;
 import com.cloud.network.Network.GuestType;
 import com.cloud.offering.NetworkOffering;
 import com.cloud.utils.net.NetUtils;
-import org.apache.commons.lang3.StringUtils;
 
 @APICommand(name = "createNetwork", description = "Creates a network", responseObject = NetworkResponse.class, responseView = ResponseView.Restricted, entityType = {Network.class},
         requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@@ -183,6 +183,14 @@
     @Parameter(name = ApiConstants.IP6_DNS2, type = CommandType.STRING, description = "the second IPv6 DNS for the network", since = "4.18.0")
     private String ip6Dns2;
 
+    @Parameter(name = ApiConstants.SOURCE_NAT_IP,
+            type = CommandType.STRING,
+            description = "IPV4 address to be assigned to the public interface of the network router. " +
+                    "This address will be used as source NAT address for the network. " +
+                    "\nIf an address is given and it cannot be acquired, an error will be returned and the network won´t be implemented,",
+            since = "4.19")
+    private String sourceNatIP;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -266,6 +274,10 @@
         return tungstenVirtualRouterUuid;
     }
 
+    public String getSourceNatIP() {
+        return sourceNatIP;
+    }
+
     @Override
     public boolean isDisplay() {
         if(displayNetwork == null)
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java
index df82d9f..c1e85a9 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworksCmd.java
@@ -23,12 +23,13 @@
 import com.cloud.server.ResourceTag;
 import org.apache.cloudstack.api.response.NetworkOfferingResponse;
 import org.apache.cloudstack.api.response.ResourceIconResponse;
+import org.apache.commons.lang3.BooleanUtils;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.BaseListTaggedResourcesCmd;
+import org.apache.cloudstack.api.BaseListRetrieveOnlyResourceCountCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ResponseObject.ResponseView;
 import org.apache.cloudstack.api.command.user.UserCmd;
@@ -44,7 +45,7 @@
 
 @APICommand(name = "listNetworks", description = "Lists all available networks.", responseObject = NetworkResponse.class, responseView = ResponseView.Restricted, entityType = {Network.class},
         requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
-public class ListNetworksCmd extends BaseListTaggedResourcesCmd implements UserCmd {
+public class ListNetworksCmd extends BaseListRetrieveOnlyResourceCountCmd implements UserCmd {
     public static final Logger s_logger = Logger.getLogger(ListNetworksCmd.class.getName());
     private static final String s_name = "listnetworksresponse";
 
@@ -190,14 +191,11 @@
 
     @Override
     public Boolean getDisplay() {
-        if (display != null) {
-            return display;
-        }
-        return super.getDisplay();
+        return BooleanUtils.toBooleanDefaultIfNull(display, super.getDisplay());
     }
 
     public Boolean getShowIcon() {
-        return showIcon != null ? showIcon : false;
+        return BooleanUtils.toBooleanDefaultIfNull(showIcon, false);
     }
 
     public String getNetworkFilter() {
@@ -215,16 +213,21 @@
     @Override
     public void execute() {
         Pair<List<? extends Network>, Integer> networks = _networkService.searchForNetworks(this);
-        ListResponse<NetworkResponse> response = new ListResponse<NetworkResponse>();
-        List<NetworkResponse> networkResponses = new ArrayList<NetworkResponse>();
-        for (Network network : networks.first()) {
-            NetworkResponse networkResponse = _responseGenerator.createNetworkResponse(getResponseView(), network);
-            networkResponses.add(networkResponse);
+        ListResponse<NetworkResponse> response = new ListResponse<>();
+        List<NetworkResponse> networkResponses = new ArrayList<>();
+
+        if (!getRetrieveOnlyResourceCount()) {
+            for (Network network : networks.first()) {
+                NetworkResponse networkResponse = _responseGenerator.createNetworkResponse(getResponseView(), network);
+                networkResponses.add(networkResponse);
+            }
         }
+
         response.setResponses(networkResponses, networks.second());
         response.setResponseName(getCommandName());
         setResponseObject(response);
-        if (response != null && response.getCount() > 0 && getShowIcon()) {
+
+        if (!getRetrieveOnlyResourceCount() && response.getCount() > 0 && getShowIcon()) {
             updateNetworkResponse(response.getResponses());
         }
     }
@@ -232,11 +235,11 @@
     private void updateNetworkResponse(List<NetworkResponse> response) {
         for (NetworkResponse networkResponse : response) {
             ResourceIcon resourceIcon = resourceIconManager.getByResourceTypeAndUuid(ResourceTag.ResourceObjectType.Network, networkResponse.getId());
-            if (resourceIcon == null) {
+            if (resourceIcon == null && networkResponse.getVpcId() != null) {
                 resourceIcon = resourceIconManager.getByResourceTypeAndUuid(ResourceTag.ResourceObjectType.Vpc, networkResponse.getVpcId());
-                if (resourceIcon == null) {
-                    continue;
-                }
+            }
+            if (resourceIcon == null) {
+                continue;
             }
             ResourceIconResponse iconResponse = _responseGenerator.createResourceIconResponse(resourceIcon);
             networkResponse.setResourceIconResponse(iconResponse);
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java
index 3aef973..d3cc169 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java
@@ -104,6 +104,9 @@
     @Parameter(name = ApiConstants.IP6_DNS2, type = CommandType.STRING, description = "the second IPv6 DNS for the network. Empty string will update the second IPv6 DNS with the value from the zone", since = "4.18.0")
     private String ip6Dns2;
 
+    @Parameter(name = ApiConstants.SOURCE_NAT_IP, type = CommandType.STRING, description = "IPV4 address to be assigned to the public interface of the network router. This address must already be acquired for this network", since = "4.19")
+    private String sourceNatIP;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -181,6 +184,10 @@
         return ip6Dns2;
     }
 
+    public String getSourceNatIP() {
+        return sourceNatIP;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/project/CreateProjectCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/project/CreateProjectCmd.java
index a0902d6..a5742e8 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/project/CreateProjectCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/project/CreateProjectCmd.java
@@ -27,6 +27,7 @@
 import org.apache.cloudstack.api.response.ProjectResponse;
 import org.apache.cloudstack.api.response.UserResponse;
 import org.apache.cloudstack.context.CallContext;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.event.EventTypes;
@@ -61,7 +62,7 @@
     @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "name of the project")
     private String name;
 
-    @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, required = true, description = "display text of the project")
+    @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING,  description = "The display text of the project, defaults to the 'name´.")
     private String displayText;
 
     // ///////////////////////////////////////////////////
@@ -98,7 +99,7 @@
     }
 
     public String getDisplayText() {
-        return displayText;
+        return StringUtils.isEmpty(displayText) ? name : displayText;
     }
 
     @Override
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/project/UpdateProjectCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/project/UpdateProjectCmd.java
index 8732f08..6520aa6 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/project/UpdateProjectCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/project/UpdateProjectCmd.java
@@ -28,6 +28,7 @@
 import org.apache.cloudstack.api.response.UserResponse;
 import org.apache.cloudstack.context.CallContext;
 import org.apache.commons.lang3.EnumUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.event.EventTypes;
@@ -35,7 +36,6 @@
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.projects.Project;
 import com.cloud.projects.ProjectAccount;
-import org.apache.commons.lang3.StringUtils;
 
 @APICommand(name = "updateProject", description = "Updates a project", responseObject = ProjectResponse.class, since = "3.0.0",
         requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@@ -67,6 +67,9 @@
             "to promote or demote the user/account based on the roleType (Regular or Admin) provided. Defaults to true")
     private Boolean swapOwner;
 
+    @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "name of the project", since = "4.19.0")
+    private String name;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -87,6 +90,10 @@
         return userId;
     }
 
+    public String getName() {
+        return name;
+    }
+
     public ProjectAccount.Role getRoleType(String role) {
         String type = role.substring(0, 1).toUpperCase() + role.substring(1).toLowerCase();
         if (!EnumUtils.isValidEnum(ProjectAccount.Role.class, type)) {
@@ -136,9 +143,9 @@
 
         Project project = null;
         if (isSwapOwner()) {
-            project = _projectService.updateProject(getId(), getDisplayText(), getAccountName());
+            project = _projectService.updateProject(getId(), getName(), getDisplayText(), getAccountName());
         }  else {
-            project = _projectService.updateProject(getId(), getDisplayText(), getAccountName(), getUserId(), getAccountRole());
+            project = _projectService.updateProject(getId(), getName(), getDisplayText(), getAccountName(), getUserId(), getAccountRole());
         }
         if (project != null) {
             ProjectResponse response = _responseGenerator.createProjectResponse(project);
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java
index a21cbfb..ea4b599 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java
@@ -29,6 +29,7 @@
 import org.apache.cloudstack.api.response.VolumeResponse;
 import org.apache.cloudstack.api.response.ProjectResponse;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.api.APICommand;
@@ -67,8 +68,7 @@
 
     @Parameter(name = ApiConstants.DISPLAY_TEXT,
                type = CommandType.STRING,
-               required = true,
-               description = "the display text of the template. This is usually used for display purposes.",
+               description = "The display text of the template, defaults to the 'name'.",
                length = 4096)
     private String displayText;
 
@@ -144,7 +144,7 @@
     }
 
     public String getDisplayText() {
-        return displayText;
+        return StringUtils.isEmpty(displayText) ? templateName : displayText;
     }
 
     public Boolean isFeatured() {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java
index 255b11a..1a5e851 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java
@@ -39,6 +39,7 @@
 import org.apache.cloudstack.api.response.TemplateResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.context.CallContext;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.exception.ResourceAllocationException;
@@ -60,8 +61,7 @@
 
     @Parameter(name = ApiConstants.DISPLAY_TEXT,
                type = CommandType.STRING,
-               required = true,
-               description = "the display text of the template. This is usually used for display purposes.",
+               description = "The display text of the template, defaults to 'name'.",
                length = 4096)
     private String displayText;
 
@@ -176,7 +176,7 @@
     }
 
     public String getDisplayText() {
-        return displayText;
+        return StringUtils.isEmpty(displayText) ? templateName : displayText;
     }
 
     public String getFormat() {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmd.java
new file mode 100644
index 0000000..935f39b
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmd.java
@@ -0,0 +1,152 @@
+/*
+ * 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.command.user.vm;
+
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.vm.VirtualMachine;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.api.response.VMScheduleResponse;
+import org.apache.cloudstack.vm.schedule.VMScheduleManager;
+
+import javax.inject.Inject;
+import java.util.Date;
+
+@APICommand(name = "createVMSchedule", description = "Create VM Schedule", responseObject = VMScheduleResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
+        authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class CreateVMScheduleCmd extends BaseCmd {
+
+    @Inject
+    VMScheduleManager vmScheduleManager;
+
+    @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
+            type = CommandType.UUID,
+            entityType = UserVmResponse.class,
+            required = true,
+            description = "ID of the VM for which schedule is to be defined")
+    private Long vmId;
+
+    @Parameter(name = ApiConstants.DESCRIPTION,
+            type = CommandType.STRING,
+            required = false,
+            description = "Description of the schedule")
+    private String description;
+
+    @Parameter(name = ApiConstants.SCHEDULE,
+            type = CommandType.STRING,
+            required = true,
+            description = "Schedule for action on VM in cron format. e.g. '0 15 10 * *' for 'at 15:00 on 10th day of every month'")
+    private String schedule;
+
+    @Parameter(name = ApiConstants.TIMEZONE,
+            type = CommandType.STRING,
+            required = true,
+            description = "Specifies a timezone for this command. For more information on the timezone parameter, see TimeZone Format.")
+    private String timeZone;
+
+    @Parameter(name = ApiConstants.ACTION,
+            type = CommandType.STRING,
+            required = true,
+            description = "Action to take on the VM (start/stop/restart/force_stop/force_reboot).")
+    private String action;
+
+    @Parameter(name = ApiConstants.START_DATE,
+            type = CommandType.DATE,
+            required = false,
+            description = "start date from which the schedule becomes active. Defaults to current date plus 1 minute."
+                    + "Use format \"yyyy-MM-dd hh:mm:ss\")")
+    private Date startDate;
+
+    @Parameter(name = ApiConstants.END_DATE,
+            type = CommandType.DATE,
+            required = false,
+            description = "end date after which the schedule becomes inactive"
+                    + "Use format \"yyyy-MM-dd hh:mm:ss\")")
+    private Date endDate;
+
+    @Parameter(name = ApiConstants.ENABLED,
+            type = CommandType.BOOLEAN,
+            required = false,
+            description = "Enable VM schedule. Defaults to true")
+    private Boolean enabled;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getVmId() {
+        return vmId;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public String getSchedule() {
+        return schedule;
+    }
+
+    public String getTimeZone() {
+        return timeZone;
+    }
+
+    public String getAction() {
+        return action;
+    }
+
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    public Date getEndDate() {
+        return endDate;
+    }
+
+    public Boolean getEnabled() {
+        if (enabled == null) {
+            enabled = true;
+        }
+        return enabled;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() {
+        VMScheduleResponse response = vmScheduleManager.createSchedule(this);
+        response.setResponseName(getCommandName());
+        setResponseObject(response);
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        VirtualMachine vm = _entityMgr.findById(VirtualMachine.class, getVmId());
+        if (vm == null) {
+            throw new InvalidParameterValueException(String.format("Unable to find VM by id=%d", getVmId()));
+        }
+        return vm.getAccountId();
+    }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmd.java
new file mode 100644
index 0000000..775a902
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmd.java
@@ -0,0 +1,112 @@
+/*
+ * 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.command.user.vm;
+
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.vm.VirtualMachine;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.api.response.VMScheduleResponse;
+import org.apache.cloudstack.vm.schedule.VMSchedule;
+import org.apache.cloudstack.vm.schedule.VMScheduleManager;
+
+import javax.inject.Inject;
+import java.util.Collections;
+import java.util.List;
+
+@APICommand(name = "deleteVMSchedule", description = "Delete VM Schedule.", responseObject = SuccessResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
+        authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class DeleteVMScheduleCmd extends BaseCmd {
+    @Inject
+    VMScheduleManager vmScheduleManager;
+
+    @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
+            type = CommandType.UUID,
+            entityType = UserVmResponse.class,
+            required = true,
+            description = "ID of VM")
+    private Long vmId;
+    @Parameter(name = ApiConstants.ID,
+            type = CommandType.UUID,
+            entityType = VMScheduleResponse.class,
+            required = false,
+            description = "ID of VM schedule")
+    private Long id;
+    @Parameter(name = ApiConstants.IDS,
+            type = CommandType.LIST,
+            collectionType = CommandType.UUID,
+            entityType = VMScheduleResponse.class,
+            required = false,
+            description = "IDs of VM schedule")
+    private List<Long> ids;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getId() {
+        return id;
+    }
+
+    public List<Long> getIds() {
+        if (ids == null) {
+            return Collections.emptyList();
+        }
+        return ids;
+    }
+
+    public Long getVmId() {
+        return vmId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() {
+        long rowsRemoved = vmScheduleManager.removeSchedule(this);
+
+        if (rowsRemoved > 0) {
+            final SuccessResponse response = new SuccessResponse();
+            response.setResponseName(getCommandName());
+            response.setObjectName(VMSchedule.class.getSimpleName().toLowerCase());
+            setResponseObject(response);
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete VM Schedules");
+        }
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        VirtualMachine vm = _entityMgr.findById(VirtualMachine.class, getVmId());
+        if (vm == null) {
+            throw new InvalidParameterValueException(String.format("Unable to find VM by id=%d", getVmId()));
+        }
+        return vm.getAccountId();
+    }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
index 7aa69bd..bd050b1 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java
@@ -263,6 +263,14 @@
     @Parameter(name = ApiConstants.IO_DRIVER_POLICY, type = CommandType.STRING, description = "Controls specific policies on IO")
     private String ioDriverPolicy;
 
+    @Parameter(name = ApiConstants.NIC_MULTIQUEUE_NUMBER, type = CommandType.INTEGER, since = "4.18",
+            description = "The number of queues for multiqueue NICs.")
+    private Integer nicMultiqueueNumber;
+
+    @Parameter(name = ApiConstants.NIC_PACKED_VIRTQUEUES_ENABLED, type = CommandType.BOOLEAN, since = "4.18",
+            description = "Enable packed virtqueues or not.")
+    private Boolean nicPackedVirtQueues;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -337,6 +345,14 @@
             customparameterMap.put(VmDetailConstants.IOTHREADS, BooleanUtils.toStringTrueFalse(iothreadsEnabled));
         }
 
+        if (nicMultiqueueNumber != null) {
+            customparameterMap.put(VmDetailConstants.NIC_MULTIQUEUE_NUMBER, nicMultiqueueNumber.toString());
+        }
+
+        if (BooleanUtils.toBoolean(nicPackedVirtQueues)) {
+            customparameterMap.put(VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED, BooleanUtils.toStringTrueFalse(nicPackedVirtQueues));
+        }
+
         return customparameterMap;
     }
 
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmd.java
new file mode 100644
index 0000000..3474f1d
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmd.java
@@ -0,0 +1,97 @@
+/*
+ * 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.command.user.vm;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.api.response.VMScheduleResponse;
+import org.apache.cloudstack.vm.schedule.VMSchedule;
+import org.apache.cloudstack.vm.schedule.VMScheduleManager;
+
+import javax.inject.Inject;
+
+@APICommand(name = "listVMSchedule", description = "List VM Schedules.", responseObject = VMScheduleResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
+        authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class ListVMScheduleCmd extends BaseListCmd {
+    @Inject
+    VMScheduleManager vmScheduleManager;
+
+    @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
+            type = CommandType.UUID,
+            entityType = UserVmResponse.class,
+            required = true,
+            description = "ID of the VM for which schedule is to be defined")
+    private Long vmId;
+
+    @Parameter(name = ApiConstants.ID,
+            type = CommandType.UUID,
+            entityType = VMScheduleResponse.class,
+            required = false,
+            description = "ID of VM schedule")
+    private Long id;
+
+    @Parameter(name = ApiConstants.ACTION,
+            type = CommandType.STRING,
+            required = false,
+            description = "Action taken by schedule")
+    private String action;
+
+    @Parameter(name = ApiConstants.ENABLED,
+            type = CommandType.BOOLEAN,
+            required = false,
+            description = "ID of VM schedule")
+    private Boolean enabled;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getVmId() {
+        return vmId;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public String getAction() {
+        return action;
+    }
+
+    public Boolean getEnabled() {
+        return enabled;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+    @Override
+    public void execute() {
+        ListResponse<VMScheduleResponse> response = vmScheduleManager.listSchedule(this);
+        response.setResponseName(getCommandName());
+        response.setObjectName(VMSchedule.class.getSimpleName().toLowerCase());
+        setResponseObject(response);
+    }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java
index e609655..07d83b4 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java
@@ -26,7 +26,7 @@
 import org.apache.cloudstack.api.ApiCommandResourceType;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiConstants.VMDetails;
-import org.apache.cloudstack.api.BaseListTaggedResourcesCmd;
+import org.apache.cloudstack.api.BaseListRetrieveOnlyResourceCountCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ResponseObject.ResponseView;
 import org.apache.cloudstack.api.command.user.UserCmd;
@@ -44,6 +44,7 @@
 import org.apache.cloudstack.api.response.UserVmResponse;
 import org.apache.cloudstack.api.response.VpcResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.commons.lang3.BooleanUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.exception.InvalidParameterValueException;
@@ -54,7 +55,7 @@
 
 @APICommand(name = "listVirtualMachines", description = "List the virtual machines owned by the account.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
         requestHasSensitiveInfo = false, responseHasSensitiveInfo = true)
-public class ListVMsCmd extends BaseListTaggedResourcesCmd implements UserCmd {
+public class ListVMsCmd extends BaseListRetrieveOnlyResourceCountCmd implements UserCmd {
     public static final Logger s_logger = Logger.getLogger(ListVMsCmd.class.getName());
 
     private static final String s_name = "listvirtualmachinesresponse";
@@ -148,7 +149,6 @@
     @Parameter(name = ApiConstants.USER_DATA, type = CommandType.BOOLEAN, description = "Whether to return the VMs' user data or not. By default, user data will not be returned.", since = "4.18.0.0")
     private Boolean showUserData;
 
-
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -255,14 +255,11 @@
 
     @Override
     public Boolean getDisplay() {
-        if (display != null) {
-            return display;
-        }
-        return super.getDisplay();
+        return BooleanUtils.toBooleanDefaultIfNull(display, super.getDisplay());
     }
 
     public Boolean getShowIcon() {
-        return showIcon != null ? showIcon : false;
+        return BooleanUtils.toBooleanDefaultIfNull(showIcon, false);
     }
 
     public Boolean getAccumulate() {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmd.java
new file mode 100644
index 0000000..72f85c1
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmd.java
@@ -0,0 +1,139 @@
+/*
+ * 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.command.user.vm;
+
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.vm.VirtualMachine;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.VMScheduleResponse;
+import org.apache.cloudstack.vm.schedule.VMSchedule;
+import org.apache.cloudstack.vm.schedule.VMScheduleManager;
+
+import javax.inject.Inject;
+import java.util.Date;
+
+@APICommand(name = "updateVMSchedule", description = "Update VM Schedule.", responseObject = VMScheduleResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
+        authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class UpdateVMScheduleCmd extends BaseCmd {
+    @Inject
+    VMScheduleManager vmScheduleManager;
+
+    @Parameter(name = ApiConstants.ID,
+            type = CommandType.UUID,
+            entityType = VMScheduleResponse.class,
+            required = true,
+            description = "ID of VM schedule")
+    private Long id;
+
+    @Parameter(name = ApiConstants.DESCRIPTION,
+            type = CommandType.STRING,
+            required = false,
+            description = "Name of the schedule")
+    private String description;
+
+    @Parameter(name = ApiConstants.SCHEDULE,
+            type = CommandType.STRING,
+            required = false,
+            description = "Schedule for action on VM in cron format. e.g. '0 15 10 * *' for 'at 15:00 on 10th day of every month'")
+    private String schedule;
+
+    @Parameter(name = ApiConstants.TIMEZONE,
+            type = CommandType.STRING,
+            required = false,
+            description = "Specifies a timezone for this command. For more information on the timezone parameter, see TimeZone Format.")
+    private String timeZone;
+
+    @Parameter(name = ApiConstants.START_DATE,
+            type = CommandType.DATE,
+            required = false,
+            description = "start date from which the schedule becomes active"
+                    + "Use format \"yyyy-MM-dd hh:mm:ss\")")
+    private Date startDate;
+
+    @Parameter(name = ApiConstants.END_DATE,
+            type = CommandType.DATE,
+            required = false,
+            description = "end date after which the schedule becomes inactive"
+                    + "Use format \"yyyy-MM-dd hh:mm:ss\")")
+    private Date endDate;
+
+    @Parameter(name = ApiConstants.ENABLED,
+            type = CommandType.BOOLEAN,
+            required = false,
+            description = "Enable VM schedule")
+    private Boolean enabled;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getId() {
+        return id;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public String getSchedule() {
+        return schedule;
+    }
+
+    public String getTimeZone() {
+        return timeZone;
+    }
+
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    public Date getEndDate() {
+        return endDate;
+    }
+
+    public Boolean getEnabled() {
+        return enabled;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() {
+        VMScheduleResponse response = vmScheduleManager.updateSchedule(this);
+        response.setResponseName(getCommandName());
+        setResponseObject(response);
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        VMSchedule vmSchedule = _entityMgr.findById(VMSchedule.class, getId());
+        if (vmSchedule == null) {
+            throw new InvalidParameterValueException(String.format("Unable to find vmSchedule by id=%d", getId()));
+        }
+        VirtualMachine vm = _entityMgr.findById(VirtualMachine.class, vmSchedule.getVmId());
+        return vm.getAccountId();
+    }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java
index fdac3ff..b62a909 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java
@@ -22,7 +22,7 @@
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiCommandResourceType;
 import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.BaseListTaggedResourcesCmd;
+import org.apache.cloudstack.api.BaseListRetrieveOnlyResourceCountCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ResponseObject.ResponseView;
 import org.apache.cloudstack.api.command.user.UserCmd;
@@ -35,13 +35,14 @@
 import org.apache.cloudstack.api.response.UserVmResponse;
 import org.apache.cloudstack.api.response.VolumeResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.commons.lang3.BooleanUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.storage.Volume;
 
 @APICommand(name = "listVolumes", description = "Lists all volumes.", responseObject = VolumeResponse.class, responseView = ResponseView.Restricted, entityType = {
         Volume.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
-public class ListVolumesCmd extends BaseListTaggedResourcesCmd implements UserCmd {
+public class ListVolumesCmd extends BaseListRetrieveOnlyResourceCountCmd implements UserCmd {
     public static final Logger s_logger = Logger.getLogger(ListVolumesCmd.class.getName());
 
     private static final String s_name = "listvolumesresponse";
@@ -145,15 +146,13 @@
 
     @Override
     public Boolean getDisplay() {
-        if (display != null) {
-            return display;
-        }
-        return super.getDisplay();
+        return BooleanUtils.toBooleanDefaultIfNull(display, super.getDisplay());
     }
 
     public String getState() {
         return state;
     }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java
index af70049..7ca66b2 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java
@@ -16,7 +16,7 @@
 // under the License.
 package org.apache.cloudstack.api.command.user.vpc;
 
-import com.cloud.network.NetworkService;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import org.apache.cloudstack.acl.RoleType;
@@ -40,6 +40,7 @@
 import com.cloud.exception.InsufficientCapacityException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.NetworkService;
 import com.cloud.network.vpc.Vpc;
 
 @APICommand(name = "createVPC", description = "Creates a VPC", responseObject = VpcResponse.class, responseView = ResponseView.Restricted, entityType = {Vpc.class},
@@ -72,8 +73,8 @@
     @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "the name of the VPC")
     private String vpcName;
 
-    @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, required = true, description = "the display text of " +
-            "the VPC")
+    @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, description = "The display text of the VPC, defaults to its 'name'.")
+
     private String displayText;
 
     @Parameter(name = ApiConstants.CIDR, type = CommandType.STRING, required = true, description = "the cidr of the VPC. All VPC " +
@@ -112,6 +113,12 @@
     @Parameter(name = ApiConstants.IP6_DNS2, type = CommandType.STRING, description = "the second IPv6 DNS for the VPC", since = "4.18.0")
     private String ip6Dns2;
 
+    @Parameter(name = ApiConstants.SOURCE_NAT_IP, type = CommandType.STRING, description = "IPV4 address to be assigned to the public interface of the network router." +
+            "This address will be used as source NAT address for the networks in ths VPC. " +
+            "\nIf an address is given and it cannot be acquired, an error will be returned and the network won´t be implemented,",
+            since = "4.19")
+    private String sourceNatIP;
+
     // ///////////////////////////////////////////////////
     // ///////////////// Accessors ///////////////////////
     // ///////////////////////////////////////////////////
@@ -137,7 +144,7 @@
     }
 
     public String getDisplayText() {
-        return displayText;
+        return StringUtils.isEmpty(displayText) ? vpcName    : displayText;
     }
 
     public Long getVpcOffering() {
@@ -179,6 +186,15 @@
         return display;
     }
 
+
+    public String getSourceNatIP() {
+        return sourceNatIP;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
     @Override
     public void create() throws ResourceAllocationException {
         Vpc vpc = _vpcService.createVpc(this);
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/ListVPCsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/ListVPCsCmd.java
index b230603..76cbcca 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/ListVPCsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/ListVPCsCmd.java
@@ -142,9 +142,7 @@
     @Override
     public void execute() {
         Pair<List<? extends Vpc>, Integer> vpcs =
-            _vpcService.listVpcs(getId(), getVpcName(), getDisplayText(), getSupportedServices(), getCidr(), getVpcOffId(), getState(), getAccountName(), getDomainId(),
-                getKeyword(), getStartIndex(), getPageSizeVal(), getZoneId(), isRecursive(), listAll(), getRestartRequired(), getTags(),
-                getProjectId(), getDisplay());
+            _vpcService.listVpcs(this);
         ListResponse<VpcResponse> response = new ListResponse<VpcResponse>();
         List<VpcResponse> vpcResponses = new ArrayList<VpcResponse>();
         for (Vpc vpc : vpcs.first()) {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmd.java
index 4c3408e..d4c7d0d 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmd.java
@@ -34,6 +34,8 @@
 import org.apache.cloudstack.api.response.VpcResponse;
 
 import com.cloud.event.EventTypes;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.network.vpc.Vpc;
 import com.cloud.user.Account;
 
@@ -63,6 +65,12 @@
             description = "MTU to be configured on the network VR's public facing interfaces", since = "4.18.0")
     private Integer publicMtu;
 
+    @Parameter(name = ApiConstants.SOURCE_NAT_IP,
+            type = CommandType.STRING,
+            description = "IPV4 address to be assigned to the public interface of the network router. This address must already be acquired for this VPC",
+            since = "4.19")
+    private String sourceNatIP;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -87,6 +95,10 @@
         return publicMtu;
     }
 
+    public String getSourceNatIP() {
+        return sourceNatIP;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
@@ -107,13 +119,22 @@
 
     @Override
     public void execute() {
-        Vpc result = _vpcService.updateVpc(getId(), getVpcName(), getDisplayText(), getCustomId(), isDisplayVpc(), getPublicMtu());
-        if (result != null) {
-            VpcResponse response = _responseGenerator.createVpcResponse(getResponseView(), result);
-            response.setResponseName(getCommandName());
-            setResponseObject(response);
-        } else {
-            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update VPC");
+        try {
+            Vpc result = _vpcService.updateVpc(this);
+            if (result != null) {
+                VpcResponse response = _responseGenerator.createVpcResponse(getResponseView(), result);
+                response.setResponseName(getCommandName());
+                setResponseObject(response);
+            } else {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update VPC");
+            }
+        } catch (final ResourceUnavailableException ex) {
+            s_logger.warn("Exception: ", ex);
+            throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
+        } catch (final InsufficientCapacityException ex) {
+            s_logger.info(ex);
+            s_logger.trace(ex);
+            throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage());
         }
     }
 
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/AsyncJobResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/AsyncJobResponse.java
index eecd6be..3eeaaef 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/AsyncJobResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/AsyncJobResponse.java
@@ -32,9 +32,21 @@
 public class AsyncJobResponse extends BaseResponse {
 
     @SerializedName("accountid")
-    @Param(description = "the account that executed the async command")
+    @Param(description = "the account id that executed the async command")
     private String accountId;
 
+    @SerializedName("account")
+    @Param(description = "the account that executed the async command")
+    private String account;
+
+    @SerializedName("domainid")
+    @Param(description = "the domain id that executed the async command")
+    private String domainid;
+
+    @SerializedName("domainpath")
+    @Param(description = "the domain that executed the async command")
+    private String domainPath;
+
     @SerializedName(ApiConstants.USER_ID)
     @Param(description = "the user that executed the async command")
     private String userId;
@@ -71,6 +83,10 @@
     @Param(description = "the unique ID of the instance/entity object related to the job")
     private String jobInstanceId;
 
+    @SerializedName("managementserverid")
+    @Param(description = "the msid of the management server on which the job is running", since = "4.19")
+    private Long msid;
+
     @SerializedName(ApiConstants.CREATED)
     @Param(description = "  the created date of the job")
     private Date created;
@@ -83,6 +99,18 @@
         this.accountId = accountId;
     }
 
+    public void setAccount(String account) {
+        this.account = account;
+    }
+
+    public void setDomainId(String domainid) {
+        this.domainid = domainid;
+    }
+
+    public void setDomainPath(String domainPath) {
+        this.domainPath = domainPath;
+    }
+
     public void setUserId(String userId) {
         this.userId = userId;
     }
@@ -127,4 +155,8 @@
     public void setRemoved(final Date removed) {
         this.removed = removed;
     }
+
+    public void setMsid(Long msid) {
+        this.msid = msid;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/BaseRoleResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/BaseRoleResponse.java
index 339d092..b1bba90 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/BaseRoleResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/BaseRoleResponse.java
@@ -36,6 +36,11 @@
     @Param(description = "the description of the role")
     private String roleDescription;
 
+    @SerializedName(ApiConstants.IS_PUBLIC)
+    @Param(description = "Indicates whether the role will be visible to all users (public) or only to root admins (private)." +
+            " If this parameter is not specified during the creation of the role its value will be defaulted to true (public).")
+    private boolean publicRole = true;
+
     public void setId(String id) {
         this.id = id;
     }
@@ -47,4 +52,8 @@
     public void setDescription(String description) {
         this.roleDescription = description;
     }
+
+    public void setPublicRole(boolean publicRole) {
+        this.publicRole = publicRole;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/EventResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/EventResponse.java
index a3ca777..8f65492 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/EventResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/EventResponse.java
@@ -93,6 +93,10 @@
     @Param(description = "whether the event is parented")
     private String parentId;
 
+    @SerializedName(ApiConstants.ARCHIVED)
+    @Param(description = "whether the event has been archived or not")
+    private Boolean archived;
+
     public void setId(String id) {
         this.id = id;
     }
@@ -173,4 +177,8 @@
     public void setProjectName(String projectName) {
         this.projectName = projectName;
     }
+
+    public void setArchived(Boolean archived) {
+        this.archived = archived;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/GuestOSResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/GuestOSResponse.java
index c1a57c3..2e3c5bb 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/GuestOSResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/GuestOSResponse.java
@@ -35,13 +35,25 @@
     @Param(description = "the ID of the OS category")
     private String osCategoryId;
 
+    @SerializedName(ApiConstants.OS_CATEGORY_NAME)
+    @Param(description = "the name of the OS category")
+    private String osCategoryName;
+
+    @SerializedName(ApiConstants.NAME)
+    @Param(description = "the name of the OS type")
+    private String name;
+
+    /**
+     * @deprecated description, as name is the correct interpretation and is needed for UI forms
+     */
+    @Deprecated(since = "4.19")
     @SerializedName(ApiConstants.DESCRIPTION)
     @Param(description = "the name/description of the OS type")
     private String description;
 
     @SerializedName(ApiConstants.IS_USER_DEFINED)
     @Param(description = "is the guest OS user defined")
-    private Boolean isUserDefined;
+    private String isUserDefined;
 
     public String getId() {
         return id;
@@ -59,6 +71,22 @@
         this.osCategoryId = osCategoryId;
     }
 
+    public String getOsCategoryName() {
+        return osCategoryName;
+    }
+
+    public void setOsCategoryName(String osCategoryName) {
+        this.osCategoryName = osCategoryName;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
     public String getDescription() {
         return description;
     }
@@ -67,11 +95,11 @@
         this.description = description;
     }
 
-    public Boolean getIsUserDefined() {
+    public String getIsUserDefined() {
         return isUserDefined;
     }
 
-    public void setIsUserDefined(Boolean isUserDefined) {
+    public void setIsUserDefined(String isUserDefined) {
         this.isUserDefined = isUserDefined;
     }
 
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/HypervisorGuestOsNamesResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/HypervisorGuestOsNamesResponse.java
new file mode 100644
index 0000000..52f55bf
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/response/HypervisorGuestOsNamesResponse.java
@@ -0,0 +1,76 @@
+// 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.response;
+
+import java.util.List;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+
+public class HypervisorGuestOsNamesResponse extends BaseResponse {
+    @SerializedName(ApiConstants.HYPERVISOR)
+    @Param(description = "the hypervisor")
+    private String hypervisor;
+
+    @SerializedName(ApiConstants.HYPERVISOR_VERSION)
+    @Param(description = "version of the hypervisor for guest os names")
+    private String hypervisorVersion;
+
+    @SerializedName(ApiConstants.GUEST_OS_LIST)
+    @Param(description = "the guest OS list of the hypervisor", responseObject = HypervisorGuestOsResponse.class)
+    private List<HypervisorGuestOsResponse> guestOSList;
+
+    @SerializedName(ApiConstants.GUEST_OS_COUNT)
+    @Param(description = "the guest OS count of the hypervisor")
+    private Integer guestOSCount;
+
+    public String getHypervisor() {
+        return hypervisor;
+    }
+
+    public void setHypervisor(String hypervisor) {
+        this.hypervisor = hypervisor;
+    }
+
+    public String getHypervisorVersion() {
+        return hypervisorVersion;
+    }
+
+    public void setHypervisorVersion(String hypervisorVersion) {
+        this.hypervisorVersion = hypervisorVersion;
+    }
+
+    public List<HypervisorGuestOsResponse> getGuestOSList() {
+        return guestOSList;
+    }
+
+    public void setGuestOSList(List<HypervisorGuestOsResponse> guestOSList) {
+        this.guestOSList = guestOSList;
+    }
+
+    public Integer getGuestOSCount() {
+        return guestOSCount;
+    }
+
+    public void setGuestOSCount(Integer guestOSCount) {
+        this.guestOSCount = guestOSCount;
+    }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/HypervisorGuestOsResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/HypervisorGuestOsResponse.java
new file mode 100644
index 0000000..e9ef630
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/response/HypervisorGuestOsResponse.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.api.response;
+
+import com.google.gson.annotations.SerializedName;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+
+import com.cloud.serializer.Param;
+
+public class HypervisorGuestOsResponse extends BaseResponse {
+    @SerializedName(ApiConstants.OS_DISPLAY_NAME)
+    @Param(description = "standard display name for the Guest OS")
+    private String osStdName;
+
+    @SerializedName(ApiConstants.OS_NAME_FOR_HYPERVISOR)
+    @Param(description = "hypervisor specific name for the Guest OS")
+    private String osNameForHypervisor;
+
+    public String getOsStdName() {
+        return osStdName;
+    }
+
+    public void setOsStdName(String osStdName) {
+        this.osStdName = osStdName;
+    }
+
+    public String getOsNameForHypervisor() {
+        return osNameForHypervisor;
+    }
+
+    public void setOsNameForHypervisor(String osNameForHypervisor) {
+        this.osNameForHypervisor = osNameForHypervisor;
+    }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java
index 13497d8..7e3adc4 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java
@@ -96,15 +96,19 @@
     private Boolean isSystem;
 
     @SerializedName(ApiConstants.VIRTUAL_MACHINE_ID)
-    @Param(description = "virtual machine id the ip address is assigned to (not null only for static nat Ip)")
+    @Param(description = "virtual machine id the ip address is assigned to")
     private String virtualMachineId;
 
+    @SerializedName(ApiConstants.VIRTUAL_MACHINE_TYPE)
+    @Param(description = "virtual machine type the ip address is assigned to", since = "4.19.0")
+    private String virtualMachineType;
+
     @SerializedName("vmipaddress")
     @Param(description = "virtual machine (dnat) ip address (not null only for static nat Ip)")
     private String virtualMachineIp;
 
     @SerializedName("virtualmachinename")
-    @Param(description = "virtual machine name the ip address is assigned to (not null only for static nat Ip)")
+    @Param(description = "virtual machine name the ip address is assigned to")
     private String virtualMachineName;
 
     @SerializedName("virtualmachinedisplayname")
@@ -159,10 +163,9 @@
     @Param(description="the name of the Network where ip belongs to")
     private String networkName;
 
-    /*
-        @SerializedName(ApiConstants.JOB_ID) @Param(description="shows the current pending asynchronous job ID. This tag is not returned if no current pending jobs are acting on the volume")
-        private IdentityProxy jobId = new IdentityProxy("async_job");
-    */
+    @SerializedName(ApiConstants.HAS_RULES)
+    @Param(description="whether the ip address has Firewall/PortForwarding/LoadBalancing rules defined")
+    private boolean hasRules;
 
     public void setIpAddress(String ipAddress) {
         this.ipAddress = ipAddress;
@@ -232,6 +235,10 @@
         this.virtualMachineId = virtualMachineId;
     }
 
+    public void setVirtualMachineType(String virtualMachineType) {
+        this.virtualMachineType = virtualMachineType;
+    }
+
     public void setVirtualMachineIp(String virtualMachineIp) {
         this.virtualMachineIp = virtualMachineIp;
     }
@@ -305,4 +312,8 @@
     public void setNetworkName(String networkName) {
         this.networkName = networkName;
     }
+
+    public void setHasRules(final boolean hasRules) {
+        this.hasRules = hasRules;
+    }
 }
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/VMScheduleResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/VMScheduleResponse.java
new file mode 100644
index 0000000..813a48e
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/response/VMScheduleResponse.java
@@ -0,0 +1,109 @@
+/*
+ * 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.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.EntityReference;
+import org.apache.cloudstack.vm.schedule.VMSchedule;
+
+import java.util.Date;
+
+@EntityReference(value = VMSchedule.class)
+public class VMScheduleResponse extends BaseResponse {
+    @SerializedName(ApiConstants.ID)
+    @Param(description = "the ID of VM schedule")
+    private String id;
+
+    @SerializedName(ApiConstants.VIRTUAL_MACHINE_ID)
+    @Param(description = "ID of virtual machine")
+    private String vmId;
+
+    @SerializedName(ApiConstants.DESCRIPTION)
+    @Param(description = "Description of VM schedule")
+    private String description;
+
+    @SerializedName(ApiConstants.SCHEDULE)
+    @Param(description = "Cron formatted VM schedule")
+    private String schedule;
+
+    @SerializedName(ApiConstants.TIMEZONE)
+    @Param(description = "Timezone of the schedule")
+    private String timeZone;
+
+    @SerializedName(ApiConstants.ACTION)
+    @Param(description = "Action")
+    private VMSchedule.Action action;
+
+    @SerializedName(ApiConstants.ENABLED)
+    @Param(description = "VM schedule is enabled")
+    private boolean enabled;
+
+    @SerializedName(ApiConstants.START_DATE)
+    @Param(description = "Date from which the schedule is active")
+    private Date startDate;
+
+    @SerializedName(ApiConstants.END_DATE)
+    @Param(description = "Date after which the schedule becomes inactive")
+    private Date endDate;
+
+    @SerializedName(ApiConstants.CREATED)
+    @Param(description = "Date when the schedule was created")
+    private Date created;
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setVmId(String vmId) {
+        this.vmId = vmId;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public void setSchedule(String schedule) {
+        this.schedule = schedule;
+    }
+
+    public void setTimeZone(String timeZone) {
+        this.timeZone = timeZone;
+    }
+
+    public void setAction(VMSchedule.Action action) {
+        this.action = action;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    public void setStartDate(Date startDate) {
+        this.startDate = startDate;
+    }
+
+    public void setEndDate(Date endDate) {
+        this.endDate = endDate;
+    }
+
+    public void setCreated(Date created) {this.created = created;}
+}
diff --git a/api/src/main/java/org/apache/cloudstack/management/ManagementServerHost.java b/api/src/main/java/org/apache/cloudstack/management/ManagementServerHost.java
index 0159fb2..54a53f3 100644
--- a/api/src/main/java/org/apache/cloudstack/management/ManagementServerHost.java
+++ b/api/src/main/java/org/apache/cloudstack/management/ManagementServerHost.java
@@ -16,12 +16,13 @@
 // under the License.
 package org.apache.cloudstack.management;
 
+import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.api.Identity;
 import org.apache.cloudstack.api.InternalIdentity;
 
-public interface ManagementServerHost extends InternalIdentity, Identity {
+public interface ManagementServerHost extends InternalIdentity, Identity, ControlledEntity {
     enum State {
-        Up, Down
+        Up, Down, PreparingToShutDown, ReadyToShutDown, ShuttingDown
     }
 
     long getMsid();
diff --git a/api/src/main/java/org/apache/cloudstack/userdata/UserDataManager.java b/api/src/main/java/org/apache/cloudstack/userdata/UserDataManager.java
new file mode 100644
index 0000000..4dfcd0a
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/userdata/UserDataManager.java
@@ -0,0 +1,27 @@
+// 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.userdata;
+
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.framework.config.Configurable;
+
+import com.cloud.utils.component.Manager;
+
+public interface UserDataManager extends Manager, Configurable {
+    String concatenateUserData(String userdata1, String userdata2, String userdataProvider);
+    String validateUserData(String userData, BaseCmd.HTTPMethod httpmethod);
+}
diff --git a/api/src/main/java/org/apache/cloudstack/vm/schedule/VMSchedule.java b/api/src/main/java/org/apache/cloudstack/vm/schedule/VMSchedule.java
new file mode 100644
index 0000000..b1e7df3
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/vm/schedule/VMSchedule.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.vm.schedule;
+
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
+
+import java.time.ZoneId;
+import java.util.Date;
+
+public interface VMSchedule extends Identity, InternalIdentity {
+    enum Action {
+        START, STOP, REBOOT, FORCE_STOP, FORCE_REBOOT
+    }
+
+    long getVmId();
+
+    String getDescription();
+
+    String getSchedule();
+
+    String getTimeZone();
+
+    Action getAction();
+
+    boolean getEnabled();
+
+    Date getStartDate();
+
+    Date getEndDate();
+
+    ZoneId getTimeZoneId();
+
+    Date getCreated();
+}
diff --git a/api/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduleManager.java b/api/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduleManager.java
new file mode 100644
index 0000000..6aca05b
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduleManager.java
@@ -0,0 +1,40 @@
+/*
+ * 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.vm.schedule;
+
+import org.apache.cloudstack.api.command.user.vm.CreateVMScheduleCmd;
+import org.apache.cloudstack.api.command.user.vm.DeleteVMScheduleCmd;
+import org.apache.cloudstack.api.command.user.vm.ListVMScheduleCmd;
+import org.apache.cloudstack.api.command.user.vm.UpdateVMScheduleCmd;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.VMScheduleResponse;
+
+public interface VMScheduleManager {
+    VMScheduleResponse createSchedule(CreateVMScheduleCmd createVMScheduleCmd);
+
+    VMScheduleResponse createResponse(VMSchedule vmSchedule);
+
+    ListResponse<VMScheduleResponse> listSchedule(ListVMScheduleCmd listVMScheduleCmd);
+
+    VMScheduleResponse updateSchedule(UpdateVMScheduleCmd updateVMScheduleCmd);
+
+    long removeScheduleByVmId(long vmId, boolean expunge);
+
+    Long removeSchedule(DeleteVMScheduleCmd deleteVMScheduleCmd);
+}
diff --git a/api/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduledJob.java b/api/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduledJob.java
new file mode 100644
index 0000000..d7a18b7
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduledJob.java
@@ -0,0 +1,38 @@
+/*
+ * 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.vm.schedule;
+
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
+
+import java.util.Date;
+
+public interface VMScheduledJob extends Identity, InternalIdentity {
+    long getVmId();
+
+    long getVmScheduleId();
+
+    Long getAsyncJobId();
+
+    void setAsyncJobId(long asyncJobId);
+
+    VMSchedule.Action getAction();
+
+    Date getScheduledTime();
+}
diff --git a/api/src/main/resources/META-INF/cloudstack/api-planner/module.properties b/api/src/main/resources/META-INF/cloudstack/api-planner/module.properties
index 8eed879..a207387 100644
--- a/api/src/main/resources/META-INF/cloudstack/api-planner/module.properties
+++ b/api/src/main/resources/META-INF/cloudstack/api-planner/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=api-planner
-parent=planner
\ No newline at end of file
+parent=planner
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmdTest.java
new file mode 100644
index 0000000..e28720f
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmdTest.java
@@ -0,0 +1,37 @@
+// 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.command.admin.offering;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.springframework.test.util.ReflectionTestUtils;
+
+public class CreateDiskOfferingCmdTest {
+
+    @InjectMocks
+    private CreateDiskOfferingCmd createDiskOfferingCmd = new CreateDiskOfferingCmd();
+
+    @Test
+    public void testGetDisplayTextWhenEmpty() {
+        String netName = "net-offering";
+        ReflectionTestUtils.setField(createDiskOfferingCmd , "offeringName", netName);
+        Assert.assertEquals(createDiskOfferingCmd.getDisplayText(), netName);
+    }
+
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/offering/CreateNetworkOfferingCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/offering/CreateNetworkOfferingCmdTest.java
new file mode 100644
index 0000000..8b95456
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/offering/CreateNetworkOfferingCmdTest.java
@@ -0,0 +1,37 @@
+// 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.command.admin.offering;
+
+import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.springframework.test.util.ReflectionTestUtils;
+
+public class CreateNetworkOfferingCmdTest {
+
+    @InjectMocks
+    private CreateNetworkOfferingCmd createNetworkOfferingCmd = new CreateNetworkOfferingCmd();
+
+    @Test
+    public void createVpcNtwkOffWithEmptyDisplayText() {
+        String netName = "network";
+        ReflectionTestUtils.setField(createNetworkOfferingCmd, "networkOfferingName", netName);
+        Assert.assertEquals(createNetworkOfferingCmd.getDisplayText(), netName);
+    }
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmdTest.java
new file mode 100644
index 0000000..717b5c326
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmdTest.java
@@ -0,0 +1,40 @@
+// 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.command.admin.offering;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CreateServiceOfferingCmdTest {
+
+    @InjectMocks
+    private CreateServiceOfferingCmd createServiceOfferingCmd;
+
+    @Test
+    public void testGetDisplayTextWhenEmpty() {
+        String netName = "net-offering";
+        ReflectionTestUtils.setField(createServiceOfferingCmd, "serviceOfferingName", netName);
+        Assert.assertEquals(createServiceOfferingCmd.getDisplayText(), netName);
+    }
+
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmdTest.java
index 7a98626..61a3c8f 100644
--- a/api/src/test/java/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmdTest.java
+++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmdTest.java
@@ -16,16 +16,10 @@
 // under the License.
 package org.apache.cloudstack.api.command.admin.vm;
 
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.exception.ManagementServerException;
-import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.exception.VirtualMachineMigrationException;
-import com.cloud.host.Host;
-import com.cloud.resource.ResourceService;
-import com.cloud.uservm.UserVm;
-import com.cloud.utils.db.UUIDManager;
-import com.cloud.vm.UserVmService;
-import com.cloud.vm.VirtualMachine;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ResponseGenerator;
 import org.apache.cloudstack.api.ResponseObject;
@@ -40,13 +34,21 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.Spy;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.springframework.test.util.ReflectionTestUtils;
 
-import java.util.List;
-import java.util.Map;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ManagementServerException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.exception.VirtualMachineMigrationException;
+import com.cloud.host.Host;
+import com.cloud.resource.ResourceService;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.db.UUIDManager;
+import com.cloud.vm.UserVmService;
+import com.cloud.vm.VirtualMachine;
 
-@RunWith(PowerMockRunner.class)
+@RunWith(MockitoJUnitRunner.class)
 public class MigrateVirtualMachineWithVolumeCmdTest {
     @Mock
     UserVmService userVmServiceMock;
@@ -68,44 +70,46 @@
 
     @Spy
     @InjectMocks
-    MigrateVirtualMachineWithVolumeCmd cmdSpy = new MigrateVirtualMachineWithVolumeCmd();
+    MigrateVirtualMachineWithVolumeCmd cmdSpy;
 
     private Long hostId = 1L;
-    private Long virtualMachineUuid = 1L;
+    private Long virtualMachineId = 1L;
     private String virtualMachineName = "VM-name";
-    private Map<String, String> migrateVolumeTo = Map.of("key","value");
+    private  Map<String, String> migrateVolumeTo = null;
     private SystemVmResponse systemVmResponse = new SystemVmResponse();
     private UserVmResponse userVmResponse = new UserVmResponse();
 
     @Before
-    public void setup() {
-        Mockito.when(cmdSpy.getVirtualMachineId()).thenReturn(virtualMachineUuid);
-        Mockito.when(cmdSpy.getHostId()).thenReturn(hostId);
-        Mockito.when(cmdSpy.getVolumeToPool()).thenReturn(migrateVolumeTo);
+    public void setUp() throws Exception {
+        ReflectionTestUtils.setField(cmdSpy, "virtualMachineId", virtualMachineId);
+        migrateVolumeTo = new HashMap<>();
+        migrateVolumeTo.put("volume", "abc");
+        migrateVolumeTo.put("pool", "xyz");
     }
 
     @Test
-    public void executeTestHostIdIsNullAndMigrateVolumeToIsNullThrowsInvalidParameterValueException(){
+    public void executeTestRequiredArgsNullThrowsInvalidParameterValueException() {
         ReflectionTestUtils.setField(cmdSpy, "hostId", null);
         ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", null);
+        ReflectionTestUtils.setField(cmdSpy, "autoSelect", null);
 
         try {
             cmdSpy.execute();
         } catch (Exception e) {
             Assert.assertEquals(InvalidParameterValueException.class, e.getClass());
-            String expected = String.format("Either %s or %s must be passed for migrating the VM.", ApiConstants.HOST_ID, ApiConstants.MIGRATE_TO);
+            String expected = String.format("Either %s or %s must be passed or %s must be true for migrating the VM.", ApiConstants.HOST_ID, ApiConstants.MIGRATE_TO, ApiConstants.AUTO_SELECT);
             Assert.assertEquals(expected , e.getMessage());
         }
     }
 
     @Test
-    public void executeTestVMIsStoppedAndHostIdIsNotNullThrowsInvalidParameterValueException(){
+    public void executeTestVMIsStoppedAndHostIdIsNotNullThrowsInvalidParameterValueException() {
         ReflectionTestUtils.setField(cmdSpy, "hostId", hostId);
         ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
 
         Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
         Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Stopped);
-        Mockito.when(virtualMachineMock.toString()).thenReturn(String.format("VM [uuid: %s, name: %s]", virtualMachineUuid, virtualMachineName));
+        Mockito.when(virtualMachineMock.toString()).thenReturn(String.format("VM [uuid: %s, name: %s]", virtualMachineId, virtualMachineName));
 
         try {
             cmdSpy.execute();
@@ -117,33 +121,35 @@
     }
 
     @Test
-    public void executeTestVMIsRunningAndHostIdIsNullThrowsInvalidParameterValueException(){
+    public void executeTestVMIsRunningHostIdIsNullAndAutoSelectIsFalseThrowsInvalidParameterValueException() {
         ReflectionTestUtils.setField(cmdSpy, "hostId", null);
+        ReflectionTestUtils.setField(cmdSpy, "autoSelect", false);
         ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
 
         Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
         Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Running);
-        Mockito.when(virtualMachineMock.toString()).thenReturn(String.format("VM [uuid: %s, name: %s]", virtualMachineUuid, virtualMachineName));
+        Mockito.when(virtualMachineMock.toString()).thenReturn(String.format("VM [uuid: %s, name: %s]", virtualMachineId, virtualMachineName));
 
         try {
             cmdSpy.execute();
         } catch (Exception e) {
             Assert.assertEquals(InvalidParameterValueException.class, e.getClass());
-            String expected = String.format("%s is not in the Stopped state to migrate, use the %s parameter to migrate it to a new host.", virtualMachineMock,
-                    ApiConstants.HOST_ID);
+            String expected = String.format("%s is not in the Stopped state to migrate, use the %s or %s parameter to migrate it to a new host.", virtualMachineMock,
+                    ApiConstants.HOST_ID, ApiConstants.AUTO_SELECT);
             Assert.assertEquals(expected , e.getMessage());
         }
     }
 
     @Test
-    public void executeTestHostIdIsNullThrowsInvalidParameterValueException(){
+    public void executeTestHostIdIsNullThrowsInvalidParameterValueException() {
+        ReflectionTestUtils.setField(cmdSpy, "virtualMachineId", virtualMachineId);
         ReflectionTestUtils.setField(cmdSpy, "hostId", hostId);
         ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
+        ReflectionTestUtils.setField(cmdSpy, "autoSelect", false);
 
         Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
         Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Running);
         Mockito.when(resourceServiceMock.getHost(Mockito.anyLong())).thenReturn(null);
-        Mockito.when(uuidManagerMock.getUuid(Host.class, virtualMachineUuid)).thenReturn(virtualMachineUuid.toString());
 
         try {
             cmdSpy.execute();
@@ -154,15 +160,22 @@
         }
     }
 
+    private Map getMockedMigrateVolumeToApiCmdParam() {
+        Map<String, String> migrateVolumeTo = new HashMap<>();
+        migrateVolumeTo.put("volume", "abc");
+        migrateVolumeTo.put("pool", "xyz");
+        return Map.of("", migrateVolumeTo);
+    }
+
     @Test
     public void executeTestHostIsNotNullMigratedVMIsNullThrowsServerApiException() throws ManagementServerException, ResourceUnavailableException, VirtualMachineMigrationException {
         ReflectionTestUtils.setField(cmdSpy, "hostId", hostId);
-        ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
+        ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", getMockedMigrateVolumeToApiCmdParam());
 
         Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
         Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Running);
-        Mockito.when(resourceServiceMock.getHost(Mockito.anyLong())).thenReturn(hostMock);
-        Mockito.when(userVmServiceMock.migrateVirtualMachineWithVolume(virtualMachineUuid, hostMock, migrateVolumeTo)).thenReturn(null);
+        Mockito.when(resourceServiceMock.getHost(hostId)).thenReturn(hostMock);
+        Mockito.when(userVmServiceMock.migrateVirtualMachineWithVolume(Mockito.anyLong(), Mockito.any(), Mockito.anyMap())).thenReturn(null);
 
         try {
             cmdSpy.execute();
@@ -176,11 +189,11 @@
     @Test
     public void executeTestHostIsNullMigratedVMIsNullThrowsServerApiException() {
         ReflectionTestUtils.setField(cmdSpy, "hostId", null);
-        ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
+        ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", getMockedMigrateVolumeToApiCmdParam());
 
         Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
         Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Stopped);
-        Mockito.when(userVmServiceMock.vmStorageMigration(virtualMachineUuid, migrateVolumeTo)).thenReturn(null);
+        Mockito.when(userVmServiceMock.vmStorageMigration(Mockito.anyLong(), Mockito.anyMap())).thenReturn(null);
 
         try {
             cmdSpy.execute();
@@ -194,11 +207,11 @@
     @Test
     public void executeTestSystemVMMigratedWithSuccess() {
         ReflectionTestUtils.setField(cmdSpy, "hostId", null);
-        ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
+        ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", getMockedMigrateVolumeToApiCmdParam());
 
         Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
         Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Stopped);
-        Mockito.when(userVmServiceMock.vmStorageMigration(virtualMachineUuid, migrateVolumeTo)).thenReturn(virtualMachineMock);
+        Mockito.when(userVmServiceMock.vmStorageMigration(Mockito.anyLong(), Mockito.anyMap())).thenReturn(virtualMachineMock);
         Mockito.when(virtualMachineMock.getType()).thenReturn(VirtualMachine.Type.ConsoleProxy);
         Mockito.when(responseGeneratorMock.createSystemVmResponse(virtualMachineMock)).thenReturn(systemVmResponse);
 
@@ -211,11 +224,11 @@
     public void executeTestUserVMMigratedWithSuccess() {
         UserVm userVmMock = Mockito.mock(UserVm.class);
         ReflectionTestUtils.setField(cmdSpy, "hostId", null);
-        ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
+        ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", getMockedMigrateVolumeToApiCmdParam());
 
         Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(userVmMock);
         Mockito.when(userVmMock.getState()).thenReturn(VirtualMachine.State.Stopped);
-        Mockito.when(userVmServiceMock.vmStorageMigration(virtualMachineUuid, migrateVolumeTo)).thenReturn(userVmMock);
+        Mockito.when(userVmServiceMock.vmStorageMigration(Mockito.anyLong(), Mockito.anyMap())).thenReturn(userVmMock);
         Mockito.when(userVmMock.getType()).thenReturn(VirtualMachine.Type.User);
         Mockito.when(responseGeneratorMock.createUserVmResponse(ResponseObject.ResponseView.Full, "virtualmachine", userVmMock)).thenReturn(List.of(userVmResponse));
 
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmdTest.java
index 18a2882..16b716d 100644
--- a/api/src/test/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmdTest.java
+++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmdTest.java
@@ -25,6 +25,8 @@
 
 import org.apache.cloudstack.api.ApiCmdTestUtil;
 import org.apache.cloudstack.api.ApiConstants;
+import org.springframework.test.util.ReflectionTestUtils;
+
 
 public class CreateVPCOfferingCmdTest {
 
@@ -61,4 +63,12 @@
         Assert.assertNull(cmd.getServiceProviders());
     }
 
+    @Test
+    public void testCreateVPCOfferingWithEmptyDisplayText() {
+        CreateVPCOfferingCmd cmd = new CreateVPCOfferingCmd();
+        String netName = "net-vpc";
+        ReflectionTestUtils.setField(cmd,"vpcOfferingName", netName);
+        Assert.assertEquals(cmd.getDisplayText(), netName);
+    }
+
 }
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/test/CreateRoleCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/test/CreateRoleCmdTest.java
index a910de7..4b9d4fd 100644
--- a/api/src/test/java/org/apache/cloudstack/api/command/test/CreateRoleCmdTest.java
+++ b/api/src/test/java/org/apache/cloudstack/api/command/test/CreateRoleCmdTest.java
@@ -54,7 +54,7 @@
         when(role.getDescription()).thenReturn("User test");
         when(role.getName()).thenReturn("testuser");
         when(role.getRoleType()).thenReturn(RoleType.User);
-        when(roleService.createRole(createRoleCmd.getRoleName(), createRoleCmd.getRoleType(), createRoleCmd.getRoleDescription())).thenReturn(role);
+        when(roleService.createRole(createRoleCmd.getRoleName(), createRoleCmd.getRoleType(), createRoleCmd.getRoleDescription(), true)).thenReturn(role);
         createRoleCmd.execute();
         RoleResponse response = (RoleResponse) createRoleCmd.getResponseObject();
         Assert.assertEquals((String) ReflectionTestUtils.getField(response, "roleName"), role.getName());
@@ -71,7 +71,7 @@
         when(newRole.getDescription()).thenReturn("User test");
         when(newRole.getName()).thenReturn("testuser");
         when(newRole.getRoleType()).thenReturn(RoleType.User);
-        when(roleService.createRole(createRoleCmd.getRoleName(), role, createRoleCmd.getRoleDescription())).thenReturn(newRole);
+        when(roleService.createRole(createRoleCmd.getRoleName(), role, createRoleCmd.getRoleDescription(), true)).thenReturn(newRole);
         createRoleCmd.execute();
         RoleResponse response = (RoleResponse) createRoleCmd.getResponseObject();
         Assert.assertEquals((String) ReflectionTestUtils.getField(response, "roleName"), newRole.getName());
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/test/ImportRoleCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/test/ImportRoleCmdTest.java
index 8de0148..6299c1e 100644
--- a/api/src/test/java/org/apache/cloudstack/api/command/test/ImportRoleCmdTest.java
+++ b/api/src/test/java/org/apache/cloudstack/api/command/test/ImportRoleCmdTest.java
@@ -93,7 +93,7 @@
         when(role.getDescription()).thenReturn("test user imported");
         when(role.getName()).thenReturn("Test User");
         when(role.getRoleType()).thenReturn(RoleType.User);
-        when(roleService.importRole(anyString(),any(), anyString(), any(), anyBoolean())).thenReturn(role);
+        when(roleService.importRole(anyString(), any(), anyString(), any(), anyBoolean(), anyBoolean())).thenReturn(role);
 
         importRoleCmd.execute();
         RoleResponse response = (RoleResponse) importRoleCmd.getResponseObject();
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/test/UpdateRoleCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/test/UpdateRoleCmdTest.java
index d298def..84b9152 100644
--- a/api/src/test/java/org/apache/cloudstack/api/command/test/UpdateRoleCmdTest.java
+++ b/api/src/test/java/org/apache/cloudstack/api/command/test/UpdateRoleCmdTest.java
@@ -58,7 +58,7 @@
         when(role.getDescription()).thenReturn("Default user");
         when(role.getName()).thenReturn("User");
         when(role.getRoleType()).thenReturn(RoleType.User);
-        when(roleService.updateRole(role,updateRoleCmd.getRoleName(),updateRoleCmd.getRoleType(),updateRoleCmd.getRoleDescription())).thenReturn(role);
+        when(roleService.updateRole(role, updateRoleCmd.getRoleName(), updateRoleCmd.getRoleType(), updateRoleCmd.getRoleDescription(), updateRoleCmd.isPublicRole())).thenReturn(role);
         when(role.getId()).thenReturn(1L);
         when(role.getDescription()).thenReturn("Description Initial");
         when(role.getName()).thenReturn("User");
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmdTest.java
new file mode 100644
index 0000000..55a41c6
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmdTest.java
@@ -0,0 +1,40 @@
+// 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.command.user.iso;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RegisterIsoCmdTest  {
+
+    @InjectMocks
+    private RegisterIsoCmd registerIsoCmd = new RegisterIsoCmd();
+
+    @Test
+    public void testGetDisplayTextWhenEmpty() {
+        String netName = "net-iso";
+        ReflectionTestUtils.setField(registerIsoCmd, "isoName", netName);
+        Assert.assertEquals(registerIsoCmd.getDisplayText(), netName);
+    }
+
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/project/CreateProjectCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/project/CreateProjectCmdTest.java
new file mode 100644
index 0000000..ee31931
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/user/project/CreateProjectCmdTest.java
@@ -0,0 +1,40 @@
+// 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.command.user.project;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CreateProjectCmdTest  {
+
+    @InjectMocks
+    private CreateProjectCmd createProjectCmd = new CreateProjectCmd();
+
+    @Test
+    public void testGetDisplayTextWhenEmpty() {
+        String netName = "net-project";
+        ReflectionTestUtils.setField(createProjectCmd , "name", netName);
+        Assert.assertEquals(createProjectCmd.getDisplayText(), netName);
+    }
+
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmdTest.java
index dfd3b6e..0c31e50 100644
--- a/api/src/test/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmdTest.java
+++ b/api/src/test/java/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmdTest.java
@@ -30,6 +30,8 @@
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
 import java.util.ArrayList;
 
 @RunWith(MockitoJUnitRunner.class)
@@ -139,4 +141,12 @@
         testIsDeployAsIsBase(Hypervisor.HypervisorType.XenServer, true, false);
         testIsDeployAsIsBase(Hypervisor.HypervisorType.Any, true, false);
     }
+
+    @Test
+    public void testGetDisplayTextWhenEmpty() {
+        registerTemplateCmd = new RegisterTemplateCmd();
+        String netName = "net-template";
+        ReflectionTestUtils.setField(registerTemplateCmd , "templateName", netName);
+        Assert.assertEquals(registerTemplateCmd.getDisplayText(), netName);
+    }
 }
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmdTest.java
new file mode 100644
index 0000000..2fdef2a
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmdTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.command.user.vm;
+
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.utils.db.EntityManager;
+import com.cloud.vm.VirtualMachine;
+import org.apache.cloudstack.api.response.VMScheduleResponse;
+import org.apache.cloudstack.vm.schedule.VMScheduleManager;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.security.InvalidParameterException;
+
+public class CreateVMScheduleCmdTest {
+    @Mock
+    public VMScheduleManager vmScheduleManager;
+    @Mock
+    public EntityManager entityManager;
+    @InjectMocks
+    private CreateVMScheduleCmd createVMScheduleCmd = new CreateVMScheduleCmd();
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    /**
+     * given: "We have a VMScheduleManager and CreateVMScheduleCmd"
+     * when: "CreateVMScheduleCmd is executed successfully"
+     * then: "a VMSchedule response is created"
+     */
+    @Test
+    public void testSuccessfulExecution() {
+        VMScheduleResponse vmScheduleResponse = Mockito.mock(VMScheduleResponse.class);
+        Mockito.when(vmScheduleManager.createSchedule(createVMScheduleCmd)).thenReturn(vmScheduleResponse);
+        createVMScheduleCmd.execute();
+        Assert.assertEquals(vmScheduleResponse, createVMScheduleCmd.getResponseObject());
+    }
+
+    /**
+     * given: "We have a VMScheduleManager and CreateVMScheduleCmd"
+     * when: "CreateVMScheduleCmd is executed with an invalid parameter"
+     * then: "an InvalidParameterException is thrown"
+     */
+    @Test(expected = InvalidParameterException.class)
+    public void testInvalidParameterException() {
+        Mockito.when(vmScheduleManager.createSchedule(createVMScheduleCmd)).thenThrow(InvalidParameterException.class);
+        createVMScheduleCmd.execute();
+    }
+
+    /**
+     * given: "We have an EntityManager and CreateVMScheduleCmd"
+     * when: "CreateVMScheduleCmd.getEntityOwnerId is executed for a VM which does exist"
+     * then: "owner of that VM is returned"
+     */
+    @Test
+    public void testSuccessfulGetEntityOwnerId() {
+        VirtualMachine vm = Mockito.mock(VirtualMachine.class);
+        Mockito.when(entityManager.findById(VirtualMachine.class, createVMScheduleCmd.getVmId())).thenReturn(vm);
+        long ownerId = createVMScheduleCmd.getEntityOwnerId();
+        Assert.assertEquals(vm.getAccountId(), ownerId);
+    }
+
+    /**
+     * given: "We have an EntityManager and CreateVMScheduleCmd"
+     * when: "CreateVMScheduleCmd.getEntityOwnerId is executed for a VM which doesn't exist"
+     * then: "an InvalidParameterException is thrown"
+     */
+    @Test(expected = InvalidParameterValueException.class)
+    public void testFailureGetEntityOwnerId() {
+        Mockito.when(entityManager.findById(VirtualMachine.class, createVMScheduleCmd.getVmId())).thenReturn(null);
+        long ownerId = createVMScheduleCmd.getEntityOwnerId();
+    }
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmdTest.java
new file mode 100644
index 0000000..6adfc2b
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmdTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.command.user.vm;
+
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.utils.db.EntityManager;
+import com.cloud.vm.VirtualMachine;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.vm.schedule.VMSchedule;
+import org.apache.cloudstack.vm.schedule.VMScheduleManager;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.security.InvalidParameterException;
+
+public class DeleteVMScheduleCmdTest {
+    @Mock
+    public VMScheduleManager vmScheduleManager;
+    @Mock
+    public EntityManager entityManager;
+
+    @InjectMocks
+    private DeleteVMScheduleCmd deleteVMScheduleCmd = new DeleteVMScheduleCmd();
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    /**
+     * given: "We have a VMScheduleManager and DeleteVMScheduleCmd"
+     * when: "VMScheduleManager.removeSchedule() is executed returning 1 row"
+     * then: "a Success response is created"
+     */
+    @Test
+    public void testSuccessfulExecution() {
+        final SuccessResponse response = new SuccessResponse();
+        response.setResponseName(deleteVMScheduleCmd.getCommandName());
+        response.setObjectName(VMSchedule.class.getSimpleName().toLowerCase());
+
+        Mockito.when(vmScheduleManager.removeSchedule(deleteVMScheduleCmd)).thenReturn(1L);
+        deleteVMScheduleCmd.execute();
+        SuccessResponse actualResponse = (SuccessResponse) deleteVMScheduleCmd.getResponseObject();
+        Assert.assertEquals(response.getResponseName(), actualResponse.getResponseName());
+        Assert.assertEquals(response.getObjectName(), actualResponse.getObjectName());
+    }
+
+    /**
+     * given: "We have a VMScheduleManager and DeleteVMScheduleCmd"
+     * when: "VMScheduleManager.removeSchedule() is executed returning 0 row"
+     * then: "ServerApiException is thrown"
+     */
+    @Test(expected = ServerApiException.class)
+    public void testServerApiException() {
+        Mockito.when(vmScheduleManager.removeSchedule(deleteVMScheduleCmd)).thenReturn(0L);
+        deleteVMScheduleCmd.execute();
+    }
+
+    /**
+     * given: "We have a VMScheduleManager and DeleteVMScheduleCmd"
+     * when: "DeleteVMScheduleCmd is executed with an invalid parameter"
+     * then: "an InvalidParameterException is thrown"
+     */
+    @Test(expected = InvalidParameterException.class)
+    public void testInvalidParameterException() {
+        Mockito.when(vmScheduleManager.removeSchedule(deleteVMScheduleCmd)).thenThrow(InvalidParameterException.class);
+        deleteVMScheduleCmd.execute();
+    }
+
+    /**
+     * given: "We have an EntityManager and DeleteVMScheduleCmd"
+     * when: "DeleteVMScheduleCmd.getEntityOwnerId is executed for a VM which does exist"
+     * then: "owner of that VM is returned"
+     */
+    @Test
+    public void testSuccessfulGetEntityOwnerId() {
+        VirtualMachine vm = Mockito.mock(VirtualMachine.class);
+        Mockito.when(entityManager.findById(VirtualMachine.class, deleteVMScheduleCmd.getVmId())).thenReturn(vm);
+        long ownerId = deleteVMScheduleCmd.getEntityOwnerId();
+        Assert.assertEquals(vm.getAccountId(), ownerId);
+    }
+
+    /**
+     * given: "We have an EntityManager and DeleteVMScheduleCmd"
+     * when: "DeleteVMScheduleCmd.getEntityOwnerId is executed for a VM which doesn't exist"
+     * then: "an InvalidParameterException is thrown"
+     */
+    @Test(expected = InvalidParameterValueException.class)
+    public void testFailureGetEntityOwnerId() {
+        Mockito.when(entityManager.findById(VirtualMachine.class, deleteVMScheduleCmd.getVmId())).thenReturn(null);
+        long ownerId = deleteVMScheduleCmd.getEntityOwnerId();
+    }
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmdTest.java
new file mode 100644
index 0000000..18657b4
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmdTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.command.user.vm;
+
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.VMScheduleResponse;
+import org.apache.cloudstack.vm.schedule.VMScheduleManager;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.security.InvalidParameterException;
+import java.util.ArrayList;
+import java.util.Collections;
+
+public class ListVMScheduleCmdTest {
+    @Mock
+    public VMScheduleManager vmScheduleManager;
+    @InjectMocks
+    private ListVMScheduleCmd listVMScheduleCmd = new ListVMScheduleCmd();
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    /**
+     * given: "We have a VMScheduleManager with 0 schedules and ListVMScheduleCmd"
+     * when: "ListVMScheduleCmd is executed"
+     * then: "a list of size 0 is returned"
+     */
+    @Test
+    public void testEmptyResponse() {
+        ListResponse<VMScheduleResponse> response = new ListResponse<VMScheduleResponse>();
+        response.setResponses(new ArrayList<VMScheduleResponse>());
+        Mockito.when(vmScheduleManager.listSchedule(listVMScheduleCmd)).thenReturn(response);
+        listVMScheduleCmd.execute();
+        ListResponse<VMScheduleResponse> actualResponseObject = (ListResponse<VMScheduleResponse>) listVMScheduleCmd.getResponseObject();
+        Assert.assertEquals(response, actualResponseObject);
+        Assert.assertEquals(0L, actualResponseObject.getResponses().size());
+    }
+
+    /**
+     * given: "We have a VMScheduleManager with 1 schedule and ListVMScheduleCmd"
+     * when: "ListVMScheduleCmd is executed"
+     * then: "a list of size 1 is returned"
+     */
+    @Test
+    public void testNonEmptyResponse() {
+        ListResponse<VMScheduleResponse> listResponse = new ListResponse<VMScheduleResponse>();
+        VMScheduleResponse response = Mockito.mock(VMScheduleResponse.class);
+        listResponse.setResponses(Collections.singletonList(response));
+        Mockito.when(vmScheduleManager.listSchedule(listVMScheduleCmd)).thenReturn(listResponse);
+        listVMScheduleCmd.execute();
+        ListResponse<VMScheduleResponse> actualResponseObject = (ListResponse<VMScheduleResponse>) listVMScheduleCmd.getResponseObject();
+        Assert.assertEquals(listResponse, actualResponseObject);
+        Assert.assertEquals(1L, actualResponseObject.getResponses().size());
+        Assert.assertEquals(response, actualResponseObject.getResponses().get(0));
+    }
+
+    /**
+     * given: "We have a VMScheduleManager and ListVMScheduleCmd"
+     * when: "ListVMScheduleCmd is executed with an invalid parameter"
+     * then: "an InvalidParameterException is thrown"
+     */
+    @Test(expected = InvalidParameterException.class)
+    public void testInvalidParameterException() {
+        Mockito.when(vmScheduleManager.listSchedule(listVMScheduleCmd)).thenThrow(InvalidParameterException.class);
+        listVMScheduleCmd.execute();
+        ListResponse<VMScheduleResponse> actualResponseObject = (ListResponse<VMScheduleResponse>) listVMScheduleCmd.getResponseObject();
+    }
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmdTest.java
new file mode 100644
index 0000000..044685b
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmdTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.command.user.vm;
+
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.utils.db.EntityManager;
+import com.cloud.vm.VirtualMachine;
+import org.apache.cloudstack.api.response.VMScheduleResponse;
+import org.apache.cloudstack.vm.schedule.VMSchedule;
+import org.apache.cloudstack.vm.schedule.VMScheduleManager;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.security.InvalidParameterException;
+
+public class UpdateVMScheduleCmdTest {
+    @Mock
+    public VMScheduleManager vmScheduleManager;
+    @Mock
+    public EntityManager entityManager;
+    @InjectMocks
+    private UpdateVMScheduleCmd updateVMScheduleCmd = new UpdateVMScheduleCmd();
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    /**
+     * given: "We have a VMScheduleManager and UpdateVMScheduleCmd"
+     * when: "UpdateVMScheduleCmd is executed successfully"
+     * then: "a VMSchedule response is created"
+     */
+    @Test
+    public void testSuccessfulExecution() {
+        VMScheduleResponse vmScheduleResponse = Mockito.mock(VMScheduleResponse.class);
+        Mockito.when(vmScheduleManager.updateSchedule(updateVMScheduleCmd)).thenReturn(vmScheduleResponse);
+        updateVMScheduleCmd.execute();
+        Assert.assertEquals(vmScheduleResponse, updateVMScheduleCmd.getResponseObject());
+    }
+
+    /**
+     * given: "We have a VMScheduleManager and UpdateVMScheduleCmd"
+     * when: "UpdateVMScheduleCmd is executed with an invalid parameter"
+     * then: "an InvalidParameterException is thrown"
+     */
+    @Test(expected = InvalidParameterException.class)
+    public void testInvalidParameterException() {
+        Mockito.when(vmScheduleManager.updateSchedule(updateVMScheduleCmd)).thenThrow(InvalidParameterException.class);
+        updateVMScheduleCmd.execute();
+    }
+
+    /**
+     * given: "We have an EntityManager and UpdateVMScheduleCmd"
+     * when: "UpdateVMScheduleCmd.getEntityOwnerId is executed for a VM which does exist"
+     * then: "owner of that VM is returned"
+     */
+    @Test
+    public void testSuccessfulGetEntityOwnerId() {
+        VMSchedule vmSchedule = Mockito.mock(VMSchedule.class);
+        VirtualMachine vm = Mockito.mock(VirtualMachine.class);
+
+        Mockito.when(entityManager.findById(VMSchedule.class, updateVMScheduleCmd.getId())).thenReturn(vmSchedule);
+        Mockito.when(entityManager.findById(VirtualMachine.class, vmSchedule.getVmId())).thenReturn(vm);
+
+        long ownerId = updateVMScheduleCmd.getEntityOwnerId();
+        Assert.assertEquals(vm.getAccountId(), ownerId);
+    }
+
+    /**
+     * given: "We have an EntityManager and UpdateVMScheduleCmd"
+     * when: "UpdateVMScheduleCmd.getEntityOwnerId is executed for a VM Schedule which doesn't exist"
+     * then: "an InvalidParameterException is thrown"
+     */
+    @Test(expected = InvalidParameterValueException.class)
+    public void testFailureGetEntityOwnerId() {
+        VMSchedule vmSchedule = Mockito.mock(VMSchedule.class);
+        Mockito.when(entityManager.findById(VMSchedule.class, updateVMScheduleCmd.getId())).thenReturn(null);
+        long ownerId = updateVMScheduleCmd.getEntityOwnerId();
+    }
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmdTest.java
index 92ac005..17c8e23 100644
--- a/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmdTest.java
+++ b/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmdTest.java
@@ -133,6 +133,12 @@
         Assert.assertTrue(cmd.getDisplayVpc());
     }
 
+    public void testGetDisplayTextWhenEmpty() {
+        String netName = "net-vpc";
+        ReflectionTestUtils.setField(cmd, "vpcName", netName);
+        Assert.assertEquals(cmd.getDisplayText(), netName);
+    }
+
     public void testCreate() throws ResourceAllocationException {
         Vpc vpc = Mockito.mock(Vpc.class);
         ReflectionTestUtils.setField(cmd, "zoneId", 1L);
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmdTest.java
index 3f27f4c..d174d36 100644
--- a/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmdTest.java
+++ b/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/UpdateVPCCmdTest.java
@@ -17,6 +17,8 @@
 
 package org.apache.cloudstack.api.command.user.vpc;
 
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.network.vpc.Vpc;
 import com.cloud.network.vpc.VpcService;
 import junit.framework.TestCase;
@@ -72,7 +74,7 @@
         Assert.assertEquals(cmd.getPublicMtu(), publicMtu);
     }
 
-    public void testExecute() {
+    public void testExecute() throws ResourceUnavailableException, InsufficientCapacityException {
         ReflectionTestUtils.setField(cmd, "id", 1L);
         ReflectionTestUtils.setField(cmd, "vpcName", "updatedVpcName");
         ReflectionTestUtils.setField(cmd, "displayText", "Updated VPC Name");
@@ -85,10 +87,10 @@
         responseGenerator = Mockito.mock(ResponseGenerator.class);
         cmd._responseGenerator = responseGenerator;
         Mockito.when(_vpcService.updateVpc(Mockito.anyLong(), Mockito.anyString(), Mockito.anyString(),
-                Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyInt())).thenReturn(vpc);
+                Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyInt(), Mockito.anyString())).thenReturn(vpc);
         Mockito.when(responseGenerator.createVpcResponse(ResponseObject.ResponseView.Full, vpc)).thenReturn(response);
         Mockito.verify(_vpcService, Mockito.times(0)).updateVpc(Mockito.anyLong(), Mockito.anyString(), Mockito.anyString(),
-                Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyInt());
+                Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyInt(), Mockito.anyString());
 
     }
 }
diff --git a/client/pom.xml b/client/pom.xml
index f7e2de6..cbe45d8 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
     </parent>
     <repositories>
         <repository>
@@ -354,6 +354,16 @@
         </dependency>
         <dependency>
             <groupId>org.apache.cloudstack</groupId>
+            <artifactId>cloud-engine-userdata-cloud-init</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cloudstack</groupId>
+            <artifactId>cloud-engine-userdata</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cloudstack</groupId>
             <artifactId>cloud-mom-rabbitmq</artifactId>
             <version>${project.version}</version>
         </dependency>
@@ -552,6 +562,11 @@
             <artifactId>cloud-plugin-integrations-kubernetes-service</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+           <groupId>org.apache.cloudstack</groupId>
+           <artifactId>cloud-plugin-shutdown</artifactId>
+           <version>${project.version}</version>
+       </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/client/src/main/java/org/apache/cloudstack/ServerDaemon.java b/client/src/main/java/org/apache/cloudstack/ServerDaemon.java
index 08f8566..63cdc45 100644
--- a/client/src/main/java/org/apache/cloudstack/ServerDaemon.java
+++ b/client/src/main/java/org/apache/cloudstack/ServerDaemon.java
@@ -45,6 +45,7 @@
 import org.eclipse.jetty.server.handler.RequestLogHandler;
 import org.eclipse.jetty.server.handler.gzip.GzipHandler;
 import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.util.ssl.KeyStoreScanner;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.util.thread.QueuedThreadPool;
 import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
@@ -241,6 +242,14 @@
             sslConnector.setPort(httpsPort);
             sslConnector.setHost(bindInterface);
             server.addConnector(sslConnector);
+
+            // add scanner to auto-reload certs
+            try {
+                KeyStoreScanner scanner = new KeyStoreScanner(sslContextFactory);
+                server.addBean(scanner);
+            } catch (Exception ex) {
+                LOG.error("failed to set up keystore scanner, manual refresh of certificates will be required", ex);
+            }
         }
     }
 
diff --git a/core/pom.xml b/core/pom.xml
index 1970a40..339439a 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
     </parent>
     <dependencies>
         <dependency>
diff --git a/core/src/main/java/com/cloud/agent/api/CheckGuestOsMappingAnswer.java b/core/src/main/java/com/cloud/agent/api/CheckGuestOsMappingAnswer.java
new file mode 100644
index 0000000..53cfded
--- /dev/null
+++ b/core/src/main/java/com/cloud/agent/api/CheckGuestOsMappingAnswer.java
@@ -0,0 +1,38 @@
+//
+// 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.agent.api;
+
+public class CheckGuestOsMappingAnswer extends Answer {
+
+    protected CheckGuestOsMappingAnswer() {
+    }
+
+    public CheckGuestOsMappingAnswer(CheckGuestOsMappingCommand cmd) {
+        super(cmd, true, null);
+    }
+
+    public CheckGuestOsMappingAnswer(CheckGuestOsMappingCommand cmd, String details) {
+        super(cmd, false, details);
+    }
+
+    public CheckGuestOsMappingAnswer(CheckGuestOsMappingCommand cmd, Throwable th) {
+        super(cmd, false, th.getMessage());
+    }
+}
diff --git a/core/src/main/java/com/cloud/agent/api/CheckGuestOsMappingCommand.java b/core/src/main/java/com/cloud/agent/api/CheckGuestOsMappingCommand.java
new file mode 100644
index 0000000..11efd80
--- /dev/null
+++ b/core/src/main/java/com/cloud/agent/api/CheckGuestOsMappingCommand.java
@@ -0,0 +1,65 @@
+//
+// 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.agent.api;
+
+import java.util.Objects;
+
+public class CheckGuestOsMappingCommand extends Command {
+    String guestOsName;
+    String guestOsHypervisorMappingName;
+    String hypervisorVersion;
+
+    public CheckGuestOsMappingCommand() {
+        super();
+    }
+
+    public CheckGuestOsMappingCommand(String guestOsName, String guestOsHypervisorMappingName, String hypervisorVersion) {
+        super();
+        this.guestOsName = guestOsName;
+        this.guestOsHypervisorMappingName = guestOsHypervisorMappingName;
+        this.hypervisorVersion = hypervisorVersion;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return false;
+    }
+
+    public String getGuestOsName() {
+        return guestOsName;
+    }
+
+    public String getGuestOsHypervisorMappingName() {
+        return guestOsHypervisorMappingName;
+    }
+
+    public String getHypervisorVersion() {
+        return hypervisorVersion;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        if (!super.equals(o)) return false;
+        CheckGuestOsMappingCommand that = (CheckGuestOsMappingCommand) o;
+        return Objects.equals(guestOsName, that.guestOsName) && Objects.equals(guestOsHypervisorMappingName, that.guestOsHypervisorMappingName) && Objects.equals(hypervisorVersion, that.hypervisorVersion);
+    }
+}
diff --git a/core/src/main/java/com/cloud/agent/api/GetHypervisorGuestOsNamesAnswer.java b/core/src/main/java/com/cloud/agent/api/GetHypervisorGuestOsNamesAnswer.java
new file mode 100644
index 0000000..d59d66c
--- /dev/null
+++ b/core/src/main/java/com/cloud/agent/api/GetHypervisorGuestOsNamesAnswer.java
@@ -0,0 +1,58 @@
+//
+// 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.agent.api;
+
+import java.util.List;
+import java.util.Objects;
+
+import com.cloud.utils.Pair;
+
+public class GetHypervisorGuestOsNamesAnswer extends Answer {
+    private List<Pair<String, String>> hypervisorGuestOsNames;
+
+    protected GetHypervisorGuestOsNamesAnswer() {
+    }
+
+    public GetHypervisorGuestOsNamesAnswer(GetHypervisorGuestOsNamesCommand cmd, List<Pair<String, String>> hypervisorGuestOsNames) {
+        super(cmd, true, null);
+        this.hypervisorGuestOsNames = hypervisorGuestOsNames;
+    }
+
+    public GetHypervisorGuestOsNamesAnswer(GetHypervisorGuestOsNamesCommand cmd, String details) {
+        super(cmd, false, details);
+    }
+
+    public GetHypervisorGuestOsNamesAnswer(GetHypervisorGuestOsNamesCommand cmd, Throwable th) {
+        super(cmd, false, th.getMessage());
+    }
+
+    public List<Pair<String, String>> getHypervisorGuestOsNames() {
+        return hypervisorGuestOsNames;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        if (!super.equals(o)) return false;
+        GetHypervisorGuestOsNamesAnswer that = (GetHypervisorGuestOsNamesAnswer) o;
+        return Objects.equals(hypervisorGuestOsNames, that.hypervisorGuestOsNames);
+    }
+}
diff --git a/core/src/main/java/com/cloud/agent/api/GetHypervisorGuestOsNamesCommand.java b/core/src/main/java/com/cloud/agent/api/GetHypervisorGuestOsNamesCommand.java
new file mode 100644
index 0000000..b31ff0e
--- /dev/null
+++ b/core/src/main/java/com/cloud/agent/api/GetHypervisorGuestOsNamesCommand.java
@@ -0,0 +1,53 @@
+//
+// 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.agent.api;
+
+import java.util.Objects;
+
+public class GetHypervisorGuestOsNamesCommand extends Command {
+    String keyword;
+
+    public GetHypervisorGuestOsNamesCommand() {
+        super();
+    }
+
+    public GetHypervisorGuestOsNamesCommand(String keyword) {
+        super();
+        this.keyword = keyword;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return false;
+    }
+
+    public String getKeyword() {
+        return keyword;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        if (!super.equals(o)) return false;
+        GetHypervisorGuestOsNamesCommand that = (GetHypervisorGuestOsNamesCommand) o;
+        return Objects.equals(keyword, that.keyword);
+    }
+}
diff --git a/core/src/main/java/com/cloud/agent/api/PingRoutingCommand.java b/core/src/main/java/com/cloud/agent/api/PingRoutingCommand.java
index d7733ee..ce529ad 100644
--- a/core/src/main/java/com/cloud/agent/api/PingRoutingCommand.java
+++ b/core/src/main/java/com/cloud/agent/api/PingRoutingCommand.java
@@ -29,6 +29,7 @@
 
     boolean _gatewayAccessible = true;
     boolean _vnetAccessible = true;
+    private Boolean hostHealthCheckResult;
 
     protected PingRoutingCommand() {
     }
@@ -57,4 +58,12 @@
     public void setVnetAccessible(boolean vnetAccessible) {
         _vnetAccessible = vnetAccessible;
     }
+
+    public Boolean getHostHealthCheckResult() {
+        return hostHealthCheckResult;
+    }
+
+    public void setHostHealthCheckResult(Boolean hostHealthCheckResult) {
+        this.hostHealthCheckResult = hostHealthCheckResult;
+    }
 }
diff --git a/core/src/main/java/com/cloud/agent/api/StartupRoutingCommand.java b/core/src/main/java/com/cloud/agent/api/StartupRoutingCommand.java
index b459f88..b4f9d20 100644
--- a/core/src/main/java/com/cloud/agent/api/StartupRoutingCommand.java
+++ b/core/src/main/java/com/cloud/agent/api/StartupRoutingCommand.java
@@ -44,6 +44,7 @@
     List<String> hostTags = new ArrayList<String>();
     String hypervisorVersion;
     HashMap<String, HashMap<String, VgpuTypesInfo>> groupDetails = new HashMap<String, HashMap<String, VgpuTypesInfo>>();
+    private Boolean hostHealthCheckResult;
 
     public StartupRoutingCommand() {
         super(Host.Type.Routing);
@@ -188,4 +189,12 @@
     public void setSupportsClonedVolumes(boolean supportsClonedVolumes) {
         this.supportsClonedVolumes = supportsClonedVolumes;
     }
+
+    public Boolean getHostHealthCheckResult() {
+        return hostHealthCheckResult;
+    }
+
+    public void setHostHealthCheckResult(Boolean hostHealthCheckResult) {
+        this.hostHealthCheckResult = hostHealthCheckResult;
+    }
 }
diff --git a/core/src/main/resources/META-INF/cloudstack/allocator/spring-core-allocator-context.xml b/core/src/main/resources/META-INF/cloudstack/allocator/spring-core-allocator-context.xml
index 0e00fda..a0d1b4c 100644
--- a/core/src/main/resources/META-INF/cloudstack/allocator/spring-core-allocator-context.xml
+++ b/core/src/main/resources/META-INF/cloudstack/allocator/spring-core-allocator-context.xml
@@ -31,4 +31,4 @@
 
     <bean id="usageEventUtils" class="com.cloud.event.UsageEventUtils" />
 
-</beans>
\ No newline at end of file
+</beans>
diff --git a/core/src/main/resources/META-INF/cloudstack/allocator/spring-core-lifecycle-allocator-context-inheritable.xml b/core/src/main/resources/META-INF/cloudstack/allocator/spring-core-lifecycle-allocator-context-inheritable.xml
index cd98a63..ec3bb63 100644
--- a/core/src/main/resources/META-INF/cloudstack/allocator/spring-core-lifecycle-allocator-context-inheritable.xml
+++ b/core/src/main/resources/META-INF/cloudstack/allocator/spring-core-lifecycle-allocator-context-inheritable.xml
@@ -41,4 +41,4 @@
             value="com.cloud.consoleproxy.ConsoleProxyAllocator" />
     </bean>
 
-</beans>
\ No newline at end of file
+</beans>
diff --git a/core/src/main/resources/META-INF/cloudstack/cloudstack/direct-download/module.properties b/core/src/main/resources/META-INF/cloudstack/cloudstack/direct-download/module.properties
index 63e1a8b..cdd8e2e 100644
--- a/core/src/main/resources/META-INF/cloudstack/cloudstack/direct-download/module.properties
+++ b/core/src/main/resources/META-INF/cloudstack/cloudstack/direct-download/module.properties
@@ -18,4 +18,4 @@
 #
 
 name=direct-download
-parent=backend
\ No newline at end of file
+parent=backend
diff --git a/core/src/main/resources/META-INF/cloudstack/core/spring-core-lifecycle-core-context-inheritable.xml b/core/src/main/resources/META-INF/cloudstack/core/spring-core-lifecycle-core-context-inheritable.xml
index b754d6b..71d1656 100644
--- a/core/src/main/resources/META-INF/cloudstack/core/spring-core-lifecycle-core-context-inheritable.xml
+++ b/core/src/main/resources/META-INF/cloudstack/core/spring-core-lifecycle-core-context-inheritable.xml
@@ -39,5 +39,10 @@
         <property name="typeClass"
             value="com.cloud.utils.component.PluggableService" />
     </bean>
-    
-</beans>
\ No newline at end of file
+
+    <bean class="org.apache.cloudstack.spring.lifecycle.registry.RegistryLifecycle">
+        <property name="registry" ref="userDataProvidersRegistry" />
+        <property name="typeClass" value="org.apache.cloudstack.userdata.UserDataProvider" />
+    </bean>
+
+</beans>
diff --git a/core/src/main/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml b/core/src/main/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml
index cb55913..a7f384c 100644
--- a/core/src/main/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml
+++ b/core/src/main/resources/META-INF/cloudstack/core/spring-core-registry-core-context.xml
@@ -342,4 +342,8 @@
     <bean id="kubernetesClusterHelperRegistry"
           class="org.apache.cloudstack.spring.lifecycle.registry.ExtensionRegistry">
     </bean>
+
+    <bean id="userDataProvidersRegistry"
+          class="org.apache.cloudstack.spring.lifecycle.registry.ExtensionRegistry">
+    </bean>
 </beans>
diff --git a/core/src/main/resources/META-INF/cloudstack/kubernetes/module.properties b/core/src/main/resources/META-INF/cloudstack/kubernetes/module.properties
index ea954a9..09f265b 100644
--- a/core/src/main/resources/META-INF/cloudstack/kubernetes/module.properties
+++ b/core/src/main/resources/META-INF/cloudstack/kubernetes/module.properties
@@ -18,4 +18,4 @@
 #
 
 name=kubernetes
-parent=compute
\ No newline at end of file
+parent=compute
diff --git a/core/src/main/resources/META-INF/cloudstack/planner/module.properties b/core/src/main/resources/META-INF/cloudstack/planner/module.properties
index 26c61d9..02a2606 100644
--- a/core/src/main/resources/META-INF/cloudstack/planner/module.properties
+++ b/core/src/main/resources/META-INF/cloudstack/planner/module.properties
@@ -18,4 +18,4 @@
 #
 
 name=planner
-parent=allocator
\ No newline at end of file
+parent=allocator
diff --git a/core/src/test/java/com/cloud/agent/api/GetHypervisorGuestOsNamesAnswerTest.java b/core/src/test/java/com/cloud/agent/api/GetHypervisorGuestOsNamesAnswerTest.java
new file mode 100644
index 0000000..36d2fb1
--- /dev/null
+++ b/core/src/test/java/com/cloud/agent/api/GetHypervisorGuestOsNamesAnswerTest.java
@@ -0,0 +1,66 @@
+//
+// 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.agent.api;
+
+import com.cloud.utils.Pair;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class GetHypervisorGuestOsNamesAnswerTest {
+
+    @Test
+    public void testGuestOsMappingAnswerSuccess() {
+        List<Pair<String, String>> hypervisorGuestOsNames = new ArrayList<>();
+        hypervisorGuestOsNames.add(new Pair<>("centos", "centos"));
+        GetHypervisorGuestOsNamesCommand cmd = new GetHypervisorGuestOsNamesCommand();
+        GetHypervisorGuestOsNamesAnswer answer = new GetHypervisorGuestOsNamesAnswer(cmd, hypervisorGuestOsNames);
+        List<Pair<String, String>> resultOsNames = answer.getHypervisorGuestOsNames();
+
+        Assert.assertEquals("centos", resultOsNames.get(0).first());
+        assertTrue(answer.getResult());
+    }
+
+    @Test
+    public void testGuestOsMappingAnswerFailure1() {
+        Throwable th = Mockito.mock(Throwable.class);
+        Mockito.when(th.getMessage()).thenReturn("failure");
+        GetHypervisorGuestOsNamesCommand cmd = new GetHypervisorGuestOsNamesCommand();
+        GetHypervisorGuestOsNamesAnswer answer = new GetHypervisorGuestOsNamesAnswer(cmd, th);
+
+        Assert.assertEquals("failure", answer.getDetails());
+        assertFalse(answer.getResult());
+    }
+
+    @Test
+    public void testGuestOsMappingAnswerFailure2() {
+        GetHypervisorGuestOsNamesCommand cmd = new GetHypervisorGuestOsNamesCommand();
+        GetHypervisorGuestOsNamesAnswer answer = new GetHypervisorGuestOsNamesAnswer(cmd, "failure");
+
+        Assert.assertEquals("failure", answer.getDetails());
+        assertFalse(answer.getResult());
+    }
+}
diff --git a/core/src/test/java/com/cloud/agent/api/GetHypervisorGuestOsNamesCommandTest.java b/core/src/test/java/com/cloud/agent/api/GetHypervisorGuestOsNamesCommandTest.java
new file mode 100644
index 0000000..5d7cb88
--- /dev/null
+++ b/core/src/test/java/com/cloud/agent/api/GetHypervisorGuestOsNamesCommandTest.java
@@ -0,0 +1,40 @@
+//
+// 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.agent.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import org.junit.Test;
+
+public class GetHypervisorGuestOsNamesCommandTest {
+
+    @Test
+    public void testExecuteInSequence() {
+        GetHypervisorGuestOsNamesCommand cmd =  new GetHypervisorGuestOsNamesCommand();
+        assertFalse(cmd.executeInSequence());
+    }
+
+    @Test
+    public void testKeyword() {
+        GetHypervisorGuestOsNamesCommand cmd =  new GetHypervisorGuestOsNamesCommand("centos");
+        assertEquals("centos", cmd.getKeyword());
+    }
+}
diff --git a/core/src/test/java/org/apache/cloudstack/api/agent/test/CheckGuestOsMappingAnswerTest.java b/core/src/test/java/org/apache/cloudstack/api/agent/test/CheckGuestOsMappingAnswerTest.java
new file mode 100644
index 0000000..1ade5e0
--- /dev/null
+++ b/core/src/test/java/org/apache/cloudstack/api/agent/test/CheckGuestOsMappingAnswerTest.java
@@ -0,0 +1,66 @@
+//
+// 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.agent.test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.cloud.agent.api.CheckGuestOsMappingAnswer;
+import com.cloud.agent.api.CheckGuestOsMappingCommand;
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.mockito.Mockito;
+
+public class CheckGuestOsMappingAnswerTest {
+    CheckGuestOsMappingCommand cmd = new CheckGuestOsMappingCommand("CentOS 7.2", "centos64Guest", "6.0");
+    CheckGuestOsMappingAnswer answer = new CheckGuestOsMappingAnswer(cmd);
+
+    @Test
+    public void testGetResult() {
+        boolean b = answer.getResult();
+        assertTrue(b);
+    }
+
+    @Test
+    public void testExecuteInSequence() {
+        boolean b = answer.executeInSequence();
+        assertFalse(b);
+    }
+
+    @Test
+    public void testGuestOsMappingAnswerDetails() {
+        CheckGuestOsMappingCommand cmd = new CheckGuestOsMappingCommand("CentOS 7.2", "centos64Guest", "6.0");
+        CheckGuestOsMappingAnswer answer = new CheckGuestOsMappingAnswer(cmd, "details");
+        String details = answer.getDetails();
+        Assert.assertEquals("details", details);
+    }
+
+    @Test
+    public void testGuestOsMappingAnswerFailure() {
+        Throwable th = Mockito.mock(Throwable.class);
+        Mockito.when(th.getMessage()).thenReturn("Failure");
+        CheckGuestOsMappingCommand cmd = new CheckGuestOsMappingCommand("CentOS 7.2", "centos64Guest", "6.0");
+        CheckGuestOsMappingAnswer answer = new CheckGuestOsMappingAnswer(cmd, th);
+        assertFalse(answer.getResult());
+        Assert.assertEquals("Failure", answer.getDetails());
+
+    }
+}
diff --git a/core/src/test/java/org/apache/cloudstack/api/agent/test/CheckGuestOsMappingCommandTest.java b/core/src/test/java/org/apache/cloudstack/api/agent/test/CheckGuestOsMappingCommandTest.java
new file mode 100644
index 0000000..3f68422
--- /dev/null
+++ b/core/src/test/java/org/apache/cloudstack/api/agent/test/CheckGuestOsMappingCommandTest.java
@@ -0,0 +1,46 @@
+//
+// 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.agent.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.cloud.agent.api.CheckGuestOsMappingCommand;
+import org.junit.Test;
+
+import com.cloud.agent.api.AgentControlCommand;
+
+public class CheckGuestOsMappingCommandTest {
+
+    @Test
+    public void testExecuteInSequence() {
+        CheckGuestOsMappingCommand cmd = new CheckGuestOsMappingCommand();
+        boolean b = cmd.executeInSequence();
+        assertFalse(b);
+    }
+
+    @Test
+    public void testCommandParams() {
+        CheckGuestOsMappingCommand cmd = new CheckGuestOsMappingCommand("CentOS 7.2", "centos64Guest", "6.0");
+        assertEquals("CentOS 7.2", cmd.getGuestOsName());
+        assertEquals("centos64Guest", cmd.getGuestOsHypervisorMappingName());
+        assertEquals("6.0", cmd.getHypervisorVersion());
+    }
+}
diff --git a/debian/changelog b/debian/changelog
index f83c9b1..0b67488 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+cloudstack (4.19.0.0-SNAPSHOT) unstable; urgency=low
+
+  * Update the version to 4.19.0.0-SNAPSHOT
+
+ -- the Apache CloudStack project <dev@cloudstack.apache.org>  Wed, 21 Jun 2023 12:31:00 +0200
+
 cloudstack (4.18.1.0-SNAPSHOT) unstable; urgency=low
 
   * Update the version to 4.18.1.0-SNAPSHOT
diff --git a/debian/cloudstack-cli.install b/debian/cloudstack-cli.install
index 287f9b1..978b68a 100644
--- a/debian/cloudstack-cli.install
+++ b/debian/cloudstack-cli.install
@@ -13,4 +13,4 @@
 # "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.
\ No newline at end of file
+# under the License.
diff --git a/debian/cloudstack-common.postinst b/debian/cloudstack-common.postinst
index 360f3bd..aa99eda 100644
--- a/debian/cloudstack-common.postinst
+++ b/debian/cloudstack-common.postinst
@@ -32,4 +32,4 @@
 cp $CLOUDUTILS_DIR/cloud_utils.py $DIST_DIR
 cp -R $CLOUDUTILS_DIR/cloudutils $DIST_DIR
 python3 -m py_compile $DIST_DIR/cloud_utils.py
-python3 -m compileall $DIST_DIR/cloudutils
\ No newline at end of file
+python3 -m compileall $DIST_DIR/cloudutils
diff --git a/debian/cloudstack-docs.install b/debian/cloudstack-docs.install
index 287f9b1..978b68a 100644
--- a/debian/cloudstack-docs.install
+++ b/debian/cloudstack-docs.install
@@ -13,4 +13,4 @@
 # "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.
\ No newline at end of file
+# under the License.
diff --git a/developer/pom.xml b/developer/pom.xml
index dda007c..44f9e56 100644
--- a/developer/pom.xml
+++ b/developer/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
     </parent>
     <dependencies>
         <dependency>
diff --git a/engine/api/pom.xml b/engine/api/pom.xml
index 5de69f1..fb3ed5d 100644
--- a/engine/api/pom.xml
+++ b/engine/api/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/engine/components-api/pom.xml b/engine/components-api/pom.xml
index 63f92fe..93be1b5 100644
--- a/engine/components-api/pom.xml
+++ b/engine/components-api/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/engine/components-api/src/main/java/com/cloud/agent/AgentManager.java b/engine/components-api/src/main/java/com/cloud/agent/AgentManager.java
index 818e0a7..6ba0c3b 100644
--- a/engine/components-api/src/main/java/com/cloud/agent/AgentManager.java
+++ b/engine/components-api/src/main/java/com/cloud/agent/AgentManager.java
@@ -39,6 +39,13 @@
 public interface AgentManager {
     static final ConfigKey<Integer> Wait = new ConfigKey<Integer>("Advanced", Integer.class, "wait", "1800", "Time in seconds to wait for control commands to return",
             true);
+    ConfigKey<Boolean> EnableKVMAutoEnableDisable = new ConfigKey<>(Boolean.class,
+                    "enable.kvm.host.auto.enable.disable",
+                    "Advanced",
+                    "false",
+                    "(KVM only) Enable Auto Disable/Enable KVM hosts in the cluster " +
+                            "according to the hosts health check results",
+                    true, ConfigKey.Scope.Cluster, null);
 
     public enum TapAgentsAction {
         Add, Del, Contains,
diff --git a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java
index c5caa31..5343fb6 100644
--- a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java
+++ b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java
@@ -20,6 +20,7 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.impl.ConfigurationSubGroupVO;
 
 import com.cloud.dc.ClusterVO;
@@ -59,6 +60,10 @@
     public static final String MESSAGE_CREATE_VLAN_IP_RANGE_EVENT = "Message.CreateVlanIpRange.Event";
     public static final String MESSAGE_DELETE_VLAN_IP_RANGE_EVENT = "Message.DeleteVlanIpRange.Event";
 
+    static final String VM_USERDATA_MAX_LENGTH_STRING = "vm.userdata.max.length";
+    static final ConfigKey<Integer> VM_USERDATA_MAX_LENGTH = new ConfigKey<>("Advanced", Integer.class, VM_USERDATA_MAX_LENGTH_STRING, "32768",
+            "Max length of vm userdata after base64 decoding. Default is 32768 and maximum is 1048576", true);
+
     /**
      * @param offering
      * @return
diff --git a/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java b/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java
index 2fa66d7..80d9ab3 100644
--- a/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java
+++ b/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java
@@ -233,4 +233,6 @@
 
     public static final String MESSAGE_ASSIGN_IPADDR_EVENT = "Message.AssignIpAddr.Event";
     public static final String MESSAGE_RELEASE_IPADDR_EVENT = "Message.ReleaseIpAddr.Event";
+
+    void updateSourceNatIpAddress(IPAddressVO requestedIp, List<IPAddressVO> userIps) throws Exception;
 }
diff --git a/engine/network/pom.xml b/engine/network/pom.xml
index d0dc4ca..f0a3cd9 100644
--- a/engine/network/pom.xml
+++ b/engine/network/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/engine/orchestration/pom.xml b/engine/orchestration/pom.xml
index 2497de6..e5eeb88 100755
--- a/engine/orchestration/pom.xml
+++ b/engine/orchestration/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
@@ -68,6 +68,11 @@
             <artifactId>cloud-server</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.cloudstack</groupId>
+            <artifactId>cloud-plugin-shutdown</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java
index b74c11c..abdee76 100644
--- a/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java
+++ b/engine/orchestration/src/main/java/com/cloud/agent/manager/AgentManagerImpl.java
@@ -51,6 +51,7 @@
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
 import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao;
 import org.apache.cloudstack.utils.identity.ManagementServerNode;
+import org.apache.commons.lang3.BooleanUtils;
 import org.apache.log4j.Logger;
 import org.apache.log4j.MDC;
 
@@ -1250,6 +1251,52 @@
             super(type, link, data);
         }
 
+        private void processHostHealthCheckResult(Boolean hostHealthCheckResult, long hostId) {
+            if (hostHealthCheckResult == null) {
+                return;
+            }
+            HostVO host = _hostDao.findById(hostId);
+            if (host == null) {
+                s_logger.error(String.format("Unable to find host with ID: %s", hostId));
+                return;
+            }
+            if (!BooleanUtils.toBoolean(EnableKVMAutoEnableDisable.valueIn(host.getClusterId()))) {
+                s_logger.debug(String.format("%s is disabled for the cluster %s, cannot process the health check result " +
+                        "received for the host %s", EnableKVMAutoEnableDisable.key(), host.getClusterId(), host.getName()));
+                return;
+            }
+
+            ResourceState.Event resourceEvent = hostHealthCheckResult ? ResourceState.Event.Enable : ResourceState.Event.Disable;
+
+            try {
+                s_logger.info(String.format("Host health check %s, auto %s KVM host: %s",
+                        hostHealthCheckResult ? "succeeds" : "fails",
+                        hostHealthCheckResult ? "enabling" : "disabling",
+                        host.getName()));
+                _resourceMgr.autoUpdateHostAllocationState(hostId, resourceEvent);
+            } catch (NoTransitionException e) {
+                s_logger.error(String.format("Cannot Auto %s host: %s", resourceEvent, host.getName()), e);
+            }
+        }
+
+        private void processStartupRoutingCommand(StartupRoutingCommand startup, long hostId) {
+            if (startup == null) {
+                s_logger.error("Empty StartupRoutingCommand received");
+                return;
+            }
+            Boolean hostHealthCheckResult = startup.getHostHealthCheckResult();
+            processHostHealthCheckResult(hostHealthCheckResult, hostId);
+        }
+
+        private void processPingRoutingCommand(PingRoutingCommand pingRoutingCommand, long hostId) {
+            if (pingRoutingCommand == null) {
+                s_logger.error("Empty PingRoutingCommand received");
+                return;
+            }
+            Boolean hostHealthCheckResult = pingRoutingCommand.getHostHealthCheckResult();
+            processHostHealthCheckResult(hostHealthCheckResult, hostId);
+        }
+
         protected void processRequest(final Link link, final Request request) {
             final AgentAttache attache = (AgentAttache)link.attachment();
             final Command[] cmds = request.getCommands();
@@ -1291,6 +1338,7 @@
                 try {
                     if (cmd instanceof StartupRoutingCommand) {
                         final StartupRoutingCommand startup = (StartupRoutingCommand) cmd;
+                        processStartupRoutingCommand(startup, hostId);
                         answer = new StartupAnswer(startup, attache.getId(), mgmtServiceConf.getPingInterval());
                     } else if (cmd instanceof StartupProxyCommand) {
                         final StartupProxyCommand startup = (StartupProxyCommand) cmd;
@@ -1322,6 +1370,7 @@
                             // if the router is sending a ping, verify the
                             // gateway was pingable
                             if (cmd instanceof PingRoutingCommand) {
+                                processPingRoutingCommand((PingRoutingCommand) cmd, hostId);
                                 final boolean gatewayAccessible = ((PingRoutingCommand)cmd).isGatewayAccessible();
                                 final HostVO host = _hostDao.findById(Long.valueOf(cmdHostId));
 
@@ -1748,8 +1797,8 @@
 
     @Override
     public ConfigKey<?>[] getConfigKeys() {
-        return new ConfigKey<?>[] { CheckTxnBeforeSending, Workers, Port, Wait, AlertWait, DirectAgentLoadSize, DirectAgentPoolSize,
-            DirectAgentThreadCap };
+        return new ConfigKey<?>[] { CheckTxnBeforeSending, Workers, Port, Wait, AlertWait, DirectAgentLoadSize,
+                DirectAgentPoolSize, DirectAgentThreadCap, EnableKVMAutoEnableDisable };
     }
 
     protected class SetHostParamsListener implements Listener {
diff --git a/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java
index 749a738..bd4e259 100644
--- a/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java
+++ b/engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java
@@ -50,6 +50,11 @@
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
 import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
 import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao;
+import org.apache.cloudstack.shutdown.ShutdownManager;
+import org.apache.cloudstack.shutdown.command.CancelShutdownManagementServerHostCommand;
+import org.apache.cloudstack.shutdown.command.PrepareForShutdownManagementServerHostCommand;
+import org.apache.cloudstack.shutdown.command.BaseShutdownManagementServerHostCommand;
+import org.apache.cloudstack.shutdown.command.TriggerShutdownManagementServerHostCommand;
 import org.apache.cloudstack.utils.identity.ManagementServerNode;
 import org.apache.cloudstack.utils.security.SSLUtils;
 import org.apache.log4j.Logger;
@@ -129,6 +134,8 @@
     private HAConfigDao haConfigDao;
     @Inject
     private CAManager caService;
+    @Inject
+    private ShutdownManager shutdownManager;
 
     protected ClusteredAgentManagerImpl() {
         super();
@@ -1341,8 +1348,10 @@
                 return _gson.toJson(answers);
             } else if (cmds.length == 1 && cmds[0] instanceof ScheduleHostScanTaskCommand) {
                 final ScheduleHostScanTaskCommand cmd = (ScheduleHostScanTaskCommand)cmds[0];
-                final String response = handleScheduleHostScanTaskCommand(cmd);
-                return response;
+                return handleScheduleHostScanTaskCommand(cmd);
+            } else if (cmds.length == 1 && cmds[0] instanceof BaseShutdownManagementServerHostCommand) {
+                final BaseShutdownManagementServerHostCommand cmd = (BaseShutdownManagementServerHostCommand)cmds[0];
+                return handleShutdownManagementServerHostCommand(cmd);
             }
 
             try {
@@ -1376,6 +1385,36 @@
             return null;
         }
 
+        private String handleShutdownManagementServerHostCommand(BaseShutdownManagementServerHostCommand cmd) {
+            if (cmd instanceof PrepareForShutdownManagementServerHostCommand) {
+                s_logger.debug("Received BaseShutdownManagementServerHostCommand - preparing to shut down");
+                try {
+                    shutdownManager.prepareForShutdown();
+                    return "Successfully prepared for shutdown";
+                } catch(CloudRuntimeException e) {
+                    return e.getMessage();
+                }
+            }
+            if (cmd instanceof TriggerShutdownManagementServerHostCommand) {
+                s_logger.debug("Received TriggerShutdownManagementServerHostCommand - triggering a shut down");
+                try {
+                    shutdownManager.triggerShutdown();
+                    return "Successfully triggered shutdown";
+                } catch(CloudRuntimeException e) {
+                    return e.getMessage();
+                }
+            }
+            if (cmd instanceof CancelShutdownManagementServerHostCommand) {
+                s_logger.debug("Received CancelShutdownManagementServerHostCommand - cancelling shut down");
+                try {
+                    shutdownManager.cancelShutdown();
+                    return "Successfully prepared for shutdown";
+                } catch(CloudRuntimeException e) {
+                    return e.getMessage();
+                }
+            }
+            throw new CloudRuntimeException("Unknown BaseShutdownManagementServerHostCommand command received : " + cmd);
+        }
     }
 
     public boolean executeAgentUserRequest(final long agentId, final Event event) throws AgentUnavailableException {
diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
index 82e13b5..4ff295b 100644
--- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
+++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java
@@ -1179,7 +1179,7 @@
     }
 
     /**
-     * Validates the locked IP, throwing an exeption if the locked IP is null or the locked IP is not in 'Free' state.
+     * Validates the locked IP, throwing an exception if the locked IP is null or the locked IP is not in 'Free' state.
      */
     protected void validateLockedRequestedIp(IPAddressVO ipVO, IPAddressVO lockedIpVO) {
         if (lockedIpVO == null) {
@@ -1601,7 +1601,7 @@
                 }
 
                 if (s_logger.isDebugEnabled()) {
-                    s_logger.debug("Asking " + element.getName() + " to implemenet " + network);
+                    s_logger.debug("Asking " + element.getName() + " to implement " + network);
                 }
 
                 if (!element.implement(network, offering, dest, context)) {
@@ -2494,7 +2494,7 @@
 
         //remove the secondary ip addresses corresponding to to this nic
         if (!removeVmSecondaryIpsOfNic(nic.getId())) {
-            s_logger.debug("Removing nic " + nic.getId() + " secondary ip addreses failed");
+            s_logger.debug("Removing nic " + nic.getId() + " secondary ip addresses failed");
         }
     }
 
diff --git a/engine/pom.xml b/engine/pom.xml
index 0bed0e9..91f430b 100644
--- a/engine/pom.xml
+++ b/engine/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <build>
@@ -58,6 +58,8 @@
         <module>storage/image</module>
         <module>storage/snapshot</module>
         <module>storage/volume</module>
+        <module>userdata/cloud-init</module>
+        <module>userdata</module>
     </modules>
     <profiles>
         <profile>
diff --git a/engine/schema/pom.xml b/engine/schema/pom.xml
index cad7a0a..4ffef5c 100644
--- a/engine/schema/pom.xml
+++ b/engine/schema/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
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 6dfe75c..ca51ad3 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
@@ -143,6 +143,8 @@
 
     HostVO findByName(String name);
 
+    HostVO findHostByHypervisorTypeAndVersion(HypervisorType hypervisorType, String hypervisorVersion);
+
     List<HostVO> listHostsWithActiveVMs(long offeringId);
 
     /**
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 15c87d6..392b623 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
@@ -116,6 +116,7 @@
     protected SearchBuilder<HostVO> ResourceStateSearch;
     protected SearchBuilder<HostVO> NameLikeSearch;
     protected SearchBuilder<HostVO> NameSearch;
+    protected SearchBuilder<HostVO> hostHypervisorTypeAndVersionSearch;
     protected SearchBuilder<HostVO> SequenceSearch;
     protected SearchBuilder<HostVO> DirectlyConnectedSearch;
     protected SearchBuilder<HostVO> UnmanagedDirectConnectSearch;
@@ -311,6 +312,13 @@
         NameSearch.and("name", NameSearch.entity().getName(), SearchCriteria.Op.EQ);
         NameSearch.done();
 
+        hostHypervisorTypeAndVersionSearch = createSearchBuilder();
+        hostHypervisorTypeAndVersionSearch.and("hypervisorType", hostHypervisorTypeAndVersionSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ);
+        hostHypervisorTypeAndVersionSearch.and("hypervisorVersion", hostHypervisorTypeAndVersionSearch.entity().getHypervisorVersion(), SearchCriteria.Op.EQ);
+        hostHypervisorTypeAndVersionSearch.and("type", hostHypervisorTypeAndVersionSearch.entity().getType(), SearchCriteria.Op.EQ);
+        hostHypervisorTypeAndVersionSearch.and("status", hostHypervisorTypeAndVersionSearch.entity().getStatus(), SearchCriteria.Op.EQ);
+        hostHypervisorTypeAndVersionSearch.done();
+
         SequenceSearch = createSearchBuilder();
         SequenceSearch.and("id", SequenceSearch.entity().getId(), SearchCriteria.Op.EQ);
         // SequenceSearch.addRetrieve("sequence", SequenceSearch.entity().getSequence());
@@ -1446,6 +1454,16 @@
         return findOneBy(sc);
     }
 
+    @Override
+    public HostVO findHostByHypervisorTypeAndVersion(HypervisorType hypervisorType, String hypervisorVersion) {
+        SearchCriteria<HostVO> sc = hostHypervisorTypeAndVersionSearch.create();
+        sc.setParameters("hypervisorType", hypervisorType);
+        sc.setParameters("hypervisorVersion", hypervisorVersion);
+        sc.setParameters("type", Host.Type.Routing);
+        sc.setParameters("status", Status.Up);
+        return findOneBy(sc);
+    }
+
     private ResultSet executeSqlGetResultsetForMethodFindHostInZoneToExecuteCommand(HypervisorType hypervisorType, long zoneId, TransactionLegacy tx, String sql) throws SQLException {
         PreparedStatement pstmt = tx.prepareAutoCloseStatement(sql);
         pstmt.setString(1, Objects.toString(hypervisorType));
diff --git a/engine/schema/src/main/java/com/cloud/network/dao/ExternalFirewallDeviceDao.java b/engine/schema/src/main/java/com/cloud/network/dao/ExternalFirewallDeviceDao.java
index b67130b..efb1b56 100644
--- a/engine/schema/src/main/java/com/cloud/network/dao/ExternalFirewallDeviceDao.java
+++ b/engine/schema/src/main/java/com/cloud/network/dao/ExternalFirewallDeviceDao.java
@@ -34,14 +34,14 @@
     /**
      * list the firewall devices added in to this physical network of certain provider type?
      * @param physicalNetworkId physical Network Id
-     * @param providerName netwrok service provider name
+     * @param providerName network service provider name
      */
     List<ExternalFirewallDeviceVO> listByPhysicalNetworkAndProvider(long physicalNetworkId, String providerName);
 
     /**
      * list the firewall devices added in to this physical network by their allocation state
      * @param physicalNetworkId physical Network Id
-     * @param providerName netwrok service provider name
+     * @param providerName network service provider name
      * @param allocationState firewall device allocation state
      * @return list of ExternalFirewallDeviceVO for the devices in the physical network with a device allocation state
      */
@@ -50,7 +50,7 @@
     /**
      * list the load balancer devices added in to this physical network by the device status (enabled/disabled)
      * @param physicalNetworkId physical Network Id
-     * @param providerName netwrok service provider name
+     * @param providerName network service provider name
      * @param state firewall device status
      * @return list of ExternalFirewallDeviceVO for the devices in the physical network with a device state
      */
diff --git a/engine/schema/src/main/java/com/cloud/network/dao/ExternalLoadBalancerDeviceDao.java b/engine/schema/src/main/java/com/cloud/network/dao/ExternalLoadBalancerDeviceDao.java
index 9125447..9d0f3d6 100644
--- a/engine/schema/src/main/java/com/cloud/network/dao/ExternalLoadBalancerDeviceDao.java
+++ b/engine/schema/src/main/java/com/cloud/network/dao/ExternalLoadBalancerDeviceDao.java
@@ -34,14 +34,14 @@
     /**
      * list the load balancer devices added in to this physical network of certain provider type?
      * @param physicalNetworkId physical Network Id
-     * @param providerName netwrok service provider name
+     * @param providerName network service provider name
      */
     List<ExternalLoadBalancerDeviceVO> listByPhysicalNetworkAndProvider(long physicalNetworkId, String providerName);
 
     /**
      * list the load balancer devices added in to this physical network by their allocation state
      * @param physicalNetworkId physical Network Id
-     * @param providerName netwrok service provider name
+     * @param providerName network service provider name
      * @param allocationState load balancer device allocation state
      * @return list of ExternalLoadBalancerDeviceVO for the devices in the physical network with a device allocation state
      */
@@ -50,7 +50,7 @@
     /**
      * list the load balancer devices added in to this physical network by the device status (enabled/disabled)
      * @param physicalNetworkId physical Network Id
-     * @param providerName netwrok service provider name
+     * @param providerName network service provider name
      * @param state load balancer device status
      * @return list of ExternalLoadBalancerDeviceVO for the devices in the physical network with a device state
      */
@@ -59,7 +59,7 @@
     /**
      * list the load balancer devices added in to this physical network by the managed type (external/cloudstack managed)
      * @param physicalNetworkId physical Network Id
-     * @param providerName netwrok service provider name
+     * @param providerName network service provider name
      * @param managed managed type
      * @return list of ExternalLoadBalancerDeviceVO for the devices in to this physical network of a managed type
      */
diff --git a/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesDao.java b/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesDao.java
index f2e9bcb..21200db 100644
--- a/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesDao.java
+++ b/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesDao.java
@@ -53,6 +53,12 @@
 
     List<FirewallRuleVO> listByIpAndNotRevoked(long ipAddressId);
 
+    /**
+     * counts the number of portforwarding rules for an IP address
+     *
+     * @param sourceIpId the id of the IP record
+     * @return the number of portforwarding rules for this IP
+     */
     long countRulesByIpId(long sourceIpId);
 
     long countRulesByIpIdAndState(long sourceIpId, FirewallRule.State state);
diff --git a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDao.java b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDao.java
index 51dfa91..bb4822e 100644
--- a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDao.java
+++ b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDao.java
@@ -58,7 +58,7 @@
     IPAddressVO findByAssociatedVmId(long vmId);
 
     // for vm secondary ips case mapping is  IP1--> vmIp1, IP2-->vmIp2, etc
-    // This method is used when one vm is mapped to muliple to public ips
+    // This method is used when one vm is mapped to multiple to public ips
     List<IPAddressVO> findAllByAssociatedVmId(long vmId);
 
     IPAddressVO findByIpAndSourceNetworkId(long networkId, String ipAddress);
@@ -75,7 +75,7 @@
 
     long countFreeIPsInNetwork(long networkId);
 
-    IPAddressVO findByVmIp(String vmIp);
+    IPAddressVO findByIp(String ipAddress);
 
     IPAddressVO findByAssociatedVmIdAndVmIp(long vmId, String vmIp);
 
diff --git a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java
index b995959..d82ffbe 100644
--- a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java
@@ -304,7 +304,7 @@
 
 
     // for vm secondary ips case mapping is  IP1--> vmIp1, IP2-->vmIp2, etc
-    // Used when vm is mapped to muliple to public ips
+    // Used when vm is mapped to multiple to public ips
     @Override
     public List<IPAddressVO> findAllByAssociatedVmId(long vmId) {
         SearchCriteria<IPAddressVO> sc = AllFieldsSearch.create();
@@ -314,9 +314,9 @@
     }
 
     @Override
-    public IPAddressVO findByVmIp(String vmIp) {
+    public IPAddressVO findByIp(String ipAddress) {
         SearchCriteria<IPAddressVO> sc = AllFieldsSearch.create();
-        sc.setParameters("associatedVmIp", vmIp);
+        sc.setParameters("ipAddress", ipAddress);
         return findOneBy(sc);
     }
 
diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSDao.java b/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSDao.java
index 83e19b1..e7cfe6f 100644
--- a/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSDao.java
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSDao.java
@@ -19,9 +19,12 @@
 import com.cloud.storage.GuestOSVO;
 import com.cloud.utils.db.GenericDao;
 
+import java.util.List;
+
 public interface GuestOSDao extends GenericDao<GuestOSVO, Long> {
 
     GuestOSVO listByDisplayName(String displayName);
 
+    List<GuestOSVO> listLikeDisplayName(String displayName);
     GuestOSVO findByCategoryIdAndDisplayNameOrderByCreatedDesc(long categoryId, String displayName);
 }
diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSDaoImpl.java
index 68da2b9..3b9a3ec 100644
--- a/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSDaoImpl.java
@@ -33,12 +33,19 @@
 
     protected final SearchBuilder<GuestOSVO> Search;
 
+    protected final SearchBuilder<GuestOSVO> displayNameSearch;
+
     public GuestOSDaoImpl() {
         Search = createSearchBuilder();
         Search.and("category_id", Search.entity().getCategoryId(), SearchCriteria.Op.EQ);
         Search.and("display_name", Search.entity().getDisplayName(), SearchCriteria.Op.EQ);
         Search.and("is_user_defined", Search.entity().getIsUserDefined(), SearchCriteria.Op.EQ);
         Search.done();
+
+        displayNameSearch = createSearchBuilder();
+        displayNameSearch.and("display_name", displayNameSearch.entity().getDisplayName(), SearchCriteria.Op.LIKE);
+        displayNameSearch.done();
+
     }
 
     @Override
@@ -49,6 +56,13 @@
     }
 
     @Override
+    public List<GuestOSVO> listLikeDisplayName(String displayName) {
+        SearchCriteria<GuestOSVO> sc = displayNameSearch.create();
+        sc.setParameters("display_name", "%" + displayName + "%");
+        return listBy(sc);
+    }
+
+    @Override
     public GuestOSVO findByCategoryIdAndDisplayNameOrderByCreatedDesc(long categoryId, String displayName) {
         SearchCriteria<GuestOSVO> sc = Search.create();
         sc.setParameters("category_id", categoryId);
@@ -56,9 +70,9 @@
         sc.setParameters("is_user_defined", false);
 
         Filter orderByFilter = new Filter(GuestOSVO.class, "created", false, null, 1L);
-        List<GuestOSVO> guestOSes = listBy(sc, orderByFilter);
-        if (CollectionUtils.isNotEmpty(guestOSes)) {
-            return guestOSes.get(0);
+        List<GuestOSVO> guestOSlist = listBy(sc, orderByFilter);
+        if (CollectionUtils.isNotEmpty(guestOSlist)) {
+            return guestOSlist.get(0);
         }
         return null;
     }
diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSHypervisorDao.java b/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSHypervisorDao.java
index 17c6b3c..47a7143 100644
--- a/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSHypervisorDao.java
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSHypervisorDao.java
@@ -40,4 +40,6 @@
                                                                       String minHypervisorVersion);
 
     List<String> listHypervisorSupportedVersionsFromMinimumVersion(String hypervisorType, String hypervisorVersion);
+
+    List<GuestOSHypervisorVO> listByHypervisorTypeAndVersion(String hypervisorType, String hypervisorVersion);
 }
diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSHypervisorDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSHypervisorDaoImpl.java
index ae3ae9a..65f17c2 100644
--- a/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSHypervisorDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSHypervisorDaoImpl.java
@@ -39,6 +39,7 @@
     protected final SearchBuilder<GuestOSHypervisorVO> userDefinedMappingSearch;
     protected final SearchBuilder<GuestOSHypervisorVO> guestOsNameSearch;
     protected final SearchBuilder<GuestOSHypervisorVO> availableHypervisorVersionSearch;
+    protected final SearchBuilder<GuestOSHypervisorVO> hypervisorTypeAndVersionSearch;
 
     public GuestOSHypervisorDaoImpl() {
         guestOsSearch = createSearchBuilder();
@@ -73,6 +74,11 @@
         availableHypervisorVersionSearch.select(null, SearchCriteria.Func.DISTINCT,
                 availableHypervisorVersionSearch.entity().getHypervisorVersion());
         availableHypervisorVersionSearch.done();
+
+        hypervisorTypeAndVersionSearch = createSearchBuilder();
+        hypervisorTypeAndVersionSearch.and("hypervisor_type", hypervisorTypeAndVersionSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ);
+        hypervisorTypeAndVersionSearch.and("hypervisor_version", hypervisorTypeAndVersionSearch.entity().getHypervisorVersion(), SearchCriteria.Op.EQ);
+        hypervisorTypeAndVersionSearch.done();
     }
 
     @Override
@@ -176,4 +182,11 @@
         return versions;
     }
 
+    @Override
+    public List<GuestOSHypervisorVO> listByHypervisorTypeAndVersion(String hypervisorType, String hypervisorVersion) {
+        SearchCriteria<GuestOSHypervisorVO> sc = hypervisorTypeAndVersionSearch.create();
+        sc.setParameters("hypervisor_type", hypervisorType);
+        sc.setParameters("hypervisor_version", hypervisorVersion);
+        return listIncludingRemovedBy(sc);
+    }
 }
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java b/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java
index 7375786..a5e57f1 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java
@@ -81,6 +81,7 @@
 import com.cloud.upgrade.dao.Upgrade41710to41720;
 import com.cloud.upgrade.dao.Upgrade41720to41800;
 import com.cloud.upgrade.dao.Upgrade41800to41810;
+import com.cloud.upgrade.dao.Upgrade41810to41900;
 import com.cloud.upgrade.dao.Upgrade420to421;
 import com.cloud.upgrade.dao.Upgrade421to430;
 import com.cloud.upgrade.dao.Upgrade430to440;
@@ -218,6 +219,7 @@
                 .next("4.17.1.0", new Upgrade41710to41720())
                 .next("4.17.2.0", new Upgrade41720to41800())
                 .next("4.18.0.0", new Upgrade41800to41810())
+                .next("4.18.1.0", new Upgrade41810to41900())
                 .build();
     }
 
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/GuestOsMapper.java b/engine/schema/src/main/java/com/cloud/upgrade/GuestOsMapper.java
index def77c5..9b64430 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/GuestOsMapper.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/GuestOsMapper.java
@@ -17,6 +17,7 @@
 package com.cloud.upgrade;
 
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import java.sql.Connection;
@@ -26,6 +27,7 @@
 
 import javax.inject.Inject;
 
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.storage.GuestOSHypervisorMapping;
 import com.cloud.storage.GuestOSHypervisorVO;
 import com.cloud.storage.GuestOSVO;
@@ -94,7 +96,7 @@
         }
     }
 
-    private boolean addGuestOs(long categoryId, String displayName) {
+    public boolean addGuestOs(long categoryId, String displayName) {
         LOG.debug("Adding guest OS with category id: " + categoryId + " and display name: " + displayName);
         GuestOSVO guestOS = new GuestOSVO();
         guestOS.setCategoryId(categoryId);
@@ -116,7 +118,7 @@
             return;
         }
 
-        LOG.debug("Adding guest OS hypervisor mapping - " + mapping.toString());
+        LOG.debug("Adding guest OS hypervisor mapping - " + mapping.toString() + ", for guest OS with id - " + guestOsId);
         GuestOSHypervisorVO guestOsMapping = new GuestOSHypervisorVO();
         guestOsMapping.setHypervisorType(mapping.getHypervisorType());
         guestOsMapping.setHypervisorVersion(mapping.getHypervisorVersion());
@@ -198,4 +200,33 @@
         LOG.warn("Invalid Guest OS hypervisor mapping");
         return false;
     }
+
+    /**
+     * Copies guest OS mappings from src version to dest version for the hypervisor (use this to copy all mappings from older version to newer version during upgrade)
+     * @return true if copied successfully, else false.
+     */
+    public boolean copyGuestOSHypervisorMappings(HypervisorType hypervisorType, String srcVersion, String destVersion) {
+        if (hypervisorType == HypervisorType.None || hypervisorType == HypervisorType.Any) {
+            LOG.warn("Unable to copy, invalid hypervisor");
+            return false;
+        }
+
+        if (StringUtils.isAnyBlank(srcVersion, destVersion)) {
+            LOG.warn("Unable to copy, invalid hypervisor version details");
+            return false;
+        }
+
+        List<GuestOSHypervisorVO> guestOSHypervisorMappingsForSrcVersion = guestOSHypervisorDao.listByHypervisorTypeAndVersion(hypervisorType.toString(), srcVersion);
+        if (CollectionUtils.isEmpty(guestOSHypervisorMappingsForSrcVersion)) {
+            LOG.warn(String.format("Unable to copy, couldn't find guest OS mappings for hypervisor: %s and src version: %s", hypervisorType.toString(), srcVersion));
+            return false;
+        }
+
+        LOG.debug(String.format("Adding guest OS mappings for hypervisor: %s and version: %s, from version: %s ", hypervisorType.toString(), destVersion, srcVersion));
+        for (GuestOSHypervisorVO guestOSHypervisorMapping : guestOSHypervisorMappingsForSrcVersion) {
+            GuestOSHypervisorMapping mapping = new GuestOSHypervisorMapping(hypervisorType.toString(), destVersion, guestOSHypervisorMapping.getGuestOsName());
+            addGuestOsHypervisorMapping(mapping, guestOSHypervisorMapping.getGuestOsId());
+        }
+        return true;
+    }
 }
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade410to420.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade410to420.java
index 915f22b..2e7eee1 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade410to420.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade410to420.java
@@ -1884,7 +1884,7 @@
             //Update all snapshots except KVM snapshots
             int rowCount = snapshotStoreInsert.executeUpdate();
             s_logger.debug("Inserted " + rowCount + " snapshots into snapshot_store_ref");
-            //backsnap_id for KVM snapshots is complate path. CONCAT is not required
+            //backsnap_id for KVM snapshots is complete path. CONCAT is not required
             try(PreparedStatement snapshotStoreInsert_2 =
                     conn.prepareStatement("INSERT INTO `cloud`.`snapshot_store_ref` (store_id,  snapshot_id, created, size, parent_snapshot_id, install_path, volume_id, update_count, ref_cnt, store_role, state) select sechost_id, id, created, size, prev_snap_id, backup_snap_id, volume_id, 0, 0, 'Image', 'Ready' from `cloud`.`snapshots` where status = 'BackedUp' and hypervisor_type = 'KVM' and sechost_id is not null and removed is null");) {
                 rowCount = snapshotStoreInsert_2.executeUpdate();
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java
new file mode 100644
index 0000000..c9ac468
--- /dev/null
+++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41810to41900.java
@@ -0,0 +1,85 @@
+// 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.upgrade.dao;
+
+import com.cloud.upgrade.SystemVmTemplateRegistration;
+import com.cloud.utils.exception.CloudRuntimeException;
+import org.apache.log4j.Logger;
+
+import java.io.InputStream;
+import java.sql.Connection;
+
+public class Upgrade41810to41900 implements DbUpgrade, DbUpgradeSystemVmTemplate {
+    final static Logger LOG = Logger.getLogger(Upgrade41810to41900.class);
+    private SystemVmTemplateRegistration systemVmTemplateRegistration;
+
+    @Override
+    public String[] getUpgradableVersionRange() {
+        return new String[] {"4.18.1.0", "4.19.0.0"};
+    }
+
+    @Override
+    public String getUpgradedVersion() {
+        return "4.19.0.0";
+    }
+
+    @Override
+    public boolean supportsRollingUpgrade() {
+        return false;
+    }
+
+    @Override
+    public InputStream[] getPrepareScripts() {
+        final String scriptFile = "META-INF/db/schema-41810to41900.sql";
+        final InputStream script = Thread.currentThread().getContextClassLoader().getResourceAsStream(scriptFile);
+        if (script == null) {
+            throw new CloudRuntimeException("Unable to find " + scriptFile);
+        }
+
+        return new InputStream[] {script};
+    }
+
+    @Override
+    public void performDataMigration(Connection conn) {
+    }
+
+    @Override
+    public InputStream[] getCleanupScripts() {
+        final String scriptFile = "META-INF/db/schema-41810to41900-cleanup.sql";
+        final InputStream script = Thread.currentThread().getContextClassLoader().getResourceAsStream(scriptFile);
+        if (script == null) {
+            throw new CloudRuntimeException("Unable to find " + scriptFile);
+        }
+
+        return new InputStream[] {script};
+    }
+
+    private void initSystemVmTemplateRegistration() {
+        systemVmTemplateRegistration = new SystemVmTemplateRegistration("");
+    }
+
+    @Override
+    public void updateSystemVmTemplates(Connection conn) {
+        LOG.debug("Updating System Vm template IDs");
+        initSystemVmTemplateRegistration();
+        try {
+            systemVmTemplateRegistration.updateSystemVmTemplates(conn);
+        } catch (Exception e) {
+            throw new CloudRuntimeException("Failed to find / register SystemVM template(s)");
+        }
+    }
+}
diff --git a/engine/schema/src/main/java/com/cloud/vm/ConsoleSessionVO.java b/engine/schema/src/main/java/com/cloud/vm/ConsoleSessionVO.java
index 4b476af..81a1124 100644
--- a/engine/schema/src/main/java/com/cloud/vm/ConsoleSessionVO.java
+++ b/engine/schema/src/main/java/com/cloud/vm/ConsoleSessionVO.java
@@ -19,13 +19,16 @@
 
 package com.cloud.vm;
 
+import java.util.Date;
+
 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 java.util.Date;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
 
 @Entity
 @Table(name = "console_session")
@@ -55,7 +58,8 @@
     private long hostId;
 
     @Column(name = "acquired")
-    private boolean acquired;
+    @Temporal(value = TemporalType.TIMESTAMP)
+    private Date acquired;
 
     @Column(name = "removed")
     private Date removed;
@@ -124,11 +128,11 @@
         this.removed = removed;
     }
 
-    public boolean isAcquired() {
+    public Date getAcquired() {
         return acquired;
     }
 
-    public void setAcquired(boolean acquired) {
+    public void setAcquired(Date acquired) {
         this.acquired = acquired;
     }
 }
diff --git a/engine/schema/src/main/java/com/cloud/vm/NicVO.java b/engine/schema/src/main/java/com/cloud/vm/NicVO.java
index 8905ebf..fba7c96 100644
--- a/engine/schema/src/main/java/com/cloud/vm/NicVO.java
+++ b/engine/schema/src/main/java/com/cloud/vm/NicVO.java
@@ -30,6 +30,9 @@
 import javax.persistence.Table;
 import javax.persistence.Transient;
 
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
 import com.cloud.network.Networks.AddressFormat;
 import com.cloud.network.Networks.Mode;
 import com.cloud.utils.db.GenericDao;
@@ -399,6 +402,15 @@
     }
 
     @Override
+    public int hashCode() {
+        return new HashCodeBuilder(17, 31).append(id).toHashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return EqualsBuilder.reflectionEquals(this, obj);
+    }
+
     public Integer getMtu() {
         return mtu;
     }
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/ConsoleProxyDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/ConsoleProxyDaoImpl.java
index dcf6505..5b5c350 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/ConsoleProxyDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/ConsoleProxyDaoImpl.java
@@ -43,7 +43,7 @@
     private static final Logger s_logger = Logger.getLogger(ConsoleProxyDaoImpl.class);
 
     //
-    // query SQL for returnning console proxy assignment info as following
+    // query SQL for returning console proxy assignment info as following
     //         proxy vm id, count of assignment
     //
     private static final String PROXY_ASSIGNMENT_MATRIX = "SELECT c.id, count(runningVm.id) AS count "
@@ -63,7 +63,7 @@
         + " WHERE v.type='ConsoleProxy' AND (v.state='Creating' OR v.state='Starting' OR v.state='Running' OR v.state='Migrating')" + " GROUP BY d.id, d.name";
 
     //
-    // query SQL for returnning running console proxy count at data center basis
+    // query SQL for returning running console proxy count at data center basis
     //
     private static final String DATACENTER_PROXY_MATRIX =
         "SELECT d.id, d.name, count(dcid) as count"
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/ConsoleSessionDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/ConsoleSessionDaoImpl.java
index f2f4703..8e7e229 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/ConsoleSessionDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/ConsoleSessionDaoImpl.java
@@ -19,12 +19,12 @@
 
 package com.cloud.vm.dao;
 
+import java.util.Date;
+
+import com.cloud.utils.db.GenericDaoBase;
 import com.cloud.utils.db.SearchBuilder;
 import com.cloud.utils.db.SearchCriteria;
 import com.cloud.vm.ConsoleSessionVO;
-import com.cloud.utils.db.GenericDaoBase;
-
-import java.util.Date;
 
 public class ConsoleSessionDaoImpl extends GenericDaoBase<ConsoleSessionVO, Long> implements ConsoleSessionDao {
 
@@ -48,7 +48,7 @@
         if (consoleSessionVO == null) {
             return false;
         }
-        return !consoleSessionVO.isAcquired();
+        return consoleSessionVO.getAcquired() == null;
     }
 
     @Override
@@ -61,7 +61,7 @@
     @Override
     public void acquireSession(String sessionUuid) {
         ConsoleSessionVO consoleSessionVO = findByUuid(sessionUuid);
-        consoleSessionVO.setAcquired(true);
+        consoleSessionVO.setAcquired(new Date());
         update(consoleSessionVO.getId(), consoleSessionVO);
     }
 
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java
index c52c690..2216564 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java
@@ -89,6 +89,8 @@
 
     NicVO findByMacAddress(String macAddress);
 
+    NicVO findByNetworkIdAndMacAddressIncludingRemoved(long networkId, String mac);
+
     List<NicVO> findNicsByIpv6GatewayIpv6CidrAndReserver(String ipv6Gateway, String ipv6Cidr, String reserverName);
 
     NicVO findByIpAddressAndVmType(String ip, VirtualMachine.Type vmType);
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java
index c8efc07..211e548 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java
@@ -218,6 +218,14 @@
     }
 
     @Override
+    public NicVO findByNetworkIdAndMacAddressIncludingRemoved(long networkId, String mac) {
+        SearchCriteria<NicVO> sc = AllFieldsSearch.create();
+        sc.setParameters("network", networkId);
+        sc.setParameters("macAddress", mac);
+        return findOneIncludingRemovedBy(sc);
+    }
+
+    @Override
     public NicVO findDefaultNicForVM(long instanceId) {
         SearchCriteria<NicVO> sc = AllFieldsSearch.create();
         sc.setParameters("instance", instanceId);
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDao.java b/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDao.java
index abc8d80..39c6586 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDao.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDao.java
@@ -103,4 +103,5 @@
 
     List<UserVmVO> findByUserDataId(long userdataId);
 
+    List<UserVmVO> listByIds(List<Long> ids);
 }
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java
index 8a1039e..01439da 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/UserVmDaoImpl.java
@@ -71,6 +71,7 @@
     protected SearchBuilder<UserVmVO> RunningSearch;
     protected SearchBuilder<UserVmVO> StateChangeSearch;
     protected SearchBuilder<UserVmVO> AccountHostSearch;
+    protected SearchBuilder<UserVmVO> IdsSearch;
 
     protected SearchBuilder<UserVmVO> DestroySearch;
     protected SearchBuilder<UserVmVO> AccountDataCenterVirtualSearch;
@@ -135,6 +136,10 @@
         AccountSearch.and("account", AccountSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
         AccountSearch.done();
 
+        IdsSearch = createSearchBuilder();
+        IdsSearch.and("ids", IdsSearch.entity().getId(), SearchCriteria.Op.IN);
+        IdsSearch.done();
+
         HostSearch = createSearchBuilder();
         HostSearch.and("host", HostSearch.entity().getHostId(), SearchCriteria.Op.EQ);
         HostSearch.done();
@@ -778,4 +783,11 @@
         sc.setParameters("userDataId", userdataId);
         return listBy(sc);
     }
+
+    @Override
+    public List<UserVmVO> listByIds(List<Long> ids) {
+        SearchCriteria<UserVmVO> sc = IdsSearch.create();
+        sc.setParameters("ids", ids.toArray());
+        return listBy(sc);
+    }
 }
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/acl/RoleVO.java b/engine/schema/src/main/java/org/apache/cloudstack/acl/RoleVO.java
index f5a0ceb..d464725 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/acl/RoleVO.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/acl/RoleVO.java
@@ -55,6 +55,9 @@
     @Column(name = "is_default")
     private boolean isDefault = false;
 
+    @Column(name = "public_role")
+    private boolean publicRole = true;
+
     @Column(name = GenericDao.REMOVED_COLUMN)
     private Date removed;
 
@@ -120,4 +123,12 @@
     public String toString() {
         return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "name", "uuid", "roleType");
     }
+
+    public boolean isPublicRole() {
+        return publicRole;
+    }
+
+    public void setPublicRole(boolean publicRole) {
+        this.publicRole = publicRole;
+    }
 }
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/acl/dao/RoleDao.java b/engine/schema/src/main/java/org/apache/cloudstack/acl/dao/RoleDao.java
index 36833d5..a776f7b 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/acl/dao/RoleDao.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/acl/dao/RoleDao.java
@@ -26,13 +26,15 @@
 import java.util.List;
 
 public interface RoleDao extends GenericDao<RoleVO, Long> {
-    List<RoleVO> findAllByName(String roleName);
+    List<RoleVO> findAllByName(String roleName, boolean showPrivateRole);
 
-    Pair<List<RoleVO>, Integer> findAllByName(final String roleName, String keyword, Long offset, Long limit);
+    Pair<List<RoleVO>, Integer> findAllByName(final String roleName, String keyword, Long offset, Long limit, boolean showPrivateRole);
 
-    List<RoleVO> findAllByRoleType(RoleType type);
-    List<RoleVO> findByName(String roleName);
-    RoleVO findByNameAndType(String roleName, RoleType type);
+    List<RoleVO> findAllByRoleType(RoleType type, boolean showPrivateRole);
+    List<RoleVO> findByName(String roleName, boolean showPrivateRole);
+    RoleVO findByNameAndType(String roleName, RoleType type, boolean showPrivateRole);
 
-    Pair<List<RoleVO>, Integer> findAllByRoleType(RoleType type, Long offset, Long limit);
+    Pair<List<RoleVO>, Integer> findAllByRoleType(RoleType type, Long offset, Long limit, boolean showPrivateRole);
+
+    Pair<List<RoleVO>, Integer> listAllRoles(Long startIndex, Long limit, boolean showPrivateRole);
 }
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/acl/dao/RoleDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/acl/dao/RoleDaoImpl.java
index b4938a1..06d3108 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/acl/dao/RoleDaoImpl.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/acl/dao/RoleDaoImpl.java
@@ -35,32 +35,41 @@
     private final SearchBuilder<RoleVO> RoleByNameSearch;
     private final SearchBuilder<RoleVO> RoleByTypeSearch;
     private final SearchBuilder<RoleVO> RoleByNameAndTypeSearch;
+    private final SearchBuilder<RoleVO> RoleByIsPublicSearch;
 
     public RoleDaoImpl() {
         super();
 
         RoleByNameSearch = createSearchBuilder();
         RoleByNameSearch.and("roleName", RoleByNameSearch.entity().getName(), SearchCriteria.Op.LIKE);
+        RoleByNameSearch.and("isPublicRole", RoleByNameSearch.entity().isPublicRole(), SearchCriteria.Op.EQ);
         RoleByNameSearch.done();
 
         RoleByTypeSearch = createSearchBuilder();
         RoleByTypeSearch.and("roleType", RoleByTypeSearch.entity().getRoleType(), SearchCriteria.Op.EQ);
+        RoleByTypeSearch.and("isPublicRole", RoleByTypeSearch.entity().isPublicRole(), SearchCriteria.Op.EQ);
         RoleByTypeSearch.done();
 
         RoleByNameAndTypeSearch = createSearchBuilder();
         RoleByNameAndTypeSearch.and("roleName", RoleByNameAndTypeSearch.entity().getName(), SearchCriteria.Op.EQ);
         RoleByNameAndTypeSearch.and("roleType", RoleByNameAndTypeSearch.entity().getRoleType(), SearchCriteria.Op.EQ);
+        RoleByNameAndTypeSearch.and("isPublicRole", RoleByNameAndTypeSearch.entity().isPublicRole(), SearchCriteria.Op.EQ);
         RoleByNameAndTypeSearch.done();
+
+        RoleByIsPublicSearch = createSearchBuilder();
+        RoleByIsPublicSearch.and("isPublicRole", RoleByIsPublicSearch.entity().isPublicRole(), SearchCriteria.Op.EQ);
+        RoleByIsPublicSearch.done();
     }
 
     @Override
-    public List<RoleVO> findAllByName(final String roleName) {
-        return findAllByName(roleName, null, null, null).first();
+    public List<RoleVO> findAllByName(final String roleName, boolean showPrivateRole) {
+        return findAllByName(roleName, null, null, null, showPrivateRole).first();
     }
 
     @Override
-    public Pair<List<RoleVO>, Integer> findAllByName(final String roleName, String keyword, Long offset, Long limit) {
+    public Pair<List<RoleVO>, Integer> findAllByName(final String roleName, String keyword, Long offset, Long limit, boolean showPrivateRole) {
         SearchCriteria<RoleVO> sc = RoleByNameSearch.create();
+        filterPrivateRolesIfNeeded(sc, showPrivateRole);
         if (StringUtils.isNotEmpty(roleName)) {
             sc.setParameters("roleName", roleName);
         }
@@ -72,28 +81,44 @@
     }
 
     @Override
-    public List<RoleVO> findAllByRoleType(final RoleType type) {
-        return findAllByRoleType(type, null, null).first();
+    public List<RoleVO> findAllByRoleType(final RoleType type, boolean showPrivateRole) {
+        return findAllByRoleType(type, null, null, showPrivateRole).first();
     }
 
-    public Pair<List<RoleVO>, Integer> findAllByRoleType(final RoleType type, Long offset, Long limit) {
+    public Pair<List<RoleVO>, Integer> findAllByRoleType(final RoleType type, Long offset, Long limit, boolean showPrivateRole) {
         SearchCriteria<RoleVO> sc = RoleByTypeSearch.create();
+        filterPrivateRolesIfNeeded(sc, showPrivateRole);
         sc.setParameters("roleType", type);
         return searchAndCount(sc, new Filter(RoleVO.class, "id", true, offset, limit));
     }
 
     @Override
-    public List<RoleVO> findByName(String roleName) {
+    public List<RoleVO> findByName(String roleName, boolean showPrivateRole) {
         SearchCriteria<RoleVO> sc = RoleByNameSearch.create();
+        filterPrivateRolesIfNeeded(sc, showPrivateRole);
         sc.setParameters("roleName", roleName);
         return listBy(sc);
     }
 
     @Override
-    public RoleVO findByNameAndType(String roleName, RoleType type) {
+    public RoleVO findByNameAndType(String roleName, RoleType type, boolean showPrivateRole) {
         SearchCriteria<RoleVO> sc = RoleByNameAndTypeSearch.create();
+        filterPrivateRolesIfNeeded(sc, showPrivateRole);
         sc.setParameters("roleName", roleName);
         sc.setParameters("roleType", type);
         return findOneBy(sc);
     }
+
+    @Override
+    public Pair<List<RoleVO>, Integer> listAllRoles(Long startIndex, Long limit, boolean showPrivateRole) {
+        SearchCriteria<RoleVO> sc = RoleByIsPublicSearch.create();
+        filterPrivateRolesIfNeeded(sc, showPrivateRole);
+        return searchAndCount(sc, new Filter(RoleVO.class, "id", true, startIndex, limit));
+    }
+
+    public void filterPrivateRolesIfNeeded(SearchCriteria<RoleVO> sc, boolean showPrivateRole) {
+        if (!showPrivateRole) {
+            sc.setParameters("isPublicRole", true);
+        }
+    }
 }
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduleVO.java b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduleVO.java
new file mode 100644
index 0000000..176f88c
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduleVO.java
@@ -0,0 +1,183 @@
+/*
+ * 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.vm.schedule;
+
+import com.cloud.utils.db.GenericDao;
+
+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.time.ZoneId;
+import java.util.Date;
+import java.util.TimeZone;
+import java.util.UUID;
+
+@Entity
+@Table(name = "vm_schedule")
+public class VMScheduleVO implements VMSchedule {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id", nullable = false)
+    Long id;
+
+    @Column(name = "uuid", nullable = false)
+    String uuid;
+
+    @Column(name = "description")
+    String description;
+
+    @Column(name = "vm_id", nullable = false)
+    long vmId;
+
+    @Column(name = "schedule", nullable = false)
+    String schedule;
+
+    @Column(name = "timezone", nullable = false)
+    String timeZone;
+
+    @Column(name = "action", nullable = false)
+    @Enumerated(value = EnumType.STRING)
+    Action action;
+
+    @Column(name = "enabled", nullable = false)
+    boolean enabled;
+
+    @Column(name = "start_date", nullable = false)
+    @Temporal(value = TemporalType.TIMESTAMP)
+    Date startDate;
+
+    @Column(name = "end_date", nullable = true)
+    @Temporal(value = TemporalType.TIMESTAMP)
+    Date endDate;
+
+    @Column(name = GenericDao.CREATED_COLUMN)
+    Date created;
+
+    @Column(name = GenericDao.REMOVED_COLUMN)
+    Date removed;
+
+    public VMScheduleVO() {
+        uuid = UUID.randomUUID().toString();
+    }
+
+    public VMScheduleVO(long vmId, String description, String schedule, String timeZone, Action action, Date startDate, Date endDate, boolean enabled) {
+        uuid = UUID.randomUUID().toString();
+        this.vmId = vmId;
+        this.description = description;
+        this.schedule = schedule;
+        this.timeZone = timeZone;
+        this.action = action;
+        this.startDate = startDate;
+        this.endDate = endDate;
+        this.enabled = enabled;
+    }
+
+    @Override
+    public String getUuid() {
+        return uuid;
+    }
+
+    @Override
+    public long getId() {
+        return id;
+    }
+
+    public long getVmId() {
+        return vmId;
+    }
+
+    public void setVmId(long vmId) {
+        this.vmId = vmId;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getSchedule() {
+        return schedule.substring(2);
+    }
+
+    public void setSchedule(String schedule) {
+        this.schedule = schedule;
+    }
+
+    @Override
+    public String getTimeZone() {
+        return timeZone;
+    }
+
+    public void setTimeZone(String timeZone) {
+        this.timeZone = timeZone;
+    }
+
+    public Action getAction() {
+        return action;
+    }
+
+    public void setAction(Action action) {
+        this.action = action;
+    }
+
+    public boolean getEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    @Override
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    public void setStartDate(Date startDate) {
+        this.startDate = startDate;
+    }
+
+    @Override
+    public Date getEndDate() {
+        return endDate;
+    }
+
+    public void setEndDate(Date endDate) {
+        this.endDate = endDate;
+    }
+
+    @Override
+    public ZoneId getTimeZoneId() {
+        return TimeZone.getTimeZone(getTimeZone()).toZoneId();
+    }
+
+    public Date getCreated() {
+        return created;
+    }
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduledJobVO.java b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduledJobVO.java
new file mode 100644
index 0000000..0c2dd94
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduledJobVO.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 org.apache.cloudstack.vm.schedule;
+
+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;
+import java.util.UUID;
+
+@Entity
+@Table(name = "vm_scheduled_job")
+public class VMScheduledJobVO implements VMScheduledJob {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    Long id;
+
+    @Column(name = "uuid", nullable = false)
+    String uuid;
+
+    @Column(name = "vm_id", nullable = false)
+    long vmId;
+
+    @Column(name = "vm_schedule_id", nullable = false)
+    long vmScheduleId;
+
+    @Column(name = "async_job_id")
+    Long asyncJobId;
+
+    @Column(name = "action", nullable = false)
+    @Enumerated(value = EnumType.STRING)
+    VMSchedule.Action action;
+
+    @Column(name = "scheduled_timestamp")
+    @Temporal(value = TemporalType.TIMESTAMP)
+    Date scheduledTime;
+
+    public VMScheduledJobVO() {
+        uuid = UUID.randomUUID().toString();
+    }
+
+    public VMScheduledJobVO(long vmId, long vmScheduleId, VMSchedule.Action action, Date scheduledTime) {
+        uuid = UUID.randomUUID().toString();
+        this.vmId = vmId;
+        this.vmScheduleId = vmScheduleId;
+        this.action = action;
+        this.scheduledTime = scheduledTime;
+    }
+
+    @Override
+    public String getUuid() {
+        return uuid;
+    }
+
+    @Override
+    public long getId() {
+        return id;
+    }
+
+    @Override
+    public long getVmId() {
+        return vmId;
+    }
+
+    @Override
+    public long getVmScheduleId() {
+        return vmScheduleId;
+    }
+
+    @Override
+    public Long getAsyncJobId() {
+        return asyncJobId;
+    }
+
+    @Override
+    public void setAsyncJobId(long asyncJobId) {
+        this.asyncJobId = asyncJobId;
+    }
+
+    @Override
+    public VMSchedule.Action getAction() {
+        return action;
+    }
+
+    @Override
+    public Date getScheduledTime() {
+        return scheduledTime;
+    }
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduleDao.java b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduleDao.java
new file mode 100644
index 0000000..b8c808b
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduleDao.java
@@ -0,0 +1,37 @@
+/*
+ * 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.vm.schedule.dao;
+
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.GenericDao;
+import com.cloud.utils.db.SearchCriteria;
+import org.apache.cloudstack.vm.schedule.VMSchedule;
+import org.apache.cloudstack.vm.schedule.VMScheduleVO;
+
+import java.util.List;
+
+public interface VMScheduleDao extends GenericDao<VMScheduleVO, Long> {
+    List<VMScheduleVO> listAllActiveSchedules();
+
+    long removeSchedulesForVmIdAndIds(Long vmId, List<Long> ids);
+
+    Pair<List<VMScheduleVO>, Integer> searchAndCount(Long id, Long vmId, VMSchedule.Action action, Boolean enabled, Long offset, Long limit);
+
+    SearchCriteria<VMScheduleVO> getSearchCriteriaForVMId(Long vmId);
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduleDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduleDaoImpl.java
new file mode 100644
index 0000000..db8c0c3
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduleDaoImpl.java
@@ -0,0 +1,108 @@
+/*
+ * 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.vm.schedule.dao;
+
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.vm.schedule.VMSchedule;
+import org.apache.cloudstack.vm.schedule.VMScheduleVO;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.List;
+
+@Component
+public class VMScheduleDaoImpl extends GenericDaoBase<VMScheduleVO, Long> implements VMScheduleDao {
+
+    private final SearchBuilder<VMScheduleVO> activeScheduleSearch;
+
+    private final SearchBuilder<VMScheduleVO> scheduleSearchByVmIdAndIds;
+
+    private final SearchBuilder<VMScheduleVO> scheduleSearch;
+
+    public VMScheduleDaoImpl() {
+        super();
+        activeScheduleSearch = createSearchBuilder();
+        activeScheduleSearch.and(ApiConstants.ENABLED, activeScheduleSearch.entity().getEnabled(), SearchCriteria.Op.EQ);
+        activeScheduleSearch.and().op(activeScheduleSearch.entity().getEndDate(), SearchCriteria.Op.NULL);
+        activeScheduleSearch.or(ApiConstants.END_DATE, activeScheduleSearch.entity().getEndDate(), SearchCriteria.Op.GT);
+        activeScheduleSearch.cp();
+        activeScheduleSearch.done();
+
+        scheduleSearchByVmIdAndIds = createSearchBuilder();
+        scheduleSearchByVmIdAndIds.and(ApiConstants.ID, scheduleSearchByVmIdAndIds.entity().getId(), SearchCriteria.Op.IN);
+        scheduleSearchByVmIdAndIds.and(ApiConstants.VIRTUAL_MACHINE_ID, scheduleSearchByVmIdAndIds.entity().getVmId(), SearchCriteria.Op.EQ);
+        scheduleSearchByVmIdAndIds.done();
+
+        scheduleSearch = createSearchBuilder();
+        scheduleSearch.and(ApiConstants.ID, scheduleSearch.entity().getId(), SearchCriteria.Op.EQ);
+        scheduleSearch.and(ApiConstants.VIRTUAL_MACHINE_ID, scheduleSearch.entity().getVmId(), SearchCriteria.Op.EQ);
+        scheduleSearch.and(ApiConstants.ACTION, scheduleSearch.entity().getAction(), SearchCriteria.Op.EQ);
+        scheduleSearch.and(ApiConstants.ENABLED, scheduleSearch.entity().getEnabled(), SearchCriteria.Op.EQ);
+        scheduleSearch.done();
+
+    }
+
+    @Override
+    public List<VMScheduleVO> listAllActiveSchedules() {
+        // WHERE enabled = true AND (end_date IS NULL OR end_date > current_date)
+        SearchCriteria<VMScheduleVO> sc = activeScheduleSearch.create();
+        sc.setParameters(ApiConstants.ENABLED, true);
+        sc.setParameters(ApiConstants.END_DATE, new Date());
+        return search(sc, null);
+    }
+
+    @Override
+    public long removeSchedulesForVmIdAndIds(Long vmId, List<Long> ids) {
+        SearchCriteria<VMScheduleVO> sc = scheduleSearchByVmIdAndIds.create();
+        sc.setParameters(ApiConstants.ID, ids.toArray());
+        sc.setParameters(ApiConstants.VIRTUAL_MACHINE_ID, vmId);
+        return remove(sc);
+    }
+
+    @Override
+    public Pair<List<VMScheduleVO>, Integer> searchAndCount(Long id, Long vmId, VMSchedule.Action action, Boolean enabled, Long offset, Long limit) {
+        SearchCriteria<VMScheduleVO> sc = scheduleSearch.create();
+
+        if (id != null) {
+            sc.setParameters(ApiConstants.ID, id);
+        }
+        if (enabled != null) {
+            sc.setParameters(ApiConstants.ENABLED, enabled);
+        }
+        if (action != null) {
+            sc.setParameters(ApiConstants.ACTION, action);
+        }
+        sc.setParameters(ApiConstants.VIRTUAL_MACHINE_ID, vmId);
+
+        Filter filter = new Filter(VMScheduleVO.class, ApiConstants.ID, false, offset, limit);
+        return searchAndCount(sc, filter);
+    }
+
+    @Override
+    public SearchCriteria<VMScheduleVO> getSearchCriteriaForVMId(Long vmId) {
+        SearchCriteria<VMScheduleVO> sc = scheduleSearch.create();
+        sc.setParameters(ApiConstants.VIRTUAL_MACHINE_ID, vmId);
+        return sc;
+    }
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduledJobDao.java b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduledJobDao.java
new file mode 100644
index 0000000..7b8c01a
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduledJobDao.java
@@ -0,0 +1,34 @@
+/*
+ * 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.vm.schedule.dao;
+
+import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.vm.schedule.VMScheduledJobVO;
+
+import java.util.Date;
+import java.util.List;
+
+public interface VMScheduledJobDao extends GenericDao<VMScheduledJobVO, Long> {
+
+    List<VMScheduledJobVO> listJobsToStart(Date currentTimestamp);
+
+    int expungeJobsForSchedules(List<Long> scheduleId, Date dateAfter);
+
+    int expungeJobsBefore(Date currentTimestamp);
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduledJobDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduledJobDaoImpl.java
new file mode 100644
index 0000000..50a2b12
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduledJobDaoImpl.java
@@ -0,0 +1,95 @@
+/*
+ * 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.vm.schedule.dao;
+
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import org.apache.cloudstack.vm.schedule.VMScheduledJobVO;
+import org.apache.commons.lang3.time.DateUtils;
+import org.springframework.stereotype.Component;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+@Component
+public class VMScheduledJobDaoImpl extends GenericDaoBase<VMScheduledJobVO, Long> implements VMScheduledJobDao {
+
+    private final SearchBuilder<VMScheduledJobVO> jobsToStartSearch;
+
+    private final SearchBuilder<VMScheduledJobVO> expungeJobsBeforeSearch;
+
+    private final SearchBuilder<VMScheduledJobVO> expungeJobForScheduleSearch;
+
+    static final String SCHEDULED_TIMESTAMP = "scheduled_timestamp";
+
+    static final String VM_SCHEDULE_ID = "vm_schedule_id";
+
+    public VMScheduledJobDaoImpl() {
+        super();
+        jobsToStartSearch = createSearchBuilder();
+        jobsToStartSearch.and(SCHEDULED_TIMESTAMP, jobsToStartSearch.entity().getScheduledTime(), SearchCriteria.Op.EQ);
+        jobsToStartSearch.and("async_job_id", jobsToStartSearch.entity().getAsyncJobId(), SearchCriteria.Op.NULL);
+        jobsToStartSearch.done();
+
+        expungeJobsBeforeSearch = createSearchBuilder();
+        expungeJobsBeforeSearch.and(SCHEDULED_TIMESTAMP, expungeJobsBeforeSearch.entity().getScheduledTime(), SearchCriteria.Op.LT);
+        expungeJobsBeforeSearch.done();
+
+        expungeJobForScheduleSearch = createSearchBuilder();
+        expungeJobForScheduleSearch.and(VM_SCHEDULE_ID, expungeJobForScheduleSearch.entity().getVmScheduleId(), SearchCriteria.Op.IN);
+        expungeJobForScheduleSearch.and(SCHEDULED_TIMESTAMP, expungeJobForScheduleSearch.entity().getScheduledTime(), SearchCriteria.Op.GTEQ);
+        expungeJobForScheduleSearch.done();
+    }
+
+    /**
+     * Execution of job wouldn't be at exact seconds. So, we round off and then execute.
+     */
+    @Override
+    public List<VMScheduledJobVO> listJobsToStart(Date currentTimestamp) {
+        if (currentTimestamp == null) {
+            currentTimestamp = new Date();
+        }
+        Date truncatedTs = DateUtils.round(currentTimestamp, Calendar.MINUTE);
+
+        SearchCriteria<VMScheduledJobVO> sc = jobsToStartSearch.create();
+        sc.setParameters(SCHEDULED_TIMESTAMP, truncatedTs);
+        Filter filter = new Filter(VMScheduledJobVO.class, "vmScheduleId", true, null, null);
+        return search(sc, filter);
+    }
+
+    @Override
+    public int expungeJobsForSchedules(List<Long> vmScheduleIds, Date dateAfter) {
+        SearchCriteria<VMScheduledJobVO> sc = expungeJobForScheduleSearch.create();
+        sc.setParameters(VM_SCHEDULE_ID, vmScheduleIds.toArray());
+        if (dateAfter != null) {
+            sc.setParameters(SCHEDULED_TIMESTAMP, dateAfter);
+        }
+        return expunge(sc);
+    }
+
+    @Override
+    public int expungeJobsBefore(Date date) {
+        SearchCriteria<VMScheduledJobVO> sc = expungeJobsBeforeSearch.create();
+        sc.setParameters(SCHEDULED_TIMESTAMP, date);
+        return expunge(sc);
+    }
+}
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 51e557f..04ec733 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
@@ -275,4 +275,6 @@
   <bean id="UserVmDeployAsIsDetailsDaoImpl" class="com.cloud.deployasis.dao.UserVmDeployAsIsDetailsDaoImpl" />
   <bean id="NetworkPermissionDaoImpl" class="org.apache.cloudstack.network.dao.NetworkPermissionDaoImpl" />
   <bean id="PassphraseDaoImpl" class="org.apache.cloudstack.secret.dao.PassphraseDaoImpl" />
+  <bean id="VMScheduleDaoImpl" class="org.apache.cloudstack.vm.schedule.dao.VMScheduleDaoImpl" />
+  <bean id="VMScheduledJobDaoImpl" class="org.apache.cloudstack.vm.schedule.dao.VMScheduledJobDaoImpl" />
 </beans>
diff --git a/engine/schema/src/main/resources/META-INF/db/data-217to218.sql b/engine/schema/src/main/resources/META-INF/db/data-217to218.sql
index a6bb1ea..5c12531 100755
--- a/engine/schema/src/main/resources/META-INF/db/data-217to218.sql
+++ b/engine/schema/src/main/resources/META-INF/db/data-217to218.sql
@@ -17,4 +17,3 @@
 
 INSERT INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'default.page.size', '500', 'Default page size for API list* commands');
 DELETE FROM `cloud`.`op_host_capacity` WHERE `capacity_type` in (2,6);
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-20to21.sql b/engine/schema/src/main/resources/META-INF/db/schema-20to21.sql
index cc41910..7013046 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-20to21.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-20to21.sql
@@ -198,4 +198,3 @@
   `created` datetime COMMENT 'date the disk offering was created',
   PRIMARY KEY  (`id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-21to22-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-21to22-cleanup.sql
index 9cfc10a..c875783 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-21to22-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-21to22-cleanup.sql
@@ -79,5 +79,3 @@
 
 UPDATE `cloud`.`vm_instance` SET domain_id=1, account_id=1 where account_id not in (select distinct id from account) or domain_id not in (select distinct id from domain);
 ALTER TABLE `cloud`.`vm_instance` ADD CONSTRAINT `fk_vm_instance__account_id` FOREIGN KEY `fk_vm_instance__account_id` (`account_id`) REFERENCES `account` (`id`);
-
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-21to22-premium.sql b/engine/schema/src/main/resources/META-INF/db/schema-21to22-premium.sql
index 9fb9859..4520284 100755
--- a/engine/schema/src/main/resources/META-INF/db/schema-21to22-premium.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-21to22-premium.sql
@@ -76,6 +76,3 @@
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 update `cloud_usage`.`usage_volume` set size = (size * 1048576);
-
-
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-21to22.sql b/engine/schema/src/main/resources/META-INF/db/schema-21to22.sql
index 7ab7228..c0cf656 100755
--- a/engine/schema/src/main/resources/META-INF/db/schema-21to22.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-21to22.sql
@@ -1016,4 +1016,3 @@
 
 DELETE FROM load_balancer_vm_map WHERE load_balancer_id NOT IN (SELECT id FROM load_balancer);
 DELETE FROM vm_instance WHERE type='User' AND id NOT IN (SELECT id FROM user_vm);
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-2210to2211.sql b/engine/schema/src/main/resources/META-INF/db/schema-2210to2211.sql
index 45ebdf7..01bec02 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-2210to2211.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-2210to2211.sql
@@ -14,4 +14,3 @@
 -- KIND, either express or implied.  See the License for the
 -- specific language governing permissions and limitations
 -- under the License.
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-2211to2212.sql b/engine/schema/src/main/resources/META-INF/db/schema-2211to2212.sql
index 71eca10..94c3d75 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-2211to2212.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-2211to2212.sql
@@ -60,4 +60,3 @@
   CONSTRAINT `fk_inline_load_balancer_nic_map__load_balancer_id` FOREIGN KEY(`load_balancer_id`) REFERENCES `load_balancing_rules`(`id`) ON DELETE CASCADE,
   CONSTRAINT `fk_inline_load_balancer_nic_map__nic_id` FOREIGN KEY(`nic_id`) REFERENCES `nics`(`id`) ON DELETE CASCADE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-2212to2213.sql b/engine/schema/src/main/resources/META-INF/db/schema-2212to2213.sql
index cb32e90..a94f60c 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-2212to2213.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-2212to2213.sql
@@ -80,4 +80,3 @@
 INSERT IGNORE INTO configuration VALUES ('Advanced', 'DEFAULT', 'management-server', 'vm.destory.forcestop', 'false', 'On destory, force-stop takes this value');
 INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.lock.timeout', '600', 'Lock wait timeout (seconds) while implementing network');
 INSERT IGNORE INTO configuration VALUES ('Network', 'DEFAULT', 'management-server', 'network.disable.rpfilter','true','disable rp_filter on Domain Router VM public interfaces.');
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-2213to2214.sql b/engine/schema/src/main/resources/META-INF/db/schema-2213to2214.sql
index de391d3..6c0cc4b 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-2213to2214.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-2213to2214.sql
@@ -87,4 +87,3 @@
 
 ALTER TABLE `cloud`.`keystore` ADD seq int;
 ALTER TABLE `cloud`.`keystore` MODIFY `cloud`.`keystore`.`key` text;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-2214to30-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-2214to30-cleanup.sql
index 6b05e9a..c90707c 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-2214to30-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-2214to30-cleanup.sql
@@ -65,4 +65,3 @@
 DROP TABLE IF EXISTS `cloud_usage`.`event`;
 
 DELETE from `cloud`.`guest_os` where id=204 or id=205;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-221to222-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-221to222-cleanup.sql
index 5908dbb..d999b93 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-221to222-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-221to222-cleanup.sql
@@ -17,4 +17,3 @@
 
 alter table firewall_rules drop column is_static_nat;
 delete from configuration where name='router.cleanup';
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-221to222.sql b/engine/schema/src/main/resources/META-INF/db/schema-221to222.sql
index c4fb804..0c663b1 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-221to222.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-221to222.sql
@@ -52,5 +52,3 @@
   PRIMARY KEY (`id`),
   INDEX `i_version__version`(`version`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-222to224-premium.sql b/engine/schema/src/main/resources/META-INF/db/schema-222to224-premium.sql
index 931ca42..9a5f627 100755
--- a/engine/schema/src/main/resources/META-INF/db/schema-222to224-premium.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-222to224-premium.sql
@@ -21,4 +21,3 @@
 ALTER TABLE `cloud_usage`.`usage_vm_instance` ADD COLUMN `hypervisor_type` varchar(255);
 
 ALTER TABLE `cloud_usage`.`usage_event` ADD COLUMN `resource_type` varchar(32);
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-222to224.sql b/engine/schema/src/main/resources/META-INF/db/schema-222to224.sql
index 439fd6d..8be6416 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-222to224.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-222to224.sql
@@ -193,4 +193,3 @@
 
 UPDATE storage_pool SET cluster_id=(SELECT cluster_id FROM host INNER JOIN storage_pool_host_ref WHERE host.id=storage_pool_host_ref.host_id AND storage_pool_host_ref.pool_id=storage_pool.id) WHERE pool_type='LVM';
 UPDATE `cloud`.`host` SET resource='com.cloud.hypervisor.xen.resource.XenServer56FP1Resource' WHERE resource='com.cloud.hypervisor.xen.resource.XenServer56FP1PremiumResource';
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-224to225.sql b/engine/schema/src/main/resources/META-INF/db/schema-224to225.sql
index a4eff69..65334af 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-224to225.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-224to225.sql
@@ -64,4 +64,3 @@
 ALTER TABLE `cloud`.`user_statistics` MODIFY `device_type` varchar(32) NOT NULL;
 
 ALTER TABLE `cloud`.`nics` MODIFY `ip6_address` char(40);
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-225to226.sql b/engine/schema/src/main/resources/META-INF/db/schema-225to226.sql
index a991ece..49f948c 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-225to226.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-225to226.sql
@@ -49,4 +49,3 @@
   INDEX `i_cmd_exec_log__instance_id`(`instance_id`),
   CONSTRAINT `fk_cmd_exec_log_ref__inst_id` FOREIGN KEY (`instance_id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-227to228-premium.sql b/engine/schema/src/main/resources/META-INF/db/schema-227to228-premium.sql
index 26d555e..40fcbfa 100755
--- a/engine/schema/src/main/resources/META-INF/db/schema-227to228-premium.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-227to228-premium.sql
@@ -34,4 +34,3 @@
 
 update `cloud_usage`.`cloud_usage` set raw_usage = (raw_usage % 24) where usage_type =6 and raw_usage > 24 and (raw_usage % 24) <> 0;
 update `cloud_usage`.`cloud_usage` set raw_usage = 24 where usage_type =6 and raw_usage > 24 and (raw_usage % 24) = 0;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-227to228.sql b/engine/schema/src/main/resources/META-INF/db/schema-227to228.sql
index c0b3eb1..6828bd1 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-227to228.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-227to228.sql
@@ -164,5 +164,3 @@
 INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Console Proxy', 'DEFAULT', 'AgentManager', 'consoleproxy.management.state', 'Auto', 'console proxy service management state');
 INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Console Proxy', 'DEFAULT', 'AgentManager', 'consoleproxy.management.state.last', 'Auto', 'last console proxy service management state');
 INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'cluster.message.timeout.seconds', '300', 'Time (in seconds) to wait before a inter-management server message post times out.');
-
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-228to229.sql b/engine/schema/src/main/resources/META-INF/db/schema-228to229.sql
index d448f03..edc46c0 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-228to229.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-228to229.sql
@@ -92,5 +92,3 @@
   CONSTRAINT `fk_elastic_lb_vm_map__elb_vm_id` FOREIGN KEY `fk_elastic_lb_vm_map__elb_vm_id` (`elb_vm_id`) REFERENCES `vm_instance` (`id`) ON DELETE CASCADE,
   CONSTRAINT `fk_elastic_lb_vm_map__lb_id` FOREIGN KEY `fk_elastic_lb_vm_map__lb_id` (`lb_id`) REFERENCES `load_balancing_rules` (`id`) ON DELETE CASCADE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-22beta3to22beta4.sql b/engine/schema/src/main/resources/META-INF/db/schema-22beta3to22beta4.sql
index 2160878..c73d165 100755
--- a/engine/schema/src/main/resources/META-INF/db/schema-22beta3to22beta4.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-22beta3to22beta4.sql
@@ -124,5 +124,3 @@
 
 DROP VIEW `cloud`.`user_ip_address_view`;
 CREATE VIEW `cloud`.`user_ip_address_view` AS SELECT INET_NTOA(user_ip_address.public_ip_address) as ip_address, user_ip_address.data_center_id, user_ip_address.account_id, user_ip_address.domain_id, user_ip_address.source_nat, user_ip_address.allocated, user_ip_address.vlan_db_id, user_ip_address.one_to_one_nat, user_ip_address.state, user_ip_address.mac_address, user_ip_address.network_id as associated_network_id from user_ip_address;
-
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-304to305-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-304to305-cleanup.sql
index b019ac2..3b5c8f5 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-304to305-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-304to305-cleanup.sql
@@ -19,4 +19,3 @@
 
 
 ALTER TABLE `cloud`.`domain_router` DROP COLUMN network_id;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-305to306-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-305to306-cleanup.sql
index 2afbc27..f15ad4f 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-305to306-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-305to306-cleanup.sql
@@ -23,4 +23,4 @@
 DELETE FROM `cloud`.`storage_pool_host_ref` WHERE `cloud`.`storage_pool_host_ref`.`pool_id` IN (SELECT `cloud`.`storage_pool`.`id` FROM `cloud`.`storage_pool` WHERE `cloud`.`storage_pool`.`removed` IS NOT NULL);
 
 ALTER TABLE `cloud`.`sync_queue` DROP COLUMN queue_proc_msid;
-ALTER TABLE `cloud`.`sync_queue` DROP COLUMN queue_proc_time;
\ No newline at end of file
+ALTER TABLE `cloud`.`sync_queue` DROP COLUMN queue_proc_time;
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-306to307.sql b/engine/schema/src/main/resources/META-INF/db/schema-306to307.sql
index bad23c1..a43833e 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-306to307.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-306to307.sql
@@ -19,4 +19,4 @@
 
 INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Network', 'DEFAULT', 'management-server', 'network.loadbalancer.haproxy.max.conn', '4096', 'Load Balancer(haproxy) maximum number of concurrent connections(global max)');
 
-ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `concurrent_connections` int(10) unsigned COMMENT 'concurrent connections supported on this network';
\ No newline at end of file
+ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `concurrent_connections` int(10) unsigned COMMENT 'concurrent connections supported on this network';
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-307to410-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-307to410-cleanup.sql
index 6a9e2af..4b00fde 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-307to410-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-307to410-cleanup.sql
@@ -35,9 +35,3 @@
 
 ALTER TABLE `cloud`.`network_offerings` DROP COLUMN `concurrent_connections`;
 ALTER TABLE `cloud`.`network_offerings` CHANGE COLUMN `concurrent_connections1` `concurrent_connections` int(10) unsigned COMMENT 'Load Balancer(haproxy) maximum number of concurrent connections(global max)';
-
-
-
-
-
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-40to410-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-40to410-cleanup.sql
index 411b568..a10361b 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-40to410-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-40to410-cleanup.sql
@@ -18,4 +18,3 @@
 --;
 -- Schema cleanup from 4.0.0 to 4.1.0;
 --;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-40to410.sql b/engine/schema/src/main/resources/META-INF/db/schema-40to410.sql
index 3d6dc65..1b3a29b 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-40to410.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-40to410.sql
@@ -1668,4 +1668,3 @@
 
 UPDATE `cloud`.`configuration` set category='Advanced' where category='Advanced ';
 UPDATE `cloud`.`configuration` set category='Hidden' where category='Hidden ';
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41000to41100-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-41000to41100-cleanup.sql
index f8d9ce9..d7a080e 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41000to41100-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41000to41100-cleanup.sql
@@ -66,4 +66,4 @@
             left join
         `cloud`.`async_job` ON async_job.instance_id = user.id
             and async_job.instance_type = 'User'
-            and async_job.job_status = 0;
\ No newline at end of file
+            and async_job.job_status = 0;
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-410to420-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-410to420-cleanup.sql
index b65717f..2a7ab6a 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-410to420-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-410to420-cleanup.sql
@@ -24,5 +24,3 @@
 ALTER TABLE `cloud`.`remote_access_vpn` DROP primary key;
 ALTER TABLE `cloud`.`remote_access_vpn` ADD primary key (`id`);
 ALTER TABLE `cloud`.`remote_access_vpn` ADD CONSTRAINT `fk_remote_access_vpn__vpn_server_addr_id` FOREIGN KEY (`vpn_server_addr_id`) REFERENCES `user_ip_address` (`id`);
-
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41110to41120.sql b/engine/schema/src/main/resources/META-INF/db/schema-41110to41120.sql
index 8b1b9d9..110d13d 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41110to41120.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41110to41120.sql
@@ -27,4 +27,4 @@
 ALTER TABLE `cloud`.`user_vm_clone_setting`
 ADD COLUMN `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT FIRST,
 DROP PRIMARY KEY,
-ADD PRIMARY KEY (`id`);
\ No newline at end of file
+ADD PRIMARY KEY (`id`);
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41500to41510-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-41500to41510-cleanup.sql
index 0939030..9866ed0 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41500to41510-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41500to41510-cleanup.sql
@@ -18,4 +18,3 @@
 --;
 -- Schema upgrade cleanup from 4.15.0.0 to 4.15.1.0
 --;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41500to41510.sql b/engine/schema/src/main/resources/META-INF/db/schema-41500to41510.sql
index 97a4a3e..8b9e000 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41500to41510.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41500to41510.sql
@@ -35,4 +35,3 @@
 -- Add support for VMware 7.0.1.0
 INSERT IGNORE INTO `cloud`.`hypervisor_capabilities` (uuid, hypervisor_type, hypervisor_version, max_guests_limit, security_group_enabled, max_data_volumes_limit, max_hosts_per_cluster, storage_motion_supported, vm_snapshot_enabled) values (UUID(), 'VMware', '7.0.1.0', 1024, 0, 59, 64, 1, 1);
 INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) SELECT UUID(),'VMware', '7.0.1.0', guest_os_name, guest_os_id, utc_timestamp(), 0  FROM `cloud`.`guest_os_hypervisor` WHERE hypervisor_type='VMware' AND hypervisor_version='7.0';
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41510to41520-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-41510to41520-cleanup.sql
index e36ac30..fad2403 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41510to41520-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41510to41520-cleanup.sql
@@ -18,4 +18,3 @@
 --;
 -- Schema upgrade cleanup from 4.15.1.0 to 4.15.2.0
 --;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41600to41610-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-41600to41610-cleanup.sql
index 9db01dd..9993611 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41600to41610-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41600to41610-cleanup.sql
@@ -17,4 +17,4 @@
 
 --;
 -- Schema upgrade cleanup from 4.16.0.0 to 4.16.1.0
---;
\ No newline at end of file
+--;
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700-cleanup.sql
index 667168b..3310fe4 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700-cleanup.sql
@@ -17,4 +17,4 @@
 
 --;
 -- Schema upgrade cleanup from 4.16.1.0 to 4.17.0.0
---;
\ No newline at end of file
+--;
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 c259c14..8417ec2 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
@@ -968,4 +968,4 @@
 ;END;
 
 CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (2, 'Debian GNU/Linux 11 (64-bit)', 'XenServer', '8.2.1', 'Debian Bullseye 11');
-CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (2, 'Debian GNU/Linux 11 (32-bit)', 'XenServer', '8.2.1', 'Debian Bullseye 11');
\ No newline at end of file
+CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (2, 'Debian GNU/Linux 11 (32-bit)', 'XenServer', '8.2.1', 'Debian Bullseye 11');
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41700to41710-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-41700to41710-cleanup.sql
index a6bdbfc..0426797 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41700to41710-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41700to41710-cleanup.sql
@@ -17,4 +17,4 @@
 
 --;
 -- Schema upgrade cleanup from 4.17.0.0 to 4.17.1.0
---;
\ No newline at end of file
+--;
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41700to41710.sql b/engine/schema/src/main/resources/META-INF/db/schema-41700to41710.sql
index 7b8ed8f..2ccd4a8 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41700to41710.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41700to41710.sql
@@ -128,4 +128,4 @@
             and async_job.job_status = 0;
 
 -- PR #6080 Change column `value` size from 255 to 4096 characters, matching the API "updateConfiguration" "value" size
-ALTER TABLE `cloud`.`account_details` MODIFY `value` VARCHAR(4096) NOT NULL;
\ No newline at end of file
+ALTER TABLE `cloud`.`account_details` MODIFY `value` VARCHAR(4096) NOT NULL;
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41720to41800.sql b/engine/schema/src/main/resources/META-INF/db/schema-41720to41800.sql
index 2af6723..a0c9847 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-41720to41800.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41720to41800.sql
@@ -1568,4 +1568,4 @@
 SET
   usage_type = 22
 WHERE
-  usage_type = 24 AND usage_display like '% io write';
\ No newline at end of file
+  usage_type = 24 AND usage_display like '% io write';
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41810to41900-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-41810to41900-cleanup.sql
new file mode 100644
index 0000000..ff0e780
--- /dev/null
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41810to41900-cleanup.sql
@@ -0,0 +1,20 @@
+-- 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.
+
+--;
+-- Schema upgrade cleanup from 4.18.1.0 to 4.19.0.0
+--;
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41810to41900.sql b/engine/schema/src/main/resources/META-INF/db/schema-41810to41900.sql
new file mode 100644
index 0000000..52c58fe
--- /dev/null
+++ b/engine/schema/src/main/resources/META-INF/db/schema-41810to41900.sql
@@ -0,0 +1,182 @@
+-- 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.
+
+--;
+-- Schema upgrade from 4.18.1.0 to 4.19.0.0
+--;
+
+ALTER TABLE `cloud`.`mshost` MODIFY COLUMN `state` varchar(25);
+
+DROP VIEW IF EXISTS `cloud`.`async_job_view`;
+CREATE VIEW `cloud`.`async_job_view` AS
+    select
+        account.id account_id,
+        account.uuid account_uuid,
+        account.account_name account_name,
+        account.type account_type,
+        domain.id domain_id,
+        domain.uuid domain_uuid,
+        domain.name domain_name,
+        domain.path domain_path,
+        user.id user_id,
+        user.uuid user_uuid,
+        async_job.id,
+        async_job.uuid,
+        async_job.job_cmd,
+        async_job.job_status,
+        async_job.job_process_status,
+        async_job.job_result_code,
+        async_job.job_result,
+        async_job.created,
+        async_job.removed,
+        async_job.instance_type,
+        async_job.instance_id,
+        async_job.job_executing_msid,
+        CASE
+            WHEN async_job.instance_type = 'Volume' THEN volumes.uuid
+            WHEN
+                async_job.instance_type = 'Template'
+                    or async_job.instance_type = 'Iso'
+            THEN
+                vm_template.uuid
+            WHEN
+                async_job.instance_type = 'VirtualMachine'
+                    or async_job.instance_type = 'ConsoleProxy'
+                    or async_job.instance_type = 'SystemVm'
+                    or async_job.instance_type = 'DomainRouter'
+            THEN
+                vm_instance.uuid
+            WHEN async_job.instance_type = 'Snapshot' THEN snapshots.uuid
+            WHEN async_job.instance_type = 'Host' THEN host.uuid
+            WHEN async_job.instance_type = 'StoragePool' THEN storage_pool.uuid
+            WHEN async_job.instance_type = 'IpAddress' THEN user_ip_address.uuid
+            WHEN async_job.instance_type = 'SecurityGroup' THEN security_group.uuid
+            WHEN async_job.instance_type = 'PhysicalNetwork' THEN physical_network.uuid
+            WHEN async_job.instance_type = 'TrafficType' THEN physical_network_traffic_types.uuid
+            WHEN async_job.instance_type = 'PhysicalNetworkServiceProvider' THEN physical_network_service_providers.uuid
+            WHEN async_job.instance_type = 'FirewallRule' THEN firewall_rules.uuid
+            WHEN async_job.instance_type = 'Account' THEN acct.uuid
+            WHEN async_job.instance_type = 'User' THEN us.uuid
+            WHEN async_job.instance_type = 'StaticRoute' THEN static_routes.uuid
+            WHEN async_job.instance_type = 'PrivateGateway' THEN vpc_gateways.uuid
+            WHEN async_job.instance_type = 'Counter' THEN counter.uuid
+            WHEN async_job.instance_type = 'Condition' THEN conditions.uuid
+            WHEN async_job.instance_type = 'AutoScalePolicy' THEN autoscale_policies.uuid
+            WHEN async_job.instance_type = 'AutoScaleVmProfile' THEN autoscale_vmprofiles.uuid
+            WHEN async_job.instance_type = 'AutoScaleVmGroup' THEN autoscale_vmgroups.uuid
+            ELSE null
+        END instance_uuid
+    from
+        `cloud`.`async_job`
+            left join
+        `cloud`.`account` ON async_job.account_id = account.id
+            left join
+        `cloud`.`domain` ON domain.id = account.domain_id
+            left join
+        `cloud`.`user` ON async_job.user_id = user.id
+            left join
+        `cloud`.`volumes` ON async_job.instance_id = volumes.id
+            left join
+        `cloud`.`vm_template` ON async_job.instance_id = vm_template.id
+            left join
+        `cloud`.`vm_instance` ON async_job.instance_id = vm_instance.id
+            left join
+        `cloud`.`snapshots` ON async_job.instance_id = snapshots.id
+            left join
+        `cloud`.`host` ON async_job.instance_id = host.id
+            left join
+        `cloud`.`storage_pool` ON async_job.instance_id = storage_pool.id
+            left join
+        `cloud`.`user_ip_address` ON async_job.instance_id = user_ip_address.id
+            left join
+        `cloud`.`security_group` ON async_job.instance_id = security_group.id
+            left join
+        `cloud`.`physical_network` ON async_job.instance_id = physical_network.id
+            left join
+        `cloud`.`physical_network_traffic_types` ON async_job.instance_id = physical_network_traffic_types.id
+            left join
+        `cloud`.`physical_network_service_providers` ON async_job.instance_id = physical_network_service_providers.id
+            left join
+        `cloud`.`firewall_rules` ON async_job.instance_id = firewall_rules.id
+            left join
+        `cloud`.`account` acct ON async_job.instance_id = acct.id
+            left join
+        `cloud`.`user` us ON async_job.instance_id = us.id
+            left join
+        `cloud`.`static_routes` ON async_job.instance_id = static_routes.id
+            left join
+        `cloud`.`vpc_gateways` ON async_job.instance_id = vpc_gateways.id
+            left join
+        `cloud`.`counter` ON async_job.instance_id = counter.id
+            left join
+        `cloud`.`conditions` ON async_job.instance_id = conditions.id
+            left join
+        `cloud`.`autoscale_policies` ON async_job.instance_id = autoscale_policies.id
+            left join
+        `cloud`.`autoscale_vmprofiles` ON async_job.instance_id = autoscale_vmprofiles.id
+            left join
+        `cloud`.`autoscale_vmgroups` ON async_job.instance_id = autoscale_vmgroups.id;
+
+-- Invalidate existing console_session records
+UPDATE `cloud`.`console_session` SET removed=now();
+-- Modify acquired column in console_session to datetime type
+ALTER TABLE `cloud`.`console_session` DROP `acquired`, ADD `acquired` datetime COMMENT 'When the session was acquired' AFTER `host_id`;
+
+-- create_public_parameter_on_roles. #6960
+ALTER TABLE `cloud`.`roles` ADD COLUMN `public_role` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Indicates whether the role will be visible to all users (public) or only to root admins (private). If this parameter is not specified during the creation of the role its value will be defaulted to true (public).';
+
+-- Add tables for VM Scheduler
+DROP TABLE IF EXISTS `cloud`.`vm_schedule`;
+CREATE TABLE `cloud`.`vm_schedule` (
+  `id` bigint unsigned NOT NULL auto_increment COMMENT 'id',
+  `vm_id` bigint unsigned NOT NULL,
+  `uuid` varchar(40) NOT NULL COMMENT 'schedule uuid',
+  `description` varchar(1024) COMMENT 'description of the vm schedule',
+  `schedule` varchar(255) NOT NULL COMMENT 'schedule frequency in cron format',
+  `timezone` varchar(100) NOT NULL COMMENT 'the timezone in which the schedule time is specified',
+  `action` varchar(20) NOT NULL COMMENT 'action to perform',
+  `enabled` int(1) NOT NULL COMMENT 'Enabled or disabled',
+  `start_date` datetime NOT NULL COMMENT 'start time for this schedule',
+  `end_date` datetime COMMENT 'end time for this schedule',
+  `created` datetime NOT NULL COMMENT 'date created',
+  `removed` datetime COMMENT 'date removed if not null',
+  PRIMARY KEY (`id`),
+  INDEX `i_vm_schedule__vm_id`(`vm_id`),
+  INDEX `i_vm_schedule__enabled_end_date`(`enabled`, `end_date`),
+  CONSTRAINT `fk_vm_schedule__vm_id` FOREIGN KEY (`vm_id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE
+  ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+DROP TABLE IF EXISTS `cloud`.`vm_scheduled_job`;
+CREATE TABLE `cloud`.`vm_scheduled_job` (
+  `id` bigint unsigned NOT NULL auto_increment COMMENT 'id',
+  `vm_id` bigint unsigned NOT NULL,
+  `vm_schedule_id` bigint unsigned NOT NULL,
+  `uuid` varchar(40) NOT NULL COMMENT 'scheduled job uuid',
+  `action` varchar(20) NOT NULL COMMENT 'action to perform',
+  `scheduled_timestamp` datetime NOT NULL COMMENT 'Time at which the action is taken',
+  `async_job_id` bigint unsigned DEFAULT NULL COMMENT 'If this schedule is being executed, it is the id of the create aysnc_job. Before that it is null',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY (`vm_schedule_id`, `scheduled_timestamp`),
+  INDEX `i_vm_scheduled_job__scheduled_timestamp`(`scheduled_timestamp`),
+  INDEX `i_vm_scheduled_job__vm_id`(`vm_id`),
+  CONSTRAINT `fk_vm_scheduled_job__vm_id` FOREIGN KEY (`vm_id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE,
+  CONSTRAINT `fk_vm_scheduled_job__vm_schedule_id` FOREIGN KEY (`vm_schedule_id`) REFERENCES `vm_schedule`(`id`) ON DELETE CASCADE
+  ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- Add support for different cluster types for kubernetes
+ALTER TABLE `cloud`.`kubernetes_cluster` ADD COLUMN `cluster_type` varchar(64) DEFAULT 'CloudManaged' COMMENT 'type of cluster';
+ALTER TABLE `cloud`.`kubernetes_cluster` MODIFY COLUMN `kubernetes_version_id` bigint unsigned NULL COMMENT 'the ID of the Kubernetes version of this Kubernetes cluster';
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-421to430-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-421to430-cleanup.sql
index 4a58e65..ce3b757 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-421to430-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-421to430-cleanup.sql
@@ -18,4 +18,3 @@
 --;
 -- Schema cleanup from 4.2.0 to 4.3.0;
 --;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-441to442.sql b/engine/schema/src/main/resources/META-INF/db/schema-441to442.sql
index 3b1618c..d90c83e 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-441to442.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-441to442.sql
@@ -18,4 +18,3 @@
 --;
 -- Schema upgrade from 4.4.1 to 4.4.2;
 --;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-442to450-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-442to450-cleanup.sql
index 33ad921..a8ea565 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-442to450-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-442to450-cleanup.sql
@@ -30,4 +30,4 @@
 
 UPDATE `cloud`.`configuration`
 SET value = 'XenServer'
-Where value = 'Xen';
\ No newline at end of file
+Where value = 'Xen';
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-442to450.sql b/engine/schema/src/main/resources/META-INF/db/schema-442to450.sql
index 06ee70b..90a52bd 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-442to450.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-442to450.sql
@@ -448,7 +448,7 @@
 
 UPDATE configuration SET value='KVM,XenServer,VMware,BareMetal,Ovm,LXC,Hyperv' WHERE name='hypervisor.list';
 UPDATE `cloud`.`configuration` SET description="If set to true, will set guest VM's name as it appears on the hypervisor, to its hostname. The flag is supported for VMware hypervisor only" WHERE name='vm.instancename.flag';
-INSERT IGNORE INTO `cloud`.`configuration`(category, instance, component, name, value, description, default_value) VALUES ('Advanced', 'DEFAULT', 'management-server', 'implicit.host.tags', 'GPU', 'Tag hosts at the time of host disovery based on the host properties/capabilities ', 'GPU');
+INSERT IGNORE INTO `cloud`.`configuration`(category, instance, component, name, value, description, default_value) VALUES ('Advanced', 'DEFAULT', 'management-server', 'implicit.host.tags', 'GPU', 'Tag hosts at the time of host discovery based on the host properties/capabilities ', 'GPU');
 
 DROP VIEW IF EXISTS `cloud`.`domain_router_view`;
 CREATE VIEW `cloud`.`domain_router_view` AS
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-452to460-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-452to460-cleanup.sql
index db5ce11..24083f9 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-452to460-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-452to460-cleanup.sql
@@ -20,4 +20,3 @@
 --
 
 DELETE FROM `cloud`.`configuration` where name='router.reboot.when.outofband.migrated';
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-452to460.sql b/engine/schema/src/main/resources/META-INF/db/schema-452to460.sql
index 1046a00..bb291fe 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-452to460.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-452to460.sql
@@ -419,5 +419,3 @@
 INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'KVM', 'default', 'CentOS 7', 246, utc_timestamp(), 0);
 
 UPDATE  `cloud`.`hypervisor_capabilities` SET  `max_data_volumes_limit` =  '32' WHERE  `hypervisor_capabilities`.`hypervisor_type` =  'KVM';
-
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-461to470.sql b/engine/schema/src/main/resources/META-INF/db/schema-461to470.sql
index 7c70199..238acb5 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-461to470.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-461to470.sql
@@ -250,4 +250,3 @@
 INSERT IGNORE INTO `cloud`.`hypervisor_capabilities` values (25,UUID(),'VMware','6.0',128,0,13,32,1,1);
 INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'VMware', '5.5', 'rhel7_64Guest', 245, utc_timestamp(), 0);
 INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) SELECT UUID(),'VMware', '6.0', guest_os_name, guest_os_id, utc_timestamp(), 0  FROM `cloud`.`guest_os_hypervisor` WHERE hypervisor_type='VMware' AND hypervisor_version='5.5' AND (guest_os_id NOT IN (1,2,3,4,62,63,64,65,156,157,221,222) AND guest_os_id NOT BETWEEN 121 AND 130);
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-480to481.sql b/engine/schema/src/main/resources/META-INF/db/schema-480to481.sql
index 4c8637b..3b2d40b 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-480to481.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-480to481.sql
@@ -18,4 +18,3 @@
 --;
 -- Schema upgrade from 4.8.0 to 4.8.1;
 --;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-481to490-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-481to490-cleanup.sql
index 0b426dc..1868a09 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-481to490-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-481to490-cleanup.sql
@@ -268,4 +268,3 @@
         `cloud`.`async_job` ON async_job.instance_id = user.id
             and async_job.instance_type = 'User'
             and async_job.job_status = 0;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-490to4910-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-490to4910-cleanup.sql
index 657713b..b0c4daf 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-490to4910-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-490to4910-cleanup.sql
@@ -18,4 +18,3 @@
 --;
 -- Schema cleanup from 4.9.0 to 4.9.1.0;
 --;
-
diff --git a/engine/schema/src/main/resources/META-INF/db/schema-4910to4920-cleanup.sql b/engine/schema/src/main/resources/META-INF/db/schema-4910to4920-cleanup.sql
index 963fda4..d4ffed5 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-4910to4920-cleanup.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-4910to4920-cleanup.sql
@@ -18,4 +18,3 @@
 --;
 -- Schema cleanup from 4.9.1.0 to 4.9.2.0;
 --;
-
diff --git a/engine/schema/src/test/java/com/cloud/upgrade/GuestOsMapperTest.java b/engine/schema/src/test/java/com/cloud/upgrade/GuestOsMapperTest.java
new file mode 100644
index 0000000..fa6c693
--- /dev/null
+++ b/engine/schema/src/test/java/com/cloud/upgrade/GuestOsMapperTest.java
@@ -0,0 +1,84 @@
+// 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.upgrade;
+
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.storage.GuestOSHypervisorVO;
+import com.cloud.storage.dao.GuestOSHypervisorDao;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(PowerMockRunner.class)
+public class GuestOsMapperTest {
+
+    @Spy
+    @InjectMocks
+    GuestOsMapper guestOsMapper = new GuestOsMapper();
+
+    @Mock
+    GuestOSHypervisorDao guestOSHypervisorDao;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testCopyGuestOSHypervisorMappingsFailures() {
+        boolean result = guestOsMapper.copyGuestOSHypervisorMappings(Hypervisor.HypervisorType.Any, "6.0", "7.0");
+        Assert.assertFalse(result);
+
+        result = guestOsMapper.copyGuestOSHypervisorMappings(Hypervisor.HypervisorType.None, "6.0", "7.0");
+        Assert.assertFalse(result);
+
+        result = guestOsMapper.copyGuestOSHypervisorMappings(Hypervisor.HypervisorType.XenServer, "", "7.0");
+        Assert.assertFalse(result);
+
+        result = guestOsMapper.copyGuestOSHypervisorMappings(Hypervisor.HypervisorType.XenServer, "6.0", "");
+        Assert.assertFalse(result);
+
+        Mockito.when(guestOSHypervisorDao.listByHypervisorTypeAndVersion(Mockito.anyString(), Mockito.anyString())).thenReturn(null);
+        result = guestOsMapper.copyGuestOSHypervisorMappings(Hypervisor.HypervisorType.XenServer, "6.0", "7.0");
+        Assert.assertFalse(result);
+    }
+
+    @Test
+    public void testCopyGuestOSHypervisorMappingsSuccess() {
+        GuestOSHypervisorVO guestOSHypervisorVO = Mockito.mock(GuestOSHypervisorVO.class);
+        List<GuestOSHypervisorVO> guestOSHypervisorVOS = new ArrayList<>();
+        guestOSHypervisorVOS.add(guestOSHypervisorVO);
+        Mockito.when(guestOSHypervisorDao.listByHypervisorTypeAndVersion(Mockito.anyString(), Mockito.anyString())).thenReturn(guestOSHypervisorVOS);
+        Mockito.when(guestOSHypervisorVO.getGuestOsName()).thenReturn("centos");
+        GuestOSHypervisorVO guestOsMapping = Mockito.mock(GuestOSHypervisorVO.class);
+        Mockito.when(guestOSHypervisorDao.persist(guestOsMapping)).thenReturn(guestOsMapping);
+
+        boolean result = guestOsMapper.copyGuestOSHypervisorMappings(Hypervisor.HypervisorType.XenServer, "6.0", "7.0");
+        Assert.assertTrue(result);
+    }
+}
diff --git a/engine/service/pom.xml b/engine/service/pom.xml
index 3e312d4..64453d3 100644
--- a/engine/service/pom.xml
+++ b/engine/service/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
     </parent>
     <artifactId>cloud-engine-service</artifactId>
     <packaging>war</packaging>
diff --git a/engine/storage/cache/pom.xml b/engine/storage/cache/pom.xml
index e70e1f0..989402c 100644
--- a/engine/storage/cache/pom.xml
+++ b/engine/storage/cache/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/engine/storage/cache/src/main/java/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java b/engine/storage/cache/src/main/java/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
index 0abdf2e..a687ddf 100644
--- a/engine/storage/cache/src/main/java/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
+++ b/engine/storage/cache/src/main/java/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java
@@ -253,11 +253,11 @@
             if (obj != null) {
                 State st = obj.getState();
 
-                long miliSeconds = 10000;
+                long milliSeconds = 10000;
                 long timeoutSeconds = 3600;
-                long timeoutMiliSeconds = timeoutSeconds * 1000;
+                long timeoutMilliSeconds = timeoutSeconds * 1000;
                 Date now = new Date();
-                long expiredEpoch = now.getTime() + timeoutMiliSeconds;
+                long expiredEpoch = now.getTime() + timeoutMilliSeconds;
                 Date expiredDate = new Date(expiredEpoch);
 
                 /*
@@ -273,7 +273,7 @@
                      */
                     s_logger.debug("waiting cache copy completion type: " + typeName + ", id: " + obj.getObjectId() + ", lock: " + lock.hashCode());
                     try {
-                        lock.wait(miliSeconds);
+                        lock.wait(milliSeconds);
                     } catch (InterruptedException e) {
                         s_logger.debug("[ignored] interrupted while waiting for cache copy completion.");
                     }
diff --git a/engine/storage/configdrive/pom.xml b/engine/storage/configdrive/pom.xml
index 122075c..041616d 100644
--- a/engine/storage/configdrive/pom.xml
+++ b/engine/storage/configdrive/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/engine/storage/datamotion/pom.xml b/engine/storage/datamotion/pom.xml
index 55d8a0e..aa3b986 100644
--- a/engine/storage/datamotion/pom.xml
+++ b/engine/storage/datamotion/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/engine/storage/image/pom.xml b/engine/storage/image/pom.xml
index a182ee2..bf7b7f8 100644
--- a/engine/storage/image/pom.xml
+++ b/engine/storage/image/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/engine/storage/integration-test/pom.xml b/engine/storage/integration-test/pom.xml
index 77f17d6..735c1a0 100644
--- a/engine/storage/integration-test/pom.xml
+++ b/engine/storage/integration-test/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/engine/storage/pom.xml b/engine/storage/pom.xml
index 40f03b6..86bb847 100644
--- a/engine/storage/pom.xml
+++ b/engine/storage/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/engine/storage/snapshot/pom.xml b/engine/storage/snapshot/pom.xml
index cf65a7f..9ba5e3a 100644
--- a/engine/storage/snapshot/pom.xml
+++ b/engine/storage/snapshot/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/StorageVMSnapshotStrategy.java b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/StorageVMSnapshotStrategy.java
index 9582900..4030295 100644
--- a/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/StorageVMSnapshotStrategy.java
+++ b/engine/storage/snapshot/src/main/java/org/apache/cloudstack/storage/vmsnapshot/StorageVMSnapshotStrategy.java
@@ -177,7 +177,7 @@
                         thawAnswer = (FreezeThawVMAnswer) agentMgr.send(hostId, thawCmd);
                         throw new CloudRuntimeException("Could not take snapshot for volume with id=" + vol.getId());
                     }
-                    s_logger.info(String.format("Snapshot with id=%s, took  %s miliseconds", snapInfo.getId(),
+                    s_logger.info(String.format("Snapshot with id=%s, took  %s milliseconds", snapInfo.getId(),
                             TimeUnit.MILLISECONDS.convert(elapsedTime(startSnapshtot), TimeUnit.NANOSECONDS)));
                 }
                 answer = new CreateVMSnapshotAnswer(ccmd, true, "");
@@ -185,7 +185,7 @@
                 thawAnswer = (FreezeThawVMAnswer) agentMgr.send(hostId, thawCmd);
                 if (thawAnswer != null && thawAnswer.getResult()) {
                     s_logger.info(String.format(
-                            "Virtual machne is thawed. The freeze of virtual machine took %s miliseconds.",
+                            "Virtual machne is thawed. The freeze of virtual machine took %s milliseconds.",
                             TimeUnit.MILLISECONDS.convert(elapsedTime(startFreeze), TimeUnit.NANOSECONDS)));
                 }
             } else {
@@ -219,7 +219,7 @@
             throw new CloudRuntimeException(e.getMessage());
         } finally {
             if (thawAnswer == null && freezeAnswer != null) {
-                s_logger.info(String.format("Freeze of virtual machine took %s miliseconds.", TimeUnit.MILLISECONDS
+                s_logger.info(String.format("Freeze of virtual machine took %s milliseconds.", TimeUnit.MILLISECONDS
                                                 .convert(elapsedTime(startFreeze), TimeUnit.NANOSECONDS)));
                 try {
                     thawAnswer = (FreezeThawVMAnswer) agentMgr.send(hostId, thawCmd);
diff --git a/engine/storage/snapshot/src/main/resources/META-INF/cloudstack/core/spring-engine-storage-snapshot-core-context.xml b/engine/storage/snapshot/src/main/resources/META-INF/cloudstack/core/spring-engine-storage-snapshot-core-context.xml
index 75545a89..1d1c831 100644
--- a/engine/storage/snapshot/src/main/resources/META-INF/cloudstack/core/spring-engine-storage-snapshot-core-context.xml
+++ b/engine/storage/snapshot/src/main/resources/META-INF/cloudstack/core/spring-engine-storage-snapshot-core-context.xml
@@ -36,4 +36,4 @@
     <bean id="snapshotStateMachineManagerImpl"
         class="org.apache.cloudstack.storage.snapshot.SnapshotStateMachineManagerImpl" />
     
-</beans>
\ No newline at end of file
+</beans>
diff --git a/engine/storage/src/main/resources/META-INF/cloudstack/storage-allocator/module.properties b/engine/storage/src/main/resources/META-INF/cloudstack/storage-allocator/module.properties
index 6c96e91..7beaf83 100644
--- a/engine/storage/src/main/resources/META-INF/cloudstack/storage-allocator/module.properties
+++ b/engine/storage/src/main/resources/META-INF/cloudstack/storage-allocator/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=storage-allocator
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/engine/storage/volume/pom.xml b/engine/storage/volume/pom.xml
index 42b1b39..acaa38c 100644
--- a/engine/storage/volume/pom.xml
+++ b/engine/storage/volume/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-engine</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/engine/storage/volume/src/main/resources/META-INF/cloudstack/core/spring-engine-storage-volume-core-context.xml b/engine/storage/volume/src/main/resources/META-INF/cloudstack/core/spring-engine-storage-volume-core-context.xml
index 860929c..a0cb6a7 100644
--- a/engine/storage/volume/src/main/resources/META-INF/cloudstack/core/spring-engine-storage-volume-core-context.xml
+++ b/engine/storage/volume/src/main/resources/META-INF/cloudstack/core/spring-engine-storage-volume-core-context.xml
@@ -46,4 +46,4 @@
     <bean id="primaryDataStoreProviderMgr"
         class="org.apache.cloudstack.storage.datastore.manager.PrimaryDataStoreProviderManagerImpl" />
  
-</beans>
\ No newline at end of file
+</beans>
diff --git a/engine/storage/volume/src/test/resource/testContext.xml b/engine/storage/volume/src/test/resource/testContext.xml
index da2f5a2..7352b11 100644
--- a/engine/storage/volume/src/test/resource/testContext.xml
+++ b/engine/storage/volume/src/test/resource/testContext.xml
@@ -76,4 +76,4 @@
 
   <bean id="eventBus" class = "org.apache.cloudstack.framework.eventbus.EventBusBase" />
   
-</beans>
\ No newline at end of file
+</beans>
diff --git a/engine/userdata/cloud-init/pom.xml b/engine/userdata/cloud-init/pom.xml
new file mode 100644
index 0000000..7e641bd
--- /dev/null
+++ b/engine/userdata/cloud-init/pom.xml
@@ -0,0 +1,36 @@
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<modelVersion>4.0.0</modelVersion>
+<artifactId>cloud-engine-userdata-cloud-init</artifactId>
+<name>Apache CloudStack Engine Cloud-Init Userdata Component</name>
+<parent>
+    <artifactId>cloud-engine</artifactId>
+    <groupId>org.apache.cloudstack</groupId>
+    <version>4.19.0.0-SNAPSHOT</version>
+    <relativePath>../../pom.xml</relativePath>
+</parent>
+<dependencies>
+    <dependency>
+        <groupId>org.apache.cloudstack</groupId>
+        <artifactId>cloud-engine-userdata</artifactId>
+        <version>${project.version}</version>
+    </dependency>
+</dependencies>
+</project>
diff --git a/engine/userdata/cloud-init/src/main/java/org/apache/cloudstack/userdata/CloudInitUserDataProvider.java b/engine/userdata/cloud-init/src/main/java/org/apache/cloudstack/userdata/CloudInitUserDataProvider.java
new file mode 100644
index 0000000..65996f1
--- /dev/null
+++ b/engine/userdata/cloud-init/src/main/java/org/apache/cloudstack/userdata/CloudInitUserDataProvider.java
@@ -0,0 +1,286 @@
+// 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.userdata;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.stream.Collectors;
+import java.util.zip.GZIPInputStream;
+
+import javax.mail.BodyPart;
+import javax.mail.MessagingException;
+import javax.mail.Multipart;
+import javax.mail.Session;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Logger;
+
+import com.cloud.utils.component.AdapterBase;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.sun.mail.util.BASE64DecoderStream;
+
+public class CloudInitUserDataProvider extends AdapterBase implements UserDataProvider {
+
+    protected enum FormatType {
+        CLOUD_CONFIG, BASH_SCRIPT, MIME, CLOUD_BOOTHOOK, INCLUDE_FILE
+    }
+
+    private static final String CLOUD_CONFIG_CONTENT_TYPE = "text/cloud-config";
+    private static final String BASH_SCRIPT_CONTENT_TYPE = "text/x-shellscript";
+    private static final String INCLUDE_FILE_CONTENT_TYPE = "text/x-include-url";
+    private static final String CLOUD_BOOTHOOK_CONTENT_TYPE = "text/cloud-boothook";
+
+    private static final Map<FormatType, String> formatContentTypeMap = Map.ofEntries(
+            Map.entry(FormatType.CLOUD_CONFIG, CLOUD_CONFIG_CONTENT_TYPE),
+            Map.entry(FormatType.BASH_SCRIPT, BASH_SCRIPT_CONTENT_TYPE),
+            Map.entry(FormatType.CLOUD_BOOTHOOK, CLOUD_BOOTHOOK_CONTENT_TYPE),
+            Map.entry(FormatType.INCLUDE_FILE, INCLUDE_FILE_CONTENT_TYPE)
+    );
+
+    private static final Logger LOGGER = Logger.getLogger(CloudInitUserDataProvider.class);
+
+    private static final Session session = Session.getDefaultInstance(new Properties());
+
+    @Override
+    public String getName() {
+        return "cloud-init";
+    }
+
+    protected boolean isGZipped(String encodedUserdata) {
+        if (StringUtils.isEmpty(encodedUserdata)) {
+            return false;
+        }
+        byte[] data = Base64.decodeBase64(encodedUserdata);
+        if (data.length < 2) {
+            return false;
+        }
+        int magic = data[0] & 0xff | ((data[1] << 8) & 0xff00);
+        return magic == GZIPInputStream.GZIP_MAGIC;
+    }
+
+    protected String extractUserDataHeader(String userdata) {
+        List<String> lines = Arrays.stream(userdata.split("\n"))
+                .filter(x -> (x.startsWith("#") && !x.startsWith("##")) || (x.startsWith("Content-Type:")))
+                .collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(lines)) {
+            throw new CloudRuntimeException("Failed to detect the user data format type as it " +
+                    "does not contain a header");
+        }
+        return lines.get(0);
+    }
+
+    protected FormatType mapUserDataHeaderToFormatType(String header) {
+        if (header.equalsIgnoreCase("#cloud-config")) {
+            return FormatType.CLOUD_CONFIG;
+        } else if (header.startsWith("#!")) {
+            return FormatType.BASH_SCRIPT;
+        } else if (header.equalsIgnoreCase("#cloud-boothook")) {
+            return FormatType.CLOUD_BOOTHOOK;
+        } else if (header.startsWith("#include")) {
+            return FormatType.INCLUDE_FILE;
+        } else if (header.startsWith("Content-Type:")) {
+            return FormatType.MIME;
+        } else {
+            String msg = String.format("Cannot recognise the user data format type from the header line: %s." +
+                    "Supported types are: cloud-config, bash script, cloud-boothook, include file or MIME", header);
+            LOGGER.error(msg);
+            throw new CloudRuntimeException(msg);
+        }
+    }
+
+    /**
+     * Detect the user data type
+     * Reference: <a href="https://canonical-cloud-init.readthedocs-hosted.com/en/latest/explanation/format.html#user-data-formats" />
+     */
+    protected FormatType getUserDataFormatType(String userdata) {
+        if (StringUtils.isBlank(userdata)) {
+            String msg = "User data expected but provided empty user data";
+            LOGGER.error(msg);
+            throw new CloudRuntimeException(msg);
+        }
+
+        String header = extractUserDataHeader(userdata);
+        return mapUserDataHeaderToFormatType(header);
+    }
+
+    private String getContentType(String userData, FormatType formatType) throws MessagingException {
+        if (formatType == FormatType.MIME) {
+            NoIdMimeMessage msg = new NoIdMimeMessage(session, new ByteArrayInputStream(userData.getBytes()));
+            return msg.getContentType();
+        }
+        if (!formatContentTypeMap.containsKey(formatType)) {
+            throw new CloudRuntimeException(String.format("Cannot get the user data content type as " +
+                    "its format type %s is invalid", formatType.name()));
+        }
+        return formatContentTypeMap.get(formatType);
+    }
+
+    protected String getBodyPartContentAsString(BodyPart bodyPart) throws MessagingException, IOException {
+        Object content = bodyPart.getContent();
+        if (content instanceof BASE64DecoderStream) {
+            return new String(((BASE64DecoderStream)bodyPart.getContent()).readAllBytes());
+        } else if (content instanceof ByteArrayInputStream) {
+            return new String(((ByteArrayInputStream)bodyPart.getContent()).readAllBytes());
+        } else if (content instanceof String) {
+            return (String)bodyPart.getContent();
+        }
+        throw new CloudRuntimeException(String.format("Failed to get content for multipart data with content type: %s", getBodyPartContentType(bodyPart)));
+    }
+
+    private String getBodyPartContentType(BodyPart bodyPart) throws MessagingException {
+        String contentType = StringUtils.defaultString(bodyPart.getDataHandler().getContentType(), bodyPart.getContentType());
+        return  contentType.contains(";") ? contentType.substring(0, contentType.indexOf(';')) : contentType;
+    }
+
+    protected MimeBodyPart generateBodyPartMimeMessage(String userData, String contentType) throws MessagingException {
+        MimeBodyPart bodyPart = new MimeBodyPart();
+        bodyPart.setContent(userData, contentType);
+        bodyPart.addHeader("Content-Transfer-Encoding", "base64");
+        return bodyPart;
+    }
+
+    protected MimeBodyPart generateBodyPartMimeMessage(String userData, FormatType formatType) throws MessagingException {
+        return generateBodyPartMimeMessage(userData, getContentType(userData, formatType));
+    }
+
+    private Multipart getMessageContent(NoIdMimeMessage message) {
+        Multipart messageContent;
+        try {
+            messageContent = (MimeMultipart) message.getContent();
+        } catch (IOException | MessagingException e) {
+            messageContent = new MimeMultipart();
+        }
+        return messageContent;
+    }
+
+    private void addBodyPartToMultipart(Multipart existingMultipart, MimeBodyPart bodyPart) throws MessagingException, IOException {
+        boolean added = false;
+        final int existingCount = existingMultipart.getCount();
+        for (int j = 0; j < existingCount; ++j) {
+            MimeBodyPart existingBodyPart = (MimeBodyPart)existingMultipart.getBodyPart(j);
+            String existingContentType = getBodyPartContentType(existingBodyPart);
+            String newContentType = getBodyPartContentType(bodyPart);
+            if (existingContentType.equals(newContentType)) {
+                String existingContent = getBodyPartContentAsString(existingBodyPart);
+                String newContent = getBodyPartContentAsString(bodyPart);
+                // generating a combined content MimeBodyPart to replace
+                MimeBodyPart combinedBodyPart = generateBodyPartMimeMessage(
+                        simpleAppendSameFormatTypeUserData(existingContent, newContent), existingContentType);
+                existingMultipart.removeBodyPart(j);
+                existingMultipart.addBodyPart(combinedBodyPart, j);
+                added = true;
+                break;
+            }
+        }
+        if (!added) {
+            existingMultipart.addBodyPart(bodyPart);
+        }
+    }
+
+    private void addBodyPartsToMessageContentFromUserDataContent(Multipart existingMultipart,
+                                                                 NoIdMimeMessage msgFromUserdata) throws MessagingException, IOException {
+        MimeMultipart newMultipart = (MimeMultipart)msgFromUserdata.getContent();
+        final int existingCount = existingMultipart.getCount();
+        final int newCount = newMultipart.getCount();
+        for (int i = 0; i < newCount; ++i) {
+            BodyPart bodyPart = newMultipart.getBodyPart(i);
+            if (existingCount == 0) {
+                existingMultipart.addBodyPart(bodyPart);
+                continue;
+            }
+            addBodyPartToMultipart(existingMultipart, (MimeBodyPart)bodyPart);
+        }
+    }
+
+    private NoIdMimeMessage createMultipartMessageAddingUserdata(String userData, FormatType formatType,
+                                                           NoIdMimeMessage message) throws MessagingException, IOException {
+        NoIdMimeMessage newMessage = new NoIdMimeMessage(session);
+        Multipart messageContent = getMessageContent(message);
+
+        if (formatType == FormatType.MIME) {
+            NoIdMimeMessage msgFromUserdata = new NoIdMimeMessage(session, new ByteArrayInputStream(userData.getBytes()));
+            addBodyPartsToMessageContentFromUserDataContent(messageContent, msgFromUserdata);
+        } else {
+            MimeBodyPart part = generateBodyPartMimeMessage(userData, formatType);
+            addBodyPartToMultipart(messageContent, part);
+        }
+        newMessage.setContent(messageContent);
+        return newMessage;
+    }
+
+    private String simpleAppendSameFormatTypeUserData(String userData1, String userData2) {
+        return String.format("%s\n\n%s", userData1, userData2.substring(userData2.indexOf('\n')+1));
+    }
+
+    private void checkGzipAppend(String encodedUserData1, String encodedUserData2) {
+        if (isGZipped(encodedUserData1) || isGZipped(encodedUserData2)) {
+            throw new CloudRuntimeException("Gzipped user data can not be used together with other user data formats");
+        }
+    }
+
+    @Override
+    public String appendUserData(String encodedUserData1, String encodedUserData2) {
+        try {
+            checkGzipAppend(encodedUserData1, encodedUserData2);
+            String userData1 = new String(Base64.decodeBase64(encodedUserData1));
+            String userData2 = new String(Base64.decodeBase64(encodedUserData2));
+            FormatType formatType1 = getUserDataFormatType(userData1);
+            FormatType formatType2 = getUserDataFormatType(userData2);
+            if (formatType1.equals(formatType2) && List.of(FormatType.CLOUD_CONFIG, FormatType.BASH_SCRIPT).contains(formatType1)) {
+                return simpleAppendSameFormatTypeUserData(userData1, userData2);
+            }
+            NoIdMimeMessage message = new NoIdMimeMessage(session);
+            message = createMultipartMessageAddingUserdata(userData1, formatType1, message);
+            message = createMultipartMessageAddingUserdata(userData2, formatType2, message);
+            ByteArrayOutputStream output = new ByteArrayOutputStream();
+            message.writeTo(output);
+            return output.toString();
+        } catch (MessagingException | IOException | CloudRuntimeException e) {
+            String msg = String.format("Error attempting to merge user data as a multipart user data. " +
+                    "Reason: %s", e.getMessage());
+            LOGGER.error(msg, e);
+            throw new CloudRuntimeException(msg, e);
+        }
+    }
+
+    /* This is a wrapper class just to remove Message-ID header from the resultant
+       multipart data which may contain server details.
+     */
+    private class NoIdMimeMessage extends MimeMessage {
+        NoIdMimeMessage (Session session) {
+            super(session);
+        }
+        NoIdMimeMessage (Session session, InputStream is) throws MessagingException {
+            super(session, is);
+        }
+        @Override
+        protected void updateMessageID() throws MessagingException {
+            removeHeader("Message-ID");
+        }
+    }
+}
diff --git a/engine/userdata/cloud-init/src/main/resources/META-INF/cloudstack/core/spring-userdata-cloud-init-context.xml b/engine/userdata/cloud-init/src/main/resources/META-INF/cloudstack/core/spring-userdata-cloud-init-context.xml
new file mode 100644
index 0000000..742398e
--- /dev/null
+++ b/engine/userdata/cloud-init/src/main/resources/META-INF/cloudstack/core/spring-userdata-cloud-init-context.xml
@@ -0,0 +1,27 @@
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
+>
+    <bean id="cloudInitUserDataProvider" class="org.apache.cloudstack.userdata.CloudInitUserDataProvider">
+        <property name="name" value="cloud-init" />
+    </bean>
+</beans>
diff --git a/engine/userdata/cloud-init/src/test/java/org/apache/cloudstack/userdata/CloudInitUserDataProviderTest.java b/engine/userdata/cloud-init/src/test/java/org/apache/cloudstack/userdata/CloudInitUserDataProviderTest.java
new file mode 100644
index 0000000..4ca9fb7
--- /dev/null
+++ b/engine/userdata/cloud-init/src/test/java/org/apache/cloudstack/userdata/CloudInitUserDataProviderTest.java
@@ -0,0 +1,206 @@
+// 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.userdata;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Properties;
+import java.util.zip.GZIPOutputStream;
+
+import javax.mail.BodyPart;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import org.apache.commons.codec.binary.Base64;
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class CloudInitUserDataProviderTest {
+
+    private final CloudInitUserDataProvider provider = new CloudInitUserDataProvider();
+    private final static String CLOUD_CONFIG_USERDATA = "## template: jinja\n" +
+            "#cloud-config\n" +
+            "runcmd:\n" +
+            "   - echo 'TestVariable {{ ds.meta_data.variable1 }}' >> /tmp/variable\n" +
+            "   - echo 'Hostname {{ ds.meta_data.public_hostname }}' > /tmp/hostname";
+    private final static String CLOUD_CONFIG_USERDATA1 = "#cloud-config\n" +
+            "password: atomic\n" +
+            "chpasswd: { expire: False }\n" +
+            "ssh_pwauth: True";
+    private final static String SHELL_SCRIPT_USERDATA = "#!/bin/bash\n" +
+            "date > /provisioned";
+    private final static String SHELL_SCRIPT_USERDATA1 = "#!/bin/bash\n" +
+            "mkdir /tmp/test";
+    private final static String SINGLE_BODYPART_CLOUDCONFIG_MULTIPART_USERDATA =
+            "Content-Type: multipart/mixed; boundary=\"//\"\n" +
+            "MIME-Version: 1.0\n" +
+            "\n" +
+            "--//\n" +
+            "Content-Type: text/cloud-config; charset=\"us-ascii\"\n" +
+            "MIME-Version: 1.0\n" +
+            "Content-Transfer-Encoding: 7bit\n" +
+            "Content-Disposition: attachment; filename=\"cloud-config.txt\"\n" +
+            "\n" +
+            "#cloud-config\n" +
+            "\n" +
+            "# Upgrade the instance on first boot\n" +
+            "# (ie run apt-get upgrade)\n" +
+            "#\n" +
+            "# Default: false\n" +
+            "# Aliases: apt_upgrade\n" +
+            "package_upgrade: true";
+    private static final Session session = Session.getDefaultInstance(new Properties());
+
+    @Test
+    public void testGetUserDataFormatType() {
+        CloudInitUserDataProvider.FormatType type = provider.getUserDataFormatType(CLOUD_CONFIG_USERDATA);
+        Assert.assertEquals(CloudInitUserDataProvider.FormatType.CLOUD_CONFIG, type);
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void testGetUserDataFormatTypeNoHeader() {
+        String userdata = "password: password\nchpasswd: { expire: False }\nssh_pwauth: True";
+        provider.getUserDataFormatType(userdata);
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void testGetUserDataFormatTypeInvalidType() {
+        String userdata = "#invalid-type\n" +
+                "password: password\nchpasswd: { expire: False }\nssh_pwauth: True";
+        provider.getUserDataFormatType(userdata);
+    }
+
+    private MimeMultipart getCheckedMultipartFromMultipartData(String multipartUserData, int count) {
+        MimeMultipart multipart = null;
+        Assert.assertTrue(multipartUserData.contains("Content-Type: multipart"));
+        try {
+            MimeMessage msgFromUserdata = new MimeMessage(session,
+                    new ByteArrayInputStream(multipartUserData.getBytes()));
+            multipart = (MimeMultipart)msgFromUserdata.getContent();
+            Assert.assertEquals(count, multipart.getCount());
+        } catch (MessagingException | IOException e) {
+            Assert.fail(String.format("Failed with exception, %s", e.getMessage()));
+        }
+        return multipart;
+    }
+
+    @Test
+    public void testAppendUserData() {
+        String multipartUserData = provider.appendUserData(Base64.encodeBase64String(CLOUD_CONFIG_USERDATA1.getBytes()),
+                Base64.encodeBase64String(SHELL_SCRIPT_USERDATA.getBytes()));
+        getCheckedMultipartFromMultipartData(multipartUserData, 2);
+    }
+
+    @Test
+    public void testAppendSameShellScriptTypeUserData() {
+        String result = SHELL_SCRIPT_USERDATA + "\n\n" +
+                SHELL_SCRIPT_USERDATA1.replace("#!/bin/bash\n", "");
+        String appendUserData = provider.appendUserData(Base64.encodeBase64String(SHELL_SCRIPT_USERDATA.getBytes()),
+                Base64.encodeBase64String(SHELL_SCRIPT_USERDATA1.getBytes()));
+        Assert.assertEquals(result, appendUserData);
+    }
+
+    @Test
+    public void testAppendSameCloudConfigTypeUserData() {
+        String result = CLOUD_CONFIG_USERDATA + "\n\n" +
+                CLOUD_CONFIG_USERDATA1.replace("#cloud-config\n", "");
+        String appendUserData = provider.appendUserData(Base64.encodeBase64String(CLOUD_CONFIG_USERDATA.getBytes()),
+                Base64.encodeBase64String(CLOUD_CONFIG_USERDATA1.getBytes()));
+        Assert.assertEquals(result, appendUserData);
+    }
+
+    @Test
+    public void testAppendUserDataMIMETemplateData() {
+        String multipartUserData = provider.appendUserData(
+                Base64.encodeBase64String(SINGLE_BODYPART_CLOUDCONFIG_MULTIPART_USERDATA.getBytes()),
+                Base64.encodeBase64String(SHELL_SCRIPT_USERDATA.getBytes()));
+        getCheckedMultipartFromMultipartData(multipartUserData, 2);
+    }
+
+    @Test
+    public void testAppendUserDataExistingMultipartWithSameType() {
+        String templateData = provider.appendUserData(Base64.encodeBase64String(CLOUD_CONFIG_USERDATA1.getBytes()),
+                Base64.encodeBase64String(SHELL_SCRIPT_USERDATA.getBytes()));
+        String multipartUserData = provider.appendUserData(Base64.encodeBase64String(templateData.getBytes()),
+                Base64.encodeBase64String(SHELL_SCRIPT_USERDATA1.getBytes()));
+        String resultantShellScript = SHELL_SCRIPT_USERDATA + "\n\n" +
+                SHELL_SCRIPT_USERDATA1.replace("#!/bin/bash\n", "");
+        MimeMultipart mimeMultipart = getCheckedMultipartFromMultipartData(multipartUserData, 2);
+        try {
+            for (int i = 0; i < mimeMultipart.getCount(); ++i) {
+                BodyPart bodyPart = mimeMultipart.getBodyPart(i);
+                if (bodyPart.getContentType().startsWith("text/x-shellscript")) {
+                    Assert.assertEquals(resultantShellScript, provider.getBodyPartContentAsString(bodyPart));
+                } else if (bodyPart.getContentType().startsWith("text/cloud-config")) {
+                    Assert.assertEquals(CLOUD_CONFIG_USERDATA1, provider.getBodyPartContentAsString(bodyPart));
+                }
+            }
+        } catch (MessagingException | IOException | CloudRuntimeException e) {
+            Assert.fail(String.format("Failed with exception, %s", e.getMessage()));
+        }
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void testAppendUserDataInvalidUserData() {
+        String templateData = CLOUD_CONFIG_USERDATA1.replace("#cloud-config\n", "");
+        provider.appendUserData(Base64.encodeBase64String(templateData.getBytes()),
+                Base64.encodeBase64String(SHELL_SCRIPT_USERDATA.getBytes()));
+    }
+
+    @Test
+    public void testIsGzippedUserDataWithCloudConfigData() {
+        Assert.assertFalse(provider.isGZipped(CLOUD_CONFIG_USERDATA));
+    }
+
+    private String createBase64EncodedGzipDataAsString() throws IOException {
+        byte[] input = CLOUD_CONFIG_USERDATA.getBytes(StandardCharsets.ISO_8859_1);
+
+        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
+        GZIPOutputStream outputStream = new GZIPOutputStream(arrayOutputStream);
+        outputStream.write(input,0, input.length);
+        outputStream.close();
+
+        return Base64.encodeBase64String(arrayOutputStream.toByteArray());
+    }
+
+    @Test
+    public void testIsGzippedUserDataWithValidGzipData() {
+        try {
+            String gzipped = createBase64EncodedGzipDataAsString();
+            Assert.assertTrue(provider.isGZipped(gzipped));
+        } catch (IOException e) {
+            Assert.fail(e.getMessage());
+        }
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void testAppendUserDataWithGzippedData() {
+        try {
+            provider.appendUserData(Base64.encodeBase64String(CLOUD_CONFIG_USERDATA.getBytes()),
+                    createBase64EncodedGzipDataAsString());
+            Assert.fail("Gzipped data shouldn't be appended with other data");
+        } catch (IOException e) {
+            Assert.fail("Exception encountered: " + e.getMessage());
+        }
+    }
+}
diff --git a/engine/userdata/pom.xml b/engine/userdata/pom.xml
new file mode 100644
index 0000000..75475b2
--- /dev/null
+++ b/engine/userdata/pom.xml
@@ -0,0 +1,53 @@
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>cloud-engine-userdata</artifactId>
+    <name>Apache CloudStack Engine Userdata Component</name>
+    <parent>
+        <groupId>org.apache.cloudstack</groupId>
+        <artifactId>cloud-engine</artifactId>
+        <version>4.19.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.cloudstack</groupId>
+            <artifactId>cloud-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cloudstack</groupId>
+            <artifactId>cloud-utils</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.activation</groupId>
+            <artifactId>activation</artifactId>
+            <version>1.1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cloudstack</groupId>
+            <artifactId>cloud-engine-components-api</artifactId>
+            <version>4.19.0.0-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/engine/userdata/src/main/java/org/apache/cloudstack/userdata/UserDataManagerImpl.java b/engine/userdata/src/main/java/org/apache/cloudstack/userdata/UserDataManagerImpl.java
new file mode 100644
index 0000000..91f24fe
--- /dev/null
+++ b/engine/userdata/src/main/java/org/apache/cloudstack/userdata/UserDataManagerImpl.java
@@ -0,0 +1,138 @@
+// 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.userdata;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.StringUtils;
+
+import com.cloud.configuration.ConfigurationManager;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.utils.component.ManagerBase;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class UserDataManagerImpl extends ManagerBase implements UserDataManager {
+
+
+    private static final int MAX_USER_DATA_LENGTH_BYTES = 2048;
+    private static final int MAX_HTTP_GET_LENGTH = 2 * MAX_USER_DATA_LENGTH_BYTES;
+    private static final int NUM_OF_2K_BLOCKS = 512;
+    private static final int MAX_HTTP_POST_LENGTH = NUM_OF_2K_BLOCKS * MAX_USER_DATA_LENGTH_BYTES;
+    private List<UserDataProvider> userDataProviders;
+    private static Map<String, UserDataProvider> userDataProvidersMap = new HashMap<>();
+
+    public void setUserDataProviders(final List<UserDataProvider> userDataProviders) {
+        this.userDataProviders = userDataProviders;
+    }
+
+    private void initializeUserdataProvidersMap() {
+        if (userDataProviders != null) {
+            for (final UserDataProvider provider : userDataProviders) {
+                userDataProvidersMap.put(provider.getName().toLowerCase(), provider);
+            }
+        }
+    }
+
+    @Override
+    public boolean start() {
+        initializeUserdataProvidersMap();
+        return true;
+    }
+
+    @Override
+    public String getConfigComponentName() {
+        return UserDataManagerImpl.class.getSimpleName();
+    }
+
+    @Override
+    public ConfigKey<?>[] getConfigKeys() {
+        return new ConfigKey[] {};
+    }
+
+    protected UserDataProvider getUserdataProvider(String name) {
+        if (StringUtils.isEmpty(name)) {
+            // Use cloud-init as the default userdata provider
+            name = "cloud-init";
+        }
+        if (!userDataProvidersMap.containsKey(name)) {
+            throw new CloudRuntimeException("Failed to find userdata provider by the name: " + name);
+        }
+        return userDataProvidersMap.get(name);
+    }
+
+    @Override
+    public String concatenateUserData(String userdata1, String userdata2, String userdataProvider) {
+        UserDataProvider provider = getUserdataProvider(userdataProvider);
+        String appendUserData = provider.appendUserData(userdata1, userdata2);
+        return Base64.encodeBase64String(appendUserData.getBytes());
+    }
+
+    @Override
+    public String validateUserData(String userData, BaseCmd.HTTPMethod httpmethod) {
+        byte[] decodedUserData = null;
+        if (userData != null) {
+
+            if (userData.contains("%")) {
+                try {
+                    userData = URLDecoder.decode(userData, "UTF-8");
+                } catch (UnsupportedEncodingException e) {
+                    throw new InvalidParameterValueException("Url decoding of userdata failed.");
+                }
+            }
+
+            if (!Base64.isBase64(userData)) {
+                throw new InvalidParameterValueException("User data is not base64 encoded");
+            }
+            // If GET, use 4K. If POST, support up to 1M.
+            if (httpmethod.equals(BaseCmd.HTTPMethod.GET)) {
+                decodedUserData = validateAndDecodeByHTTPMethod(userData, MAX_HTTP_GET_LENGTH, BaseCmd.HTTPMethod.GET);
+            } else if (httpmethod.equals(BaseCmd.HTTPMethod.POST)) {
+                decodedUserData = validateAndDecodeByHTTPMethod(userData, MAX_HTTP_POST_LENGTH, BaseCmd.HTTPMethod.POST);
+            }
+
+            if (decodedUserData == null || decodedUserData.length < 1) {
+                throw new InvalidParameterValueException("User data is too short");
+            }
+            // Re-encode so that the '=' paddings are added if necessary since 'isBase64' does not require it, but python does on the VR.
+            return Base64.encodeBase64String(decodedUserData);
+        }
+        return null;
+    }
+
+    private byte[] validateAndDecodeByHTTPMethod(String userData, int maxHTTPLength, BaseCmd.HTTPMethod httpMethod) {
+        byte[] decodedUserData = null;
+
+        if (userData.length() >= maxHTTPLength) {
+            throw new InvalidParameterValueException(String.format("User data is too long for an http %s request", httpMethod.toString()));
+        }
+        if (userData.length() > ConfigurationManager.VM_USERDATA_MAX_LENGTH.value()) {
+            throw new InvalidParameterValueException("User data has exceeded configurable max length : " + ConfigurationManager.VM_USERDATA_MAX_LENGTH.value());
+        }
+        decodedUserData = Base64.decodeBase64(userData.getBytes());
+        if (decodedUserData.length > maxHTTPLength) {
+            throw new InvalidParameterValueException(String.format("User data is too long for http %s request", httpMethod.toString()));
+        }
+        return decodedUserData;
+    }
+}
diff --git a/engine/userdata/src/main/java/org/apache/cloudstack/userdata/UserDataProvider.java b/engine/userdata/src/main/java/org/apache/cloudstack/userdata/UserDataProvider.java
new file mode 100644
index 0000000..4cdcd51
--- /dev/null
+++ b/engine/userdata/src/main/java/org/apache/cloudstack/userdata/UserDataProvider.java
@@ -0,0 +1,28 @@
+// 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.userdata;
+
+public interface UserDataProvider {
+    String getName();
+
+    /**
+     * Append user data into a single user data.
+     * NOTE: userData1 and userData2 are Base64 encoded user data strings
+     * @return a non-encrypted string containing both user data inputs
+     */
+    String appendUserData(String encodedUserData1, String encodedUserData2);
+}
diff --git a/engine/userdata/src/main/resources/META-INF/cloudstack/core/spring-engine-userdata-core-context.xml b/engine/userdata/src/main/resources/META-INF/cloudstack/core/spring-engine-userdata-core-context.xml
new file mode 100644
index 0000000..0d4c647
--- /dev/null
+++ b/engine/userdata/src/main/resources/META-INF/cloudstack/core/spring-engine-userdata-core-context.xml
@@ -0,0 +1,34 @@
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:aop="http://www.springframework.org/schema/aop"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd
+                      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
+                      http://www.springframework.org/schema/context
+                      http://www.springframework.org/schema/context/spring-context.xsd"
+                      >
+
+    <bean id="userDataManager" class="org.apache.cloudstack.userdata.UserDataManagerImpl">
+        <property name="userDataProviders" value="#{userDataProvidersRegistry.registered}" />
+    </bean>
+ 
+</beans>
diff --git a/engine/userdata/src/test/java/org/apache/cloudstack/userdata/UserDataManagerImplTest.java b/engine/userdata/src/test/java/org/apache/cloudstack/userdata/UserDataManagerImplTest.java
new file mode 100644
index 0000000..67e7b38
--- /dev/null
+++ b/engine/userdata/src/test/java/org/apache/cloudstack/userdata/UserDataManagerImplTest.java
@@ -0,0 +1,59 @@
+// 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.userdata;
+
+import static org.junit.Assert.assertEquals;
+
+import java.nio.charset.StandardCharsets;
+
+import org.apache.cloudstack.api.BaseCmd;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class UserDataManagerImplTest {
+
+    @Spy
+    @InjectMocks
+    private UserDataManagerImpl userDataManager;
+
+    @Test
+    public void testValidateBase64WithoutPadding() {
+        // fo should be encoded in base64 either as Zm8 or Zm8=
+        String encodedUserdata = "Zm8";
+        String encodedUserdataWithPadding = "Zm8=";
+
+        // Verify that we accept both but return the padded version
+        assertEquals("validate return the value with padding", encodedUserdataWithPadding, userDataManager.validateUserData(encodedUserdata, BaseCmd.HTTPMethod.GET));
+        assertEquals("validate return the value with padding", encodedUserdataWithPadding, userDataManager.validateUserData(encodedUserdataWithPadding, BaseCmd.HTTPMethod.GET));
+    }
+
+    @Test
+    public void testValidateUrlEncodedBase64() {
+        // fo should be encoded in base64 either as Zm8 or Zm8=
+        String encodedUserdata = "Zm+8/w8=";
+        String urlEncodedUserdata = java.net.URLEncoder.encode(encodedUserdata, StandardCharsets.UTF_8);
+
+        // Verify that we accept both but return the padded version
+        assertEquals("validate return the value with padding", encodedUserdata, userDataManager.validateUserData(encodedUserdata, BaseCmd.HTTPMethod.GET));
+        assertEquals("validate return the value with padding", encodedUserdata, userDataManager.validateUserData(urlEncodedUserdata, BaseCmd.HTTPMethod.GET));
+    }
+
+}
diff --git a/framework/agent-lb/pom.xml b/framework/agent-lb/pom.xml
index 6737a4f..db75099 100644
--- a/framework/agent-lb/pom.xml
+++ b/framework/agent-lb/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <artifactId>cloudstack-framework</artifactId>
         <groupId>org.apache.cloudstack</groupId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/framework/ca/pom.xml b/framework/ca/pom.xml
index c49aea0..9e1cffc 100644
--- a/framework/ca/pom.xml
+++ b/framework/ca/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-framework</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/framework/cluster/pom.xml b/framework/cluster/pom.xml
index 3d891f1..7cb8334 100644
--- a/framework/cluster/pom.xml
+++ b/framework/cluster/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-framework</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/framework/cluster/src/main/java/com/cloud/cluster/ManagementServerHostVO.java b/framework/cluster/src/main/java/com/cloud/cluster/ManagementServerHostVO.java
index 121b939..2918ccd 100644
--- a/framework/cluster/src/main/java/com/cloud/cluster/ManagementServerHostVO.java
+++ b/framework/cluster/src/main/java/com/cloud/cluster/ManagementServerHostVO.java
@@ -125,6 +125,11 @@
     }
 
     @Override
+    public Class<?> getEntityType() {
+        return ManagementServerHost.class;
+    }
+
+    @Override
     public String getName() {
         return name;
     }
@@ -196,4 +201,14 @@
     public String toString() {
         return new StringBuilder("ManagementServer[").append("-").append(id).append("-").append(msid).append("-").append(state).append("]").toString();
     }
+
+    @Override
+    public long getDomainId() {
+        return 1L;
+    }
+
+    @Override
+    public long getAccountId() {
+        return 1L;
+    }
 }
diff --git a/framework/config/pom.xml b/framework/config/pom.xml
index d49eef4..7805869 100644
--- a/framework/config/pom.xml
+++ b/framework/config/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-framework</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/framework/db/pom.xml b/framework/db/pom.xml
index 73e304c..c3f99ae 100644
--- a/framework/db/pom.xml
+++ b/framework/db/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-framework</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/framework/db/src/test/resources/db.properties b/framework/db/src/test/resources/db.properties
index e3a5d22..bb7c398 100644
--- a/framework/db/src/test/resources/db.properties
+++ b/framework/db/src/test/resources/db.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 
-# Just here to make the unit test not blow up
\ No newline at end of file
+# Just here to make the unit test not blow up
diff --git a/framework/direct-download/pom.xml b/framework/direct-download/pom.xml
index 13c00b6..4a2dfb4 100644
--- a/framework/direct-download/pom.xml
+++ b/framework/direct-download/pom.xml
@@ -25,14 +25,14 @@
         <dependency>
             <groupId>org.apache.cloudstack</groupId>
             <artifactId>cloud-utils</artifactId>
-            <version>4.18.1.0-SNAPSHOT</version>
+            <version>4.19.0.0-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
     </dependencies>
     <parent>
         <artifactId>cloudstack-framework</artifactId>
         <groupId>org.apache.cloudstack</groupId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
-</project>
\ No newline at end of file
+</project>
diff --git a/framework/events/pom.xml b/framework/events/pom.xml
index 91023e6..050c445 100644
--- a/framework/events/pom.xml
+++ b/framework/events/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-framework</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/framework/ipc/pom.xml b/framework/ipc/pom.xml
index 05a18ba..02b508b 100644
--- a/framework/ipc/pom.xml
+++ b/framework/ipc/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-framework</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/framework/ipc/src/main/java/org/apache/cloudstack/framework/messagebus/MessageDetector.java b/framework/ipc/src/main/java/org/apache/cloudstack/framework/messagebus/MessageDetector.java
index c771d6b..4bcf9b1 100644
--- a/framework/ipc/src/main/java/org/apache/cloudstack/framework/messagebus/MessageDetector.java
+++ b/framework/ipc/src/main/java/org/apache/cloudstack/framework/messagebus/MessageDetector.java
@@ -31,15 +31,15 @@
         _subjects = null;
     }
 
-    public void waitAny(long timeoutInMiliseconds) {
-        if (timeoutInMiliseconds < 100) {
-            s_logger.warn("waitAny is passed with a too short time-out interval. " + timeoutInMiliseconds + "ms");
-            timeoutInMiliseconds = 100;
+    public void waitAny(long timeoutInMilliseconds) {
+        if (timeoutInMilliseconds < 100) {
+            s_logger.warn("waitAny is passed with a too short time-out interval. " + timeoutInMilliseconds + "ms");
+            timeoutInMilliseconds = 100;
         }
 
         synchronized (this) {
             try {
-                wait(timeoutInMiliseconds);
+                wait(timeoutInMilliseconds);
             } catch (InterruptedException e) {
                 s_logger.debug("[ignored] interrupted while waiting on any message.");
             }
diff --git a/framework/ipc/src/main/resources/META-INF/cloudstack/core/spring-framework-ipc-core-context.xml b/framework/ipc/src/main/resources/META-INF/cloudstack/core/spring-framework-ipc-core-context.xml
index 15b6f80..926a84a 100644
--- a/framework/ipc/src/main/resources/META-INF/cloudstack/core/spring-framework-ipc-core-context.xml
+++ b/framework/ipc/src/main/resources/META-INF/cloudstack/core/spring-framework-ipc-core-context.xml
@@ -56,4 +56,4 @@
 
   <bean id="messageBus" class = "org.apache.cloudstack.framework.messagebus.MessageBusBase" />
 
-</beans>
\ No newline at end of file
+</beans>
diff --git a/framework/jobs/pom.xml b/framework/jobs/pom.xml
index a3d6b14..b00875e 100644
--- a/framework/jobs/pom.xml
+++ b/framework/jobs/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-framework</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/AsyncJob.java b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/AsyncJob.java
index b8200bf..bde9b4a 100644
--- a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/AsyncJob.java
+++ b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/AsyncJob.java
@@ -90,6 +90,8 @@
     @Override
     Long getExecutingMsid();
 
+    void setExecutingMsid(Long msid);
+
     @Override
     Long getCompleteMsid();
 
diff --git a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/AsyncJobManager.java b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/AsyncJobManager.java
index 8542407..9f50a54 100644
--- a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/AsyncJobManager.java
+++ b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/AsyncJobManager.java
@@ -117,12 +117,12 @@
      *
      * @param wakupTopicsOnMessageBus topic on message bus to wakeup the wait
      * @param checkIntervalInMilliSeconds time to break out wait for checking predicate condition
-     * @param timeoutInMiliseconds time out to break out the whole wait process
+     * @param timeoutInMilliseconds time out to break out the whole wait process
      * @param predicate
      * @return true, predicate condition is satisfied
      *             false, wait is timed out
      */
-    boolean waitAndCheck(AsyncJob job, String[] wakupTopicsOnMessageBus, long checkIntervalInMilliSeconds, long timeoutInMiliseconds, Predicate predicate);
+    boolean waitAndCheck(AsyncJob job, String[] wakupTopicsOnMessageBus, long checkIntervalInMilliSeconds, long timeoutInMilliseconds, Predicate predicate);
 
     AsyncJob queryJob(long jobId, boolean updatePollTime);
 
@@ -133,4 +133,14 @@
     List<AsyncJobVO> findFailureAsyncJobs(String... cmds);
 
     long countPendingJobs(String havingInfo, String... cmds);
+
+    // Returns the number of pending jobs for the given Management server msids.
+    // NOTE: This is the msid and NOT the id
+    long countPendingNonPseudoJobs(Long... msIds);
+
+    void enableAsyncJobs();
+
+    void disableAsyncJobs();
+
+    boolean isAsyncJobsEnabled();
 }
diff --git a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobDao.java b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobDao.java
index 2696e10..9f7a4ad 100644
--- a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobDao.java
+++ b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobDao.java
@@ -46,4 +46,8 @@
     List<AsyncJobVO> getFailureJobsSinceLastMsStart(long msId, String... cmds);
 
     long countPendingJobs(String havingInfo, String... cmds);
+
+    // Returns the number of pending jobs for the given Management server msids.
+    // NOTE: This is the msid and NOT the id
+    long countPendingNonPseudoJobs(Long... msIds);
 }
diff --git a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobDaoImpl.java b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobDaoImpl.java
index 7dd7343..1914ff7 100644
--- a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobDaoImpl.java
+++ b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobDaoImpl.java
@@ -48,6 +48,7 @@
     private final SearchBuilder<AsyncJobVO> expiringCompletedAsyncJobSearch;
     private final SearchBuilder<AsyncJobVO> failureMsidAsyncJobSearch;
     private final GenericSearchBuilder<AsyncJobVO, Long> asyncJobTypeSearch;
+    private final GenericSearchBuilder<AsyncJobVO, Long> pendingNonPseudoAsyncJobsSearch;
 
     public AsyncJobDaoImpl() {
         pendingAsyncJobSearch = createSearchBuilder();
@@ -103,6 +104,11 @@
         asyncJobTypeSearch.and("status", asyncJobTypeSearch.entity().getStatus(), SearchCriteria.Op.EQ);
         asyncJobTypeSearch.done();
 
+        pendingNonPseudoAsyncJobsSearch = createSearchBuilder(Long.class);
+        pendingNonPseudoAsyncJobsSearch.select(null, SearchCriteria.Func.COUNT, pendingNonPseudoAsyncJobsSearch.entity().getId());
+        pendingNonPseudoAsyncJobsSearch.and("instanceTypeNEQ", pendingNonPseudoAsyncJobsSearch.entity().getInstanceType(), SearchCriteria.Op.NEQ);
+        pendingNonPseudoAsyncJobsSearch.and("jobStatusEQ", pendingNonPseudoAsyncJobsSearch.entity().getStatus(), SearchCriteria.Op.EQ);
+        pendingNonPseudoAsyncJobsSearch.and("executingMsidIN", pendingNonPseudoAsyncJobsSearch.entity().getExecutingMsid(), SearchCriteria.Op.IN);
     }
 
     @Override
@@ -237,6 +243,20 @@
         return listBy(sc);
     }
 
+    // Returns the number of pending jobs for the given Management server msids.
+    // NOTE: This is the msid and NOT the id
+    @Override
+    public long countPendingNonPseudoJobs(Long... msIds) {
+        SearchCriteria<Long> sc = pendingNonPseudoAsyncJobsSearch.create();
+        sc.setParameters("instanceTypeNEQ", AsyncJobVO.PSEUDO_JOB_INSTANCE_TYPE);
+        sc.setParameters("jobStatusEQ", JobInfo.Status.IN_PROGRESS);
+        if (msIds != null) {
+            sc.setParameters("executingMsidIN", (Object[])msIds);
+        }
+        List<Long> results = customSearch(sc, null);
+        return results.get(0);
+    }
+
     @Override
     public long countPendingJobs(String havingInfo, String... cmds) {
         SearchCriteria<Long> sc = asyncJobTypeSearch.create();
diff --git a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java
index a963357..15fe75b 100644
--- a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java
+++ b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java
@@ -64,6 +64,7 @@
 
 import com.cloud.cluster.ClusterManagerListener;
 import org.apache.cloudstack.management.ManagementServerHost;
+
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Snapshot;
 import com.cloud.storage.dao.SnapshotDao;
@@ -155,6 +156,8 @@
     private ExecutorService _apiJobExecutor;
     private ExecutorService _workerJobExecutor;
 
+    private boolean asyncJobsEnabled = true;
+
     @Override
     public String getConfigComponentName() {
         return AsyncJobManager.class.getSimpleName();
@@ -197,12 +200,21 @@
         return submitAsyncJob(job, false);
     }
 
+    private void checkShutdown() {
+        if (!isAsyncJobsEnabled()) {
+            throw new CloudRuntimeException("A shutdown has been triggered. Can not accept new jobs");
+        }
+    }
+
     @SuppressWarnings("unchecked")
     @DB
     public long submitAsyncJob(AsyncJob job, boolean scheduleJobExecutionInContext) {
+        checkShutdown();
+
         @SuppressWarnings("rawtypes")
         GenericDao dao = GenericDaoBase.getDao(job.getClass());
         job.setInitMsid(getMsid());
+        job.setExecutingMsid(getMsid());
         job.setSyncSource(null);        // no sync source originally
         dao.persist(job);
 
@@ -218,6 +230,8 @@
     @Override
     @DB
     public long submitAsyncJob(final AsyncJob job, final String syncObjType, final long syncObjId) {
+        checkShutdown();
+
         try {
             @SuppressWarnings("rawtypes")
             final GenericDao dao = GenericDaoBase.getDao(job.getClass());
@@ -744,7 +758,7 @@
     }
 
     @Override
-    public boolean waitAndCheck(AsyncJob job, String[] wakeupTopicsOnMessageBus, long checkIntervalInMilliSeconds, long timeoutInMiliseconds, Predicate predicate) {
+    public boolean waitAndCheck(AsyncJob job, String[] wakeupTopicsOnMessageBus, long checkIntervalInMilliSeconds, long timeoutInMilliseconds, Predicate predicate) {
 
         MessageDetector msgDetector = new MessageDetector();
         String[] topics = Arrays.copyOf(wakeupTopicsOnMessageBus, wakeupTopicsOnMessageBus.length + 1);
@@ -753,7 +767,7 @@
         msgDetector.open(_messageBus, topics);
         try {
             long startTick = System.currentTimeMillis();
-            while (timeoutInMiliseconds < 0 || System.currentTimeMillis() - startTick < timeoutInMiliseconds) {
+            while (timeoutInMilliseconds < 0 || System.currentTimeMillis() - startTick < timeoutInMilliseconds) {
                 msgDetector.waitAny(checkIntervalInMilliSeconds);
                 job = _jobDao.findById(job.getId());
                 if (job != null && job.getStatus().done()) {
@@ -827,6 +841,11 @@
 
             protected void reallyRun() {
                 try {
+                    if (!isAsyncJobsEnabled()) {
+                        s_logger.info("A shutdown has been triggered. Not executing any async job");
+                        return;
+                    }
+
                     List<SyncQueueItemVO> l = _queueMgr.dequeueFromAny(getMsid(), MAX_ONETIME_SCHEDULE_SIZE);
                     if (l != null && l.size() > 0) {
                         for (SyncQueueItemVO item : l) {
@@ -1171,4 +1190,26 @@
     public long countPendingJobs(String havingInfo, String... cmds) {
         return _jobDao.countPendingJobs(havingInfo, cmds);
     }
+
+    // Returns the number of pending jobs for the given Management server msids.
+    // NOTE: This is the msid and NOT the id
+    @Override
+    public long countPendingNonPseudoJobs(Long... msIds) {
+    return _jobDao.countPendingNonPseudoJobs(msIds);
+    }
+
+    @Override
+    public void enableAsyncJobs() {
+        this.asyncJobsEnabled = true;
+    }
+
+    @Override
+    public void disableAsyncJobs() {
+        this.asyncJobsEnabled = false;
+    }
+
+    @Override
+    public boolean isAsyncJobsEnabled() {
+        return asyncJobsEnabled;
+    }
 }
diff --git a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobVO.java b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobVO.java
index 8f3c033..6b85ae2 100644
--- a/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobVO.java
+++ b/framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobVO.java
@@ -294,6 +294,7 @@
         return executingMsid;
     }
 
+    @Override
     public void setExecutingMsid(Long executingMsid) {
         this.executingMsid = executingMsid;
     }
diff --git a/framework/jobs/src/test/resources/log4j.properties b/framework/jobs/src/test/resources/log4j.properties
index fdf675a..7ffdca8 100644
--- a/framework/jobs/src/test/resources/log4j.properties
+++ b/framework/jobs/src/test/resources/log4j.properties
@@ -32,4 +32,3 @@
 #log4j.category.com.cloud.utils.db.Transaction=ALL
 log4j.category.org.apache.cloudstack.network.contrail=ALL
 log4j.category.com.cloud.network=ALL
-
diff --git a/framework/managed-context/pom.xml b/framework/managed-context/pom.xml
index c4cfeed..b8ac33e 100644
--- a/framework/managed-context/pom.xml
+++ b/framework/managed-context/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/framework/pom.xml b/framework/pom.xml
index 226a3c1..679796c 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
     </parent>
     <build>
         <plugins>
diff --git a/framework/quota/pom.xml b/framework/quota/pom.xml
index 1ad07c4..437577f 100644
--- a/framework/quota/pom.xml
+++ b/framework/quota/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-framework</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/framework/rest/pom.xml b/framework/rest/pom.xml
index 04a6130..5895ce0 100644
--- a/framework/rest/pom.xml
+++ b/framework/rest/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-framework</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>cloud-framework-rest</artifactId>
diff --git a/framework/security/pom.xml b/framework/security/pom.xml
index 7a83cf5..956b1f9 100644
--- a/framework/security/pom.xml
+++ b/framework/security/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-framework</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/framework/spring/lifecycle/pom.xml b/framework/spring/lifecycle/pom.xml
index da74ff2..b27c583 100644
--- a/framework/spring/lifecycle/pom.xml
+++ b/framework/spring/lifecycle/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/framework/spring/module/pom.xml b/framework/spring/module/pom.xml
index d56fdf6..cdeb4d3 100644
--- a/framework/spring/module/pom.xml
+++ b/framework/spring/module/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/framework/spring/module/src/test/resources/testfiles/all/test2-defaults.properties b/framework/spring/module/src/test/resources/testfiles/all/test2-defaults.properties
index 2456923..13a8339 100644
--- a/framework/spring/module/src/test/resources/testfiles/all/test2-defaults.properties
+++ b/framework/spring/module/src/test/resources/testfiles/all/test2-defaults.properties
@@ -14,4 +14,3 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
diff --git a/framework/spring/module/src/test/resources/testfiles/missingname/module.properties b/framework/spring/module/src/test/resources/testfiles/missingname/module.properties
index 2456923..13a8339 100644
--- a/framework/spring/module/src/test/resources/testfiles/missingname/module.properties
+++ b/framework/spring/module/src/test/resources/testfiles/missingname/module.properties
@@ -14,4 +14,3 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-
diff --git a/framework/spring/module/src/test/resources/testhierarchy/excluded/module.properties b/framework/spring/module/src/test/resources/testhierarchy/excluded/module.properties
index 0ea382a..3088f24 100644
--- a/framework/spring/module/src/test/resources/testhierarchy/excluded/module.properties
+++ b/framework/spring/module/src/test/resources/testhierarchy/excluded/module.properties
@@ -16,4 +16,4 @@
 # under the License.
 
 name=excluded
-parent=base
\ No newline at end of file
+parent=base
diff --git a/framework/spring/module/src/test/resources/testhierarchy/excluded2/module.properties b/framework/spring/module/src/test/resources/testhierarchy/excluded2/module.properties
index e3665ee..9c1c16f 100644
--- a/framework/spring/module/src/test/resources/testhierarchy/excluded2/module.properties
+++ b/framework/spring/module/src/test/resources/testhierarchy/excluded2/module.properties
@@ -16,4 +16,4 @@
 # under the License.
 
 name=excluded2
-parent=base
\ No newline at end of file
+parent=base
diff --git a/framework/spring/module/src/test/resources/testhierarchy/orphan-of-excluded/defaults.properties b/framework/spring/module/src/test/resources/testhierarchy/orphan-of-excluded/defaults.properties
index 811d442..bf96fe6 100644
--- a/framework/spring/module/src/test/resources/testhierarchy/orphan-of-excluded/defaults.properties
+++ b/framework/spring/module/src/test/resources/testhierarchy/orphan-of-excluded/defaults.properties
@@ -17,4 +17,4 @@
 
 modules.include.excluded=false
 modules.include.base=True
-modules.exclude=excluded2,excluded2
\ No newline at end of file
+modules.exclude=excluded2,excluded2
diff --git a/framework/spring/module/src/test/resources/testhierarchy/orphan-of-excluded/module.properties b/framework/spring/module/src/test/resources/testhierarchy/orphan-of-excluded/module.properties
index 93b9186..f676150 100644
--- a/framework/spring/module/src/test/resources/testhierarchy/orphan-of-excluded/module.properties
+++ b/framework/spring/module/src/test/resources/testhierarchy/orphan-of-excluded/module.properties
@@ -16,4 +16,4 @@
 # under the License.
 
 name=orphan-of-excluded
-parent=excluded
\ No newline at end of file
+parent=excluded
diff --git a/packaging/centos7/cloud-ipallocator.rc b/packaging/centos7/cloud-ipallocator.rc
index d3eadec..255725b 100755
--- a/packaging/centos7/cloud-ipallocator.rc
+++ b/packaging/centos7/cloud-ipallocator.rc
@@ -93,4 +93,3 @@
 esac
 
 exit $RETVAL
-
diff --git a/packaging/centos7/cloud.spec b/packaging/centos7/cloud.spec
index c6ae6a6..9a1cf92 100644
--- a/packaging/centos7/cloud.spec
+++ b/packaging/centos7/cloud.spec
@@ -714,4 +714,3 @@
 
 * Fri Oct 5 2012 Hugo Trippaers <hugo@apache.org> 4.1.0
 - new style spec file
-
diff --git a/packaging/centos8/cloud-ipallocator.rc b/packaging/centos8/cloud-ipallocator.rc
index d3eadec..255725b 100755
--- a/packaging/centos8/cloud-ipallocator.rc
+++ b/packaging/centos8/cloud-ipallocator.rc
@@ -93,4 +93,3 @@
 esac
 
 exit $RETVAL
-
diff --git a/plugins/acl/dynamic-role-based/pom.xml b/plugins/acl/dynamic-role-based/pom.xml
index 3b9854e..786d69d 100644
--- a/plugins/acl/dynamic-role-based/pom.xml
+++ b/plugins/acl/dynamic-role-based/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/acl/project-role-based/pom.xml b/plugins/acl/project-role-based/pom.xml
index b673a35..fbbf688 100644
--- a/plugins/acl/project-role-based/pom.xml
+++ b/plugins/acl/project-role-based/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/acl/project-role-based/src/main/resources/META-INF/cloudstack/acl-project-role-based/module.properties b/plugins/acl/project-role-based/src/main/resources/META-INF/cloudstack/acl-project-role-based/module.properties
index 76064d4..3aa38c8 100644
--- a/plugins/acl/project-role-based/src/main/resources/META-INF/cloudstack/acl-project-role-based/module.properties
+++ b/plugins/acl/project-role-based/src/main/resources/META-INF/cloudstack/acl-project-role-based/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=acl-project-role-based
-parent=api
\ No newline at end of file
+parent=api
diff --git a/plugins/acl/project-role-based/src/main/test/java/org/apache/cloudstack/acl/ProjectRoleBasedApiAccessCheckerTest.java b/plugins/acl/project-role-based/src/test/java/org/apache/cloudstack/acl/ProjectRoleBasedApiAccessCheckerTest.java
similarity index 86%
rename from plugins/acl/project-role-based/src/main/test/java/org/apache/cloudstack/acl/ProjectRoleBasedApiAccessCheckerTest.java
rename to plugins/acl/project-role-based/src/test/java/org/apache/cloudstack/acl/ProjectRoleBasedApiAccessCheckerTest.java
index 5505975..81061d3 100644
--- a/plugins/acl/project-role-based/src/main/test/java/org/apache/cloudstack/acl/ProjectRoleBasedApiAccessCheckerTest.java
+++ b/plugins/acl/project-role-based/src/test/java/org/apache/cloudstack/acl/ProjectRoleBasedApiAccessCheckerTest.java
@@ -26,25 +26,24 @@
 import com.cloud.user.UserVO;
 
 import org.apache.cloudstack.context.CallContext;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
 import junit.framework.TestCase;
+import org.mockito.junit.MockitoJUnitRunner;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(CallContext.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ProjectRoleBasedApiAccessCheckerTest extends TestCase {
     @Mock
     ProjectAccountDao projectAccountDaoMock;
@@ -63,12 +62,21 @@
 
     List<String> apiNames = new ArrayList<>(Arrays.asList("apiName"));
 
+    MockedStatic<CallContext> callContextMocked;
+
     @Before
     public void setup() {
-
+        callContextMocked = Mockito.mockStatic(CallContext.class);
+        callContextMocked.when(CallContext::current).thenReturn(callContextMock);
         Mockito.doReturn(true).when(roleServiceMock).isEnabled();
     }
 
+    @Override
+    @After
+    public void tearDown() throws Exception {
+        callContextMocked.close();
+    }
+
     public Project getTestProject() {
         return new ProjectVO("Teste", "Teste", 1L, 1L);
     }
@@ -88,8 +96,6 @@
 
     @Test
     public void getApisAllowedToUserTestProjectIsNullShouldReturnUnchangedApiList() {
-        PowerMockito.mockStatic(CallContext.class);
-        PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
 
         Mockito.doReturn(null).when(callContextMock).getProject();
 
@@ -99,8 +105,6 @@
 
     @Test (expected = PermissionDeniedException.class)
     public void getApisAllowedToUserTestProjectAccountIsNullThrowPermissionDeniedException() {
-        PowerMockito.mockStatic(CallContext.class);
-        PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
 
         Mockito.when(callContextMock.getProject()).thenReturn(getTestProject());
         Mockito.when(projectAccountDaoMock.findByProjectIdAccountId(Mockito.anyLong(), Mockito.anyLong())).thenReturn(null);
@@ -111,8 +115,6 @@
 
     @Test
     public void getApisAllowedToUserTestProjectAccountHasAdminRoleReturnsUnchangedApiList() {
-        PowerMockito.mockStatic(CallContext.class);
-        PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
 
         Mockito.doReturn(getTestProject()).when(callContextMock).getProject();
         Mockito.doReturn(projectAccountVOMock).when(projectAccountDaoMock).findByProjectIdUserId(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong());
@@ -124,8 +126,6 @@
 
     @Test
     public void getApisAllowedToUserTestProjectAccountNotPermittedForTheApiListShouldReturnEmptyList() {
-        PowerMockito.mockStatic(CallContext.class);
-        PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
 
         Mockito.doReturn(getTestProject()).when(callContextMock).getProject();
         Mockito.doReturn(projectAccountVOMock).when(projectAccountDaoMock).findByProjectIdUserId(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong());
@@ -139,8 +139,6 @@
 
     @Test
     public void getApisAllowedToUserTestProjectAccountPermittedForTheApiListShouldReturnTheSameList() {
-        PowerMockito.mockStatic(CallContext.class);
-        PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
 
         Mockito.doReturn(getTestProject()).when(callContextMock).getProject();
         Mockito.doReturn(projectAccountVOMock).when(projectAccountDaoMock).findByProjectIdUserId(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong());
diff --git a/plugins/acl/project-role-based/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/plugins/acl/project-role-based/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d4
--- /dev/null
+++ b/plugins/acl/project-role-based/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/plugins/acl/static-role-based/pom.xml b/plugins/acl/static-role-based/pom.xml
index 937dc27..b6bb633 100644
--- a/plugins/acl/static-role-based/pom.xml
+++ b/plugins/acl/static-role-based/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/acl/static-role-based/src/main/resources/META-INF/cloudstack/acl-static-role-based/module.properties b/plugins/acl/static-role-based/src/main/resources/META-INF/cloudstack/acl-static-role-based/module.properties
index 06fc721..93ef1fa 100644
--- a/plugins/acl/static-role-based/src/main/resources/META-INF/cloudstack/acl-static-role-based/module.properties
+++ b/plugins/acl/static-role-based/src/main/resources/META-INF/cloudstack/acl-static-role-based/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=acl-static-role-based
-parent=api
\ No newline at end of file
+parent=api
diff --git a/plugins/affinity-group-processors/explicit-dedication/pom.xml b/plugins/affinity-group-processors/explicit-dedication/pom.xml
index 584ca25..870cb40 100644
--- a/plugins/affinity-group-processors/explicit-dedication/pom.xml
+++ b/plugins/affinity-group-processors/explicit-dedication/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/affinity-group-processors/explicit-dedication/src/main/resources/META-INF/cloudstack/explicit-dedication/module.properties b/plugins/affinity-group-processors/explicit-dedication/src/main/resources/META-INF/cloudstack/explicit-dedication/module.properties
index e204fe7..7c1a555 100644
--- a/plugins/affinity-group-processors/explicit-dedication/src/main/resources/META-INF/cloudstack/explicit-dedication/module.properties
+++ b/plugins/affinity-group-processors/explicit-dedication/src/main/resources/META-INF/cloudstack/explicit-dedication/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=explicit-dedication
-parent=planner
\ No newline at end of file
+parent=planner
diff --git a/plugins/affinity-group-processors/host-affinity/pom.xml b/plugins/affinity-group-processors/host-affinity/pom.xml
index 721d0c4..f30e8ba 100644
--- a/plugins/affinity-group-processors/host-affinity/pom.xml
+++ b/plugins/affinity-group-processors/host-affinity/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/affinity-group-processors/host-affinity/src/main/resources/META-INF/cloudstack/host-affinity/module.properties b/plugins/affinity-group-processors/host-affinity/src/main/resources/META-INF/cloudstack/host-affinity/module.properties
index fe0d91b..d915002 100644
--- a/plugins/affinity-group-processors/host-affinity/src/main/resources/META-INF/cloudstack/host-affinity/module.properties
+++ b/plugins/affinity-group-processors/host-affinity/src/main/resources/META-INF/cloudstack/host-affinity/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=host-affinity
-parent=planner
\ No newline at end of file
+parent=planner
diff --git a/plugins/affinity-group-processors/host-affinity/src/main/resources/META-INF/cloudstack/host-affinity/spring-host-affinity-context.xml b/plugins/affinity-group-processors/host-affinity/src/main/resources/META-INF/cloudstack/host-affinity/spring-host-affinity-context.xml
index 3d42e80..483da79 100644
--- a/plugins/affinity-group-processors/host-affinity/src/main/resources/META-INF/cloudstack/host-affinity/spring-host-affinity-context.xml
+++ b/plugins/affinity-group-processors/host-affinity/src/main/resources/META-INF/cloudstack/host-affinity/spring-host-affinity-context.xml
@@ -32,4 +32,4 @@
         <property name="name" value="HostAffinityProcessor" />
         <property name="type" value="host affinity" />
     </bean>
-</beans>
\ No newline at end of file
+</beans>
diff --git a/plugins/affinity-group-processors/host-anti-affinity/pom.xml b/plugins/affinity-group-processors/host-anti-affinity/pom.xml
index 74124fa..0e44868 100644
--- a/plugins/affinity-group-processors/host-anti-affinity/pom.xml
+++ b/plugins/affinity-group-processors/host-anti-affinity/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/affinity-group-processors/host-anti-affinity/src/main/resources/META-INF/cloudstack/host-anti-affinity/module.properties b/plugins/affinity-group-processors/host-anti-affinity/src/main/resources/META-INF/cloudstack/host-anti-affinity/module.properties
index 1ea1e84..359359d 100644
--- a/plugins/affinity-group-processors/host-anti-affinity/src/main/resources/META-INF/cloudstack/host-anti-affinity/module.properties
+++ b/plugins/affinity-group-processors/host-anti-affinity/src/main/resources/META-INF/cloudstack/host-anti-affinity/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=host-anti-affinity
-parent=planner
\ No newline at end of file
+parent=planner
diff --git a/plugins/affinity-group-processors/non-strict-host-affinity/pom.xml b/plugins/affinity-group-processors/non-strict-host-affinity/pom.xml
index 5b66d00..f6fbb9e 100644
--- a/plugins/affinity-group-processors/non-strict-host-affinity/pom.xml
+++ b/plugins/affinity-group-processors/non-strict-host-affinity/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/affinity-group-processors/non-strict-host-anti-affinity/pom.xml b/plugins/affinity-group-processors/non-strict-host-anti-affinity/pom.xml
index a0ac53a..adb4de2 100644
--- a/plugins/affinity-group-processors/non-strict-host-anti-affinity/pom.xml
+++ b/plugins/affinity-group-processors/non-strict-host-anti-affinity/pom.xml
@@ -25,14 +25,14 @@
         <dependency>
             <groupId>org.apache.cloudstack</groupId>
             <artifactId>cloud-plugin-non-strict-host-affinity</artifactId>
-            <version>4.18.1.0-SNAPSHOT</version>
+            <version>4.19.0.0-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
     </dependencies>
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/alert-handlers/snmp-alerts/pom.xml b/plugins/alert-handlers/snmp-alerts/pom.xml
index a64d1f7..04e5de2 100644
--- a/plugins/alert-handlers/snmp-alerts/pom.xml
+++ b/plugins/alert-handlers/snmp-alerts/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <artifactId>cloudstack-plugins</artifactId>
         <groupId>org.apache.cloudstack</groupId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/alert-handlers/syslog-alerts/pom.xml b/plugins/alert-handlers/syslog-alerts/pom.xml
index 41ef708..48af97b 100644
--- a/plugins/alert-handlers/syslog-alerts/pom.xml
+++ b/plugins/alert-handlers/syslog-alerts/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <artifactId>cloudstack-plugins</artifactId>
         <groupId>org.apache.cloudstack</groupId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/api/discovery/pom.xml b/plugins/api/discovery/pom.xml
index 391019b..0026c4f 100644
--- a/plugins/api/discovery/pom.xml
+++ b/plugins/api/discovery/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/api/rate-limit/pom.xml b/plugins/api/rate-limit/pom.xml
index af81331..e951fe3 100644
--- a/plugins/api/rate-limit/pom.xml
+++ b/plugins/api/rate-limit/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <build>
diff --git a/plugins/api/rate-limit/src/main/resources/META-INF/cloudstack/rate-limit/module.properties b/plugins/api/rate-limit/src/main/resources/META-INF/cloudstack/rate-limit/module.properties
index c998a87..86aa179 100644
--- a/plugins/api/rate-limit/src/main/resources/META-INF/cloudstack/rate-limit/module.properties
+++ b/plugins/api/rate-limit/src/main/resources/META-INF/cloudstack/rate-limit/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=rate-limit
-parent=api
\ No newline at end of file
+parent=api
diff --git a/plugins/api/solidfire-intg-test/pom.xml b/plugins/api/solidfire-intg-test/pom.xml
index 7baf426..f33aa33 100644
--- a/plugins/api/solidfire-intg-test/pom.xml
+++ b/plugins/api/solidfire-intg-test/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/api/solidfire-intg-test/src/main/resources/META-INF/cloudstack/solidfire-intg-test/module.properties b/plugins/api/solidfire-intg-test/src/main/resources/META-INF/cloudstack/solidfire-intg-test/module.properties
index a6460b9..3b3f2a8 100644
--- a/plugins/api/solidfire-intg-test/src/main/resources/META-INF/cloudstack/solidfire-intg-test/module.properties
+++ b/plugins/api/solidfire-intg-test/src/main/resources/META-INF/cloudstack/solidfire-intg-test/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=solidfire-intg-test
-parent=api
\ No newline at end of file
+parent=api
diff --git a/plugins/api/vmware-sioc/pom.xml b/plugins/api/vmware-sioc/pom.xml
index b9c4973..8dd0cfc 100644
--- a/plugins/api/vmware-sioc/pom.xml
+++ b/plugins/api/vmware-sioc/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/api/vmware-sioc/src/main/resources/META-INF/cloudstack/vmware-sioc/module.properties b/plugins/api/vmware-sioc/src/main/resources/META-INF/cloudstack/vmware-sioc/module.properties
index 826e644..c000d56 100644
--- a/plugins/api/vmware-sioc/src/main/resources/META-INF/cloudstack/vmware-sioc/module.properties
+++ b/plugins/api/vmware-sioc/src/main/resources/META-INF/cloudstack/vmware-sioc/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=vmware-sioc
-parent=api
\ No newline at end of file
+parent=api
diff --git a/plugins/backup/dummy/pom.xml b/plugins/backup/dummy/pom.xml
index 05cec8f..3c3d5cf 100644
--- a/plugins/backup/dummy/pom.xml
+++ b/plugins/backup/dummy/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <artifactId>cloudstack-plugins</artifactId>
         <groupId>org.apache.cloudstack</groupId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/backup/networker/pom.xml b/plugins/backup/networker/pom.xml
index 17fb70a..1672409 100644
--- a/plugins/backup/networker/pom.xml
+++ b/plugins/backup/networker/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <artifactId>cloudstack-plugins</artifactId>
         <groupId>org.apache.cloudstack</groupId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/module.properties b/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/module.properties
index 816ba25..72abf02 100644
--- a/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/module.properties
+++ b/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=networker
-parent=backup
\ No newline at end of file
+parent=backup
diff --git a/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/spring-backup-networker-context.xml b/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/spring-backup-networker-context.xml
index 271fcc7..bfe265e 100644
--- a/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/spring-backup-networker-context.xml
+++ b/plugins/backup/networker/src/main/resources/META-INF/cloudstack/networker/spring-backup-networker-context.xml
@@ -24,4 +24,3 @@
         <property name="name" value="networker"/>
     </bean>
 </beans>
-
diff --git a/plugins/backup/veeam/pom.xml b/plugins/backup/veeam/pom.xml
index e5750a2..ee59fa8 100644
--- a/plugins/backup/veeam/pom.xml
+++ b/plugins/backup/veeam/pom.xml
@@ -23,7 +23,7 @@
   <parent>
     <artifactId>cloudstack-plugins</artifactId>
     <groupId>org.apache.cloudstack</groupId>
-    <version>4.18.1.0-SNAPSHOT</version>
+    <version>4.19.0.0-SNAPSHOT</version>
     <relativePath>../../pom.xml</relativePath>
   </parent>
 
diff --git a/plugins/ca/root-ca/pom.xml b/plugins/ca/root-ca/pom.xml
index 676709b..824d423 100644
--- a/plugins/ca/root-ca/pom.xml
+++ b/plugins/ca/root-ca/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/database/mysql-ha/pom.xml b/plugins/database/mysql-ha/pom.xml
index 80cdbf0..82806f5 100644
--- a/plugins/database/mysql-ha/pom.xml
+++ b/plugins/database/mysql-ha/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/database/quota/pom.xml b/plugins/database/quota/pom.xml
index 8336f93..129f343 100644
--- a/plugins/database/quota/pom.xml
+++ b/plugins/database/quota/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/database/quota/src/test/java/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java b/plugins/database/quota/src/test/java/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java
index a02afda..b960a1b 100644
--- a/plugins/database/quota/src/test/java/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java
+++ b/plugins/database/quota/src/test/java/org/apache/cloudstack/api/response/QuotaResponseBuilderImplTest.java
@@ -52,10 +52,8 @@
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.MockedConstruction;
 import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
 
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.user.Account;
@@ -64,8 +62,9 @@
 import com.cloud.user.dao.UserDao;
 
 import junit.framework.TestCase;
+import org.mockito.junit.MockitoJUnitRunner;
 
-@RunWith(PowerMockRunner.class)
+@RunWith(MockitoJUnitRunner.class)
 public class QuotaResponseBuilderImplTest extends TestCase {
 
     @Mock
@@ -322,12 +321,13 @@
     }
 
     @Test
-    @PrepareForTest(QuotaResponseBuilderImpl.class)
     public void getNewQuotaTariffObjectTestCreateFromCurrentQuotaTariff() throws Exception {
-        PowerMockito.whenNew(QuotaTariffVO.class).withArguments(Mockito.any(QuotaTariffVO.class)).thenReturn(quotaTariffVoMock);
-
-        quotaResponseBuilderSpy.getNewQuotaTariffObject(quotaTariffVoMock, "", 0);
-        PowerMockito.verifyNew(QuotaTariffVO.class).withArguments(Mockito.any(QuotaTariffVO.class));
+        try (MockedConstruction<QuotaTariffVO> quotaTariffVOMockedConstruction = Mockito.mockConstruction(QuotaTariffVO.class, (mock,
+                                                                                                        context) -> {
+        })) {
+            QuotaTariffVO result = quotaResponseBuilderSpy.getNewQuotaTariffObject(quotaTariffVoMock, "", 0);
+            Assert.assertEquals(quotaTariffVOMockedConstruction.constructed().get(0), result);
+        }
     }
 
     @Test (expected = InvalidParameterValueException.class)
@@ -360,7 +360,6 @@
 
     @Test (expected = ServerApiException.class)
     public void deleteQuotaTariffTestQuotaDoesNotExistThrowsServerApiException() {
-        Mockito.doReturn(null).when(quotaTariffDaoMock).findById(Mockito.anyLong());
         quotaResponseBuilderSpy.deleteQuotaTariff("");
     }
 
@@ -380,7 +379,6 @@
         Calendar[] period = createPeriodForQuotaSummary();
         overrideDefaultQuotaEnabledConfigValue("false");
 
-        Mockito.doReturn(accountMock).when(accountDaoMock).findActiveAccount(Mockito.anyString(), Mockito.anyLong());
         Mockito.doReturn(period).when(quotaStatementMock).getCurrentStatementTime();
         Mockito.doReturn(domainVOMock).when(domainDaoMock).findById(Mockito.anyLong());
         Mockito.doReturn(BigDecimal.ZERO).when(quotaBalanceDaoMock).lastQuotaBalance(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(Date.class));
@@ -396,7 +394,6 @@
         Calendar[] period = createPeriodForQuotaSummary();
         overrideDefaultQuotaEnabledConfigValue("true");
 
-        Mockito.doReturn(accountMock).when(accountDaoMock).findActiveAccount(Mockito.anyString(), Mockito.anyLong());
         Mockito.doReturn(period).when(quotaStatementMock).getCurrentStatementTime();
         Mockito.doReturn(domainVOMock).when(domainDaoMock).findById(Mockito.anyLong());
         Mockito.doReturn(BigDecimal.ZERO).when(quotaBalanceDaoMock).lastQuotaBalance(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(Date.class));
diff --git a/plugins/database/quota/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/plugins/database/quota/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d4
--- /dev/null
+++ b/plugins/database/quota/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/plugins/dedicated-resources/pom.xml b/plugins/dedicated-resources/pom.xml
index 435879d..084e8fd 100644
--- a/plugins/dedicated-resources/pom.xml
+++ b/plugins/dedicated-resources/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/deployment-planners/implicit-dedication/pom.xml b/plugins/deployment-planners/implicit-dedication/pom.xml
index fb6dc0a..0d78434 100644
--- a/plugins/deployment-planners/implicit-dedication/pom.xml
+++ b/plugins/deployment-planners/implicit-dedication/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/deployment-planners/implicit-dedication/src/main/resources/META-INF/cloudstack/implicit-dedication/module.properties b/plugins/deployment-planners/implicit-dedication/src/main/resources/META-INF/cloudstack/implicit-dedication/module.properties
index 6cda904..85ba7d5 100644
--- a/plugins/deployment-planners/implicit-dedication/src/main/resources/META-INF/cloudstack/implicit-dedication/module.properties
+++ b/plugins/deployment-planners/implicit-dedication/src/main/resources/META-INF/cloudstack/implicit-dedication/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=implicit-dedication
-parent=planner
\ No newline at end of file
+parent=planner
diff --git a/plugins/deployment-planners/user-concentrated-pod/pom.xml b/plugins/deployment-planners/user-concentrated-pod/pom.xml
index d64800a..2fe6404 100644
--- a/plugins/deployment-planners/user-concentrated-pod/pom.xml
+++ b/plugins/deployment-planners/user-concentrated-pod/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/deployment-planners/user-concentrated-pod/src/main/resources/META-INF/cloudstack/user-concentrated-pod/module.properties b/plugins/deployment-planners/user-concentrated-pod/src/main/resources/META-INF/cloudstack/user-concentrated-pod/module.properties
index 7a430b2..1ac3e14 100644
--- a/plugins/deployment-planners/user-concentrated-pod/src/main/resources/META-INF/cloudstack/user-concentrated-pod/module.properties
+++ b/plugins/deployment-planners/user-concentrated-pod/src/main/resources/META-INF/cloudstack/user-concentrated-pod/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=user-concentrated-pod
-parent=planner
\ No newline at end of file
+parent=planner
diff --git a/plugins/deployment-planners/user-dispersing/pom.xml b/plugins/deployment-planners/user-dispersing/pom.xml
index 584ec2c..3d7682a 100644
--- a/plugins/deployment-planners/user-dispersing/pom.xml
+++ b/plugins/deployment-planners/user-dispersing/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/event-bus/inmemory/pom.xml b/plugins/event-bus/inmemory/pom.xml
index 22497a8..2ed5a91 100644
--- a/plugins/event-bus/inmemory/pom.xml
+++ b/plugins/event-bus/inmemory/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/event-bus/kafka/pom.xml b/plugins/event-bus/kafka/pom.xml
index 6836798..6756ea2 100644
--- a/plugins/event-bus/kafka/pom.xml
+++ b/plugins/event-bus/kafka/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/event-bus/rabbitmq/pom.xml b/plugins/event-bus/rabbitmq/pom.xml
index a8472be..6019fb9 100644
--- a/plugins/event-bus/rabbitmq/pom.xml
+++ b/plugins/event-bus/rabbitmq/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/ha-planners/skip-heurestics/pom.xml b/plugins/ha-planners/skip-heurestics/pom.xml
index 27091c0..59a2600 100644
--- a/plugins/ha-planners/skip-heurestics/pom.xml
+++ b/plugins/ha-planners/skip-heurestics/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/ha-planners/skip-heurestics/src/main/resources/META-INF/cloudstack/skip-heurestics/spring-skip-heurestics-context.xml b/plugins/ha-planners/skip-heurestics/src/main/resources/META-INF/cloudstack/skip-heurestics/spring-skip-heurestics-context.xml
index 21a5064..3cb5a55 100644
--- a/plugins/ha-planners/skip-heurestics/src/main/resources/META-INF/cloudstack/skip-heurestics/spring-skip-heurestics-context.xml
+++ b/plugins/ha-planners/skip-heurestics/src/main/resources/META-INF/cloudstack/skip-heurestics/spring-skip-heurestics-context.xml
@@ -23,4 +23,3 @@
 
 
 </beans>
-
diff --git a/plugins/host-allocators/random/pom.xml b/plugins/host-allocators/random/pom.xml
index 111606a..8c8bd99 100644
--- a/plugins/host-allocators/random/pom.xml
+++ b/plugins/host-allocators/random/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/host-allocators/random/src/main/resources/META-INF/cloudstack/host-allocator-random/module.properties b/plugins/host-allocators/random/src/main/resources/META-INF/cloudstack/host-allocator-random/module.properties
index 9a04174..dcfe8d3 100644
--- a/plugins/host-allocators/random/src/main/resources/META-INF/cloudstack/host-allocator-random/module.properties
+++ b/plugins/host-allocators/random/src/main/resources/META-INF/cloudstack/host-allocator-random/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=host-allocator-random
-parent=allocator
\ No newline at end of file
+parent=allocator
diff --git a/plugins/hypervisors/baremetal/pom.xml b/plugins/hypervisors/baremetal/pom.xml
index 83430fc..6150bed 100755
--- a/plugins/hypervisors/baremetal/pom.xml
+++ b/plugins/hypervisors/baremetal/pom.xml
@@ -22,7 +22,7 @@
     <parent>

         <groupId>org.apache.cloudstack</groupId>

         <artifactId>cloudstack-plugins</artifactId>

-        <version>4.18.1.0-SNAPSHOT</version>

+        <version>4.19.0.0-SNAPSHOT</version>

         <relativePath>../../pom.xml</relativePath>

     </parent>

     <artifactId>cloud-plugin-hypervisor-baremetal</artifactId>

diff --git a/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-compute/module.properties b/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-compute/module.properties
index 654b0d8..9fb9f43 100644
--- a/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-compute/module.properties
+++ b/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-compute/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=baremetal-compute
-parent=compute
\ No newline at end of file
+parent=compute
diff --git a/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-discoverer/module.properties b/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-discoverer/module.properties
index 3307c8c..93c622e 100644
--- a/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-discoverer/module.properties
+++ b/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-discoverer/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=baremetal-discoverer
-parent=discoverer
\ No newline at end of file
+parent=discoverer
diff --git a/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-network/module.properties b/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-network/module.properties
index acfe594..993c464 100644
--- a/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-network/module.properties
+++ b/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-network/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=baremetal-network
-parent=network
\ No newline at end of file
+parent=network
diff --git a/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-planner/module.properties b/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-planner/module.properties
index c6c4e74..2c1ec6b 100644
--- a/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-planner/module.properties
+++ b/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-planner/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=baremetal-planner
-parent=planner
\ No newline at end of file
+parent=planner
diff --git a/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-storage/module.properties b/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-storage/module.properties
index b4269a8..5583b2b 100644
--- a/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-storage/module.properties
+++ b/plugins/hypervisors/baremetal/src/main/resources/META-INF/cloudstack/baremetal-storage/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=baremetal-storage
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/.gitignore b/plugins/hypervisors/hyperv/DotNet/ServerResource/.gitignore
index a2f30c8..ca0119f 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/.gitignore
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/.gitignore
@@ -23,4 +23,3 @@
 ServerResource*/bin/*
 *.user
 !.nuget/
-
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentShell.csproj b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentShell.csproj
index f804ef6..262d2a8 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentShell.csproj
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/AgentShell.csproj
@@ -148,4 +148,4 @@
   <Target Name="AfterBuild">
   </Target>
   -->
-</Project>
\ No newline at end of file
+</Project>
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/App.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/App.config
index 3ec08bd..f7acb95 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/App.config
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/App.config
@@ -143,4 +143,4 @@
       </setting>
     </CloudStack.Plugin.AgentShell.AgentSettings>
   </userSettings>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/packages.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/packages.config
index fb1c846..2f2cd01 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/packages.config
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/AgentShell/packages.config
@@ -10,4 +10,4 @@
   <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
   <package id="NSubstitute" version="1.6.1.0" targetFramework="net45" />
   <package id="xunit" version="1.9.2" targetFramework="net45" />
-</packages>
\ No newline at end of file
+</packages>
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj
index 8bebfff..c596b8d 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/HypervResource.csproj
@@ -110,4 +110,4 @@
   <Target Name="AfterBuild">

   </Target>

   -->

-</Project>
\ No newline at end of file
+</Project>
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/heartbeat.bat b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/heartbeat.bat
index 85f6e7b..472f68f 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/heartbeat.bat
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/heartbeat.bat
@@ -20,4 +20,4 @@
 @REM http://stackoverflow.com/questions/9871499/how-to-get-utc-time-with-windows-batch-file
 
 for /f %%x in ('wmic path win32_utctime get /format:list ^| findstr "="') do set %%x
-echo %Year%-%Month%-%Day%@%Hour%:%Minute%:%Second%>%1
\ No newline at end of file
+echo %Year%-%Month%-%Day%@%Hour%:%Minute%:%Second%>%1
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/packages.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/packages.config
index 4c538e4..efa54b2 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/packages.config
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/packages.config
@@ -6,4 +6,4 @@
   <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
   <package id="NSubstitute" version="1.6.1.0" targetFramework="net45" />
   <package id="xunit" version="1.9.2" targetFramework="net45" />
-</packages>
\ No newline at end of file
+</packages>
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/App.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/App.config
index c959ccf..6b941dc 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/App.config
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/App.config
@@ -136,4 +136,4 @@
       </providers>
     </roleManager>
   </system.web>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/packages.config b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/packages.config
index 4c538e4..efa54b2 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/packages.config
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/ServerResource.Tests/packages.config
@@ -6,4 +6,4 @@
   <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
   <package id="NSubstitute" version="1.6.1.0" targetFramework="net45" />
   <package id="xunit" version="1.9.2" targetFramework="net45" />
-</packages>
\ No newline at end of file
+</packages>
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/WmiWrappers.csproj b/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/WmiWrappers.csproj
index 5404736..3232f67 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/WmiWrappers.csproj
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/WmiWrappers/WmiWrappers.csproj
@@ -194,4 +194,4 @@
   <Target Name="AfterBuild">

   </Target>

   -->

-</Project>
\ No newline at end of file
+</Project>
diff --git a/plugins/hypervisors/hyperv/pom.xml b/plugins/hypervisors/hyperv/pom.xml
index 8962fe4..946e5f4 100644
--- a/plugins/hypervisors/hyperv/pom.xml
+++ b/plugins/hypervisors/hyperv/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <properties>
diff --git a/plugins/hypervisors/hyperv/src/main/resources/META-INF/cloudstack/hyperv-compute/module.properties b/plugins/hypervisors/hyperv/src/main/resources/META-INF/cloudstack/hyperv-compute/module.properties
index 439b7d5..abf8789 100644
--- a/plugins/hypervisors/hyperv/src/main/resources/META-INF/cloudstack/hyperv-compute/module.properties
+++ b/plugins/hypervisors/hyperv/src/main/resources/META-INF/cloudstack/hyperv-compute/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=hyperv-compute
-parent=compute
\ No newline at end of file
+parent=compute
diff --git a/plugins/hypervisors/hyperv/src/main/resources/META-INF/cloudstack/hyperv-discoverer/module.properties b/plugins/hypervisors/hyperv/src/main/resources/META-INF/cloudstack/hyperv-discoverer/module.properties
index be51dd6..ea8c023 100644
--- a/plugins/hypervisors/hyperv/src/main/resources/META-INF/cloudstack/hyperv-discoverer/module.properties
+++ b/plugins/hypervisors/hyperv/src/main/resources/META-INF/cloudstack/hyperv-discoverer/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=hyperv-discoverer
-parent=discoverer
\ No newline at end of file
+parent=discoverer
diff --git a/plugins/hypervisors/kvm/pom.xml b/plugins/hypervisors/kvm/pom.xml
index a74cb92..9265d66 100644
--- a/plugins/hypervisors/kvm/pom.xml
+++ b/plugins/hypervisors/kvm/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 6fcb546..3411ad4 100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -322,6 +322,7 @@
     private String _dcId;
     private String _clusterId;
     private final Properties _uefiProperties = new Properties();
+    private String hostHealthCheckScriptPath;
 
     private long _hvVersion;
     private Duration _timeout;
@@ -717,6 +718,10 @@
         NATIVE, OPENVSWITCH, TUNGSTEN
     }
 
+    protected enum HealthCheckResult {
+        SUCCESS, FAILURE, IGNORE
+    }
+
     protected BridgeType _bridgeType;
 
     protected StorageSubsystemCommandHandler storageHandler;
@@ -943,6 +948,12 @@
             throw new ConfigurationException("Unable to find the ovs-pvlan-kvm-vm.sh");
         }
 
+        hostHealthCheckScriptPath = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.HEALTH_CHECK_SCRIPT_PATH);
+        if (StringUtils.isNotBlank(hostHealthCheckScriptPath) && !new File(hostHealthCheckScriptPath).exists()) {
+            s_logger.info(String.format("Unable to find the host health check script at: %s, " +
+                    "discarding it", hostHealthCheckScriptPath));
+        }
+
         setupTungstenVrouterPath = Script.findScript(tungstenScriptsDir, "setup_tungsten_vrouter.sh");
         if (setupTungstenVrouterPath == null) {
             throw new ConfigurationException("Unable to find the setup_tungsten_vrouter.sh");
@@ -2837,7 +2848,7 @@
         for (int i = 0; i < nics.length; i++) {
             for (final NicTO nic : vmSpec.getNics()) {
                 if (nic.getDeviceId() == i) {
-                    createVif(vm, nic, nicAdapter, extraConfig);
+                    createVif(vm, vmSpec, nic, nicAdapter, extraConfig);
                 }
             }
         }
@@ -3218,12 +3229,16 @@
         }
     }
 
-    private void createVif(final LibvirtVMDef vm, final NicTO nic, final String nicAdapter, Map<String, String> extraConfig) throws InternalErrorException, LibvirtException {
+    private void createVif(final LibvirtVMDef vm, final VirtualMachineTO vmSpec, final NicTO nic, final String nicAdapter, Map<String, String> extraConfig) throws InternalErrorException, LibvirtException {
         if (vm.getDevices() == null) {
             s_logger.error("LibvirtVMDef object get devices with null result");
             throw new InternalErrorException("LibvirtVMDef object get devices with null result");
         }
-        vm.getDevices().addDevice(getVifDriver(nic.getType(), nic.getName()).plug(nic, vm.getPlatformEmulator(), nicAdapter, extraConfig));
+        final InterfaceDef interfaceDef = getVifDriver(nic.getType(), nic.getName()).plug(nic, vm.getPlatformEmulator(), nicAdapter, extraConfig);
+        if (vmSpec.getDetails() != null) {
+            setInterfaceDefQueueSettings(vmSpec.getDetails(), vmSpec.getCpus(), interfaceDef);
+        }
+        vm.getDevices().addDevice(interfaceDef);
     }
 
     public boolean cleanupDisk(Map<String, String> volumeToDisconnect) {
@@ -3441,13 +3456,54 @@
 
     @Override
     public PingCommand getCurrentStatus(final long id) {
-
+        PingRoutingCommand pingRoutingCommand;
         if (!_canBridgeFirewall) {
-            return new PingRoutingCommand(com.cloud.host.Host.Type.Routing, id, this.getHostVmStateReport());
+            pingRoutingCommand = new PingRoutingCommand(com.cloud.host.Host.Type.Routing, id, this.getHostVmStateReport());
         } else {
             final HashMap<String, Pair<Long, Long>> nwGrpStates = syncNetworkGroups(id);
-            return new PingRoutingWithNwGroupsCommand(getType(), id, this.getHostVmStateReport(), nwGrpStates);
+            pingRoutingCommand = new PingRoutingWithNwGroupsCommand(getType(), id, this.getHostVmStateReport(), nwGrpStates);
         }
+        HealthCheckResult healthCheckResult = getHostHealthCheckResult();
+        if (healthCheckResult != HealthCheckResult.IGNORE) {
+            pingRoutingCommand.setHostHealthCheckResult(healthCheckResult == HealthCheckResult.SUCCESS);
+        }
+        return pingRoutingCommand;
+    }
+
+    /**
+     * The health check result is true, if the script is executed successfully and the exit code is 0
+     * The health check result is false, if the script is executed successfully and the exit code is 1
+     * The health check result is null, if
+     * - Script file is not specified, or
+     * - Script file does not exist, or
+     * - Script file is not accessible by the user of the cloudstack-agent process, or
+     * - Script file is not executable
+     * - There are errors when the script is executed (exit codes other than 0 or 1)
+     */
+    private HealthCheckResult getHostHealthCheckResult() {
+        if (StringUtils.isBlank(hostHealthCheckScriptPath)) {
+            s_logger.debug("Host health check script path is not specified");
+            return HealthCheckResult.IGNORE;
+        }
+        File script = new File(hostHealthCheckScriptPath);
+        if (!script.exists() || !script.isFile() || !script.canExecute()) {
+            s_logger.warn(String.format("The host health check script file set at: %s cannot be executed, " +
+                            "reason: %s", hostHealthCheckScriptPath,
+                    !script.exists() ? "file does not exist" : "please check file permissions to execute this file"));
+            return HealthCheckResult.IGNORE;
+        }
+        int exitCode = executeBashScriptAndRetrieveExitValue(hostHealthCheckScriptPath);
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug(String.format("Host health check script exit code: %s", exitCode));
+        }
+        return retrieveHealthCheckResultFromExitCode(exitCode);
+    }
+
+    private HealthCheckResult retrieveHealthCheckResultFromExitCode(int exitCode) {
+        if (exitCode != 0 && exitCode != 1) {
+            return HealthCheckResult.IGNORE;
+        }
+        return exitCode == 0 ? HealthCheckResult.SUCCESS : HealthCheckResult.FAILURE;
     }
 
     @Override
@@ -3489,6 +3545,10 @@
         cmd.setGatewayIpAddress(_localGateway);
         cmd.setIqn(getIqn());
         cmd.getHostDetails().put(HOST_VOLUME_ENCRYPTION, String.valueOf(hostSupportsVolumeEncryption()));
+        HealthCheckResult healthCheckResult = getHostHealthCheckResult();
+        if (healthCheckResult != HealthCheckResult.IGNORE) {
+            cmd.setHostHealthCheckResult(healthCheckResult == HealthCheckResult.SUCCESS);
+        }
 
         if (cmd.getHostDetails().containsKey("Host.OS")) {
             _hostDistro = cmd.getHostDetails().get("Host.OS");
@@ -5092,4 +5152,30 @@
     public static String generateSecretUUIDFromString(String seed) {
         return UUID.nameUUIDFromBytes(seed.getBytes()).toString();
     }
+
+    public void setInterfaceDefQueueSettings(Map<String, String> details, Integer cpus, InterfaceDef interfaceDef) {
+        String nicMultiqueueNumber = details.get(VmDetailConstants.NIC_MULTIQUEUE_NUMBER);
+        if (nicMultiqueueNumber != null) {
+            try {
+                Integer nicMultiqueueNumberInteger = Integer.valueOf(nicMultiqueueNumber);
+                if (nicMultiqueueNumberInteger == InterfaceDef.MULTI_QUEUE_NUMBER_MEANS_CPU_CORES) {
+                    if (cpus != null) {
+                        interfaceDef.setMultiQueueNumber(cpus);
+                    }
+                } else {
+                    interfaceDef.setMultiQueueNumber(nicMultiqueueNumberInteger);
+                }
+            } catch (NumberFormatException ex) {
+                s_logger.warn(String.format("VM details %s is not a valid integer value %s", VmDetailConstants.NIC_MULTIQUEUE_NUMBER, nicMultiqueueNumber));
+            }
+        }
+        String nicPackedEnabled = details.get(VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED);
+        if (nicPackedEnabled != null) {
+            try {
+                interfaceDef.setPackedVirtQueues(Boolean.valueOf(nicPackedEnabled));
+            } catch (NumberFormatException ex) {
+                s_logger.warn(String.format("VM details %s is not a valid Boolean value %s", VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED, nicPackedEnabled));
+            }
+        }
+    }
 }
diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
index cb650e2..9a27e5e 100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java
@@ -249,6 +249,15 @@
                     def.setDpdkOvsPath(ovsPath);
                     def.setInterfaceMode(mode);
                 }
+                String multiQueueNumber = getAttrValue("driver", "queues", nic);
+                if (StringUtils.isNotBlank(multiQueueNumber)) {
+                    def.setMultiQueueNumber(Integer.valueOf(multiQueueNumber));
+                }
+
+                String packedOn = getAttrValue("driver", "packed", nic);
+                if (StringUtils.isNotBlank(packedOn)) {
+                    def.setPackedVirtQueues("on".equalsIgnoreCase(packedOn));
+                }
 
                 if (StringUtils.isNotBlank(slot)) {
                     def.setSlot(Integer.parseInt(slot, 16));
diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
index b739c0e..aac44fc 100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
@@ -1280,6 +1280,8 @@
             DIRECT_ATTACHED_WITHOUT_DHCP, DIRECT_ATTACHED_WITH_DHCP, VNET, VLAN;
         }
 
+        public static final int MULTI_QUEUE_NUMBER_MEANS_CPU_CORES = -1;
+
         private GuestNetType _netType; /*
          * bridge, ethernet, network, user,
          * internal, vhostuser
@@ -1305,6 +1307,8 @@
         private String _interfaceMode;
         private String _userIp4Network;
         private Integer _userIp4Prefix;
+        private Integer _multiQueueNumber;
+        private Boolean _packedVirtQueues;
 
         public void defBridgeNet(String brName, String targetBrName, String macAddr, NicModel model) {
             defBridgeNet(brName, targetBrName, macAddr, model, 0);
@@ -1493,6 +1497,14 @@
             _interfaceMode = mode;
         }
 
+        public void setMultiQueueNumber(Integer multiQueueNumber) {
+            this._multiQueueNumber = multiQueueNumber;
+        }
+
+        public void setPackedVirtQueues(Boolean packedVirtQueues) {
+            this._packedVirtQueues = packedVirtQueues;
+        }
+
         public String getContent() {
             StringBuilder netBuilder = new StringBuilder();
             if (_netType == GuestNetType.BRIDGE) {
@@ -1515,6 +1527,21 @@
             if (_model != null) {
                 netBuilder.append("<model type='" + _model + "'/>\n");
             }
+            if (NicModel.VIRTIO.equals(_model)) {
+                boolean isMultiQueueNumberSpecified = _multiQueueNumber != null;
+                boolean isPackedVirtQueuesEnabled = _packedVirtQueues != null && _packedVirtQueues
+                        && s_qemuVersion >= 4200000 && s_libvirtVersion >= 6300000;
+                if (isMultiQueueNumberSpecified || isPackedVirtQueuesEnabled) {
+                    netBuilder.append("<driver");
+                    if (isMultiQueueNumberSpecified) {
+                        netBuilder.append(" queues='" + _multiQueueNumber + "'");
+                    }
+                    if (isPackedVirtQueuesEnabled) {
+                        netBuilder.append(" packed='on'");
+                    }
+                    netBuilder.append("/>\n");
+                }
+            }
             if ((s_libvirtVersion >= 9004) && (_networkRateKBps > 0)) { // supported from libvirt 0.9.4
                 netBuilder.append("<bandwidth>\n");
                 netBuilder.append("<inbound average='" + _networkRateKBps + "' peak='" + _networkRateKBps + "'/>\n");
diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java
index ca78c71..dffa836 100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPlugNicCommandWrapper.java
@@ -64,6 +64,9 @@
             }
             final VifDriver vifDriver = libvirtComputingResource.getVifDriver(nic.getType(), nic.getName());
             final InterfaceDef interfaceDef = vifDriver.plug(nic, "Other PV", "", null);
+            if (command.getDetails() != null) {
+                libvirtComputingResource.setInterfaceDefQueueSettings(command.getDetails(), null, interfaceDef);
+            }
             vm.attachDevice(interfaceDef.toString());
 
             // apply default network rules on new nic
diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java
index 9109d57..ec9e67e 100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtPrepareForMigrationCommandWrapper.java
@@ -80,6 +80,9 @@
 
             for (final NicTO nic : nics) {
                 LibvirtVMDef.InterfaceDef interfaceDef = libvirtComputingResource.getVifDriver(nic.getType(), nic.getName()).plug(nic, null, "", vm.getExtraConfig());
+                if (vm.getDetails() != null) {
+                    libvirtComputingResource.setInterfaceDefQueueSettings(vm.getDetails(), vm.getCpus(), interfaceDef);
+                }
                 if (interfaceDef != null && interfaceDef.getNetType() == GuestNetType.VHOSTUSER) {
                     DpdkTO to = new DpdkTO(interfaceDef.getDpdkOvsPath(), interfaceDef.getDpdkSourcePort(), interfaceDef.getInterfaceMode());
                     dpdkInterfaceMapping.put(nic.getMac(), to);
diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java
index ff9ae6d..558c7f0 100644
--- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java
+++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtReplugNicCommandWrapper.java
@@ -66,7 +66,9 @@
 
             final VifDriver newVifDriver = libvirtComputingResource.getVifDriver(nic.getType(), nic.getName());
             final InterfaceDef interfaceDef = newVifDriver.plug(nic, "Other PV", oldPluggedNic.getModel().toString(), null);
-
+            if (command.getDetails() != null) {
+                libvirtComputingResource.setInterfaceDefQueueSettings(command.getDetails(), null, interfaceDef);
+            }
             interfaceDef.setSlot(oldPluggedNic.getSlot());
             interfaceDef.setDevName(oldPluggedNic.getDevName());
             interfaceDef.setLinkStateUp(false);
diff --git a/plugins/hypervisors/kvm/src/main/resources/META-INF/cloudstack/kvm-compute/module.properties b/plugins/hypervisors/kvm/src/main/resources/META-INF/cloudstack/kvm-compute/module.properties
index 1137972..0b28201 100644
--- a/plugins/hypervisors/kvm/src/main/resources/META-INF/cloudstack/kvm-compute/module.properties
+++ b/plugins/hypervisors/kvm/src/main/resources/META-INF/cloudstack/kvm-compute/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=kvm-compute
-parent=compute
\ No newline at end of file
+parent=compute
diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java
index 741f0a8..1acb86f 100644
--- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java
+++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java
@@ -151,6 +151,58 @@
     }
 
     @Test
+    public void testInterfaceWithMultiQueueAndPacked() {
+        LibvirtVMDef.InterfaceDef ifDef = new LibvirtVMDef.InterfaceDef();
+        ifDef.defBridgeNet("targetDeviceName", null, "00:11:22:aa:bb:dd", LibvirtVMDef.InterfaceDef.NicModel.VIRTIO);
+        ifDef.setMultiQueueNumber(6);
+
+        LibvirtVMDef.setGlobalQemuVersion(5000000L);
+        LibvirtVMDef.setGlobalLibvirtVersion(6400000L);
+
+        String expected =
+                "<interface type='" + LibvirtVMDef.InterfaceDef.GuestNetType.BRIDGE + "'>\n"
+                        + "<source bridge='targetDeviceName'/>\n"
+                        + "<mac address='00:11:22:aa:bb:dd'/>\n"
+                        + "<model type='virtio'/>\n"
+                        + "<driver queues='6'/>\n"
+                        + "<link state='up'/>\n"
+                        + "</interface>\n";
+        assertEquals(expected, ifDef.toString());
+
+        ifDef.setPackedVirtQueues(true);
+        expected =
+                "<interface type='" + LibvirtVMDef.InterfaceDef.GuestNetType.BRIDGE + "'>\n"
+                        + "<source bridge='targetDeviceName'/>\n"
+                        + "<mac address='00:11:22:aa:bb:dd'/>\n"
+                        + "<model type='virtio'/>\n"
+                        + "<driver queues='6' packed='on'/>\n"
+                        + "<link state='up'/>\n"
+                        + "</interface>\n";
+        assertEquals(expected, ifDef.toString());
+
+        ifDef.setMultiQueueNumber(null);
+        expected =
+                "<interface type='" + LibvirtVMDef.InterfaceDef.GuestNetType.BRIDGE + "'>\n"
+                        + "<source bridge='targetDeviceName'/>\n"
+                        + "<mac address='00:11:22:aa:bb:dd'/>\n"
+                        + "<model type='virtio'/>\n"
+                        + "<driver packed='on'/>\n"
+                        + "<link state='up'/>\n"
+                        + "</interface>\n";
+        assertEquals(expected, ifDef.toString());
+
+        LibvirtVMDef.setGlobalLibvirtVersion(300000L);
+        expected =
+                "<interface type='" + LibvirtVMDef.InterfaceDef.GuestNetType.BRIDGE + "'>\n"
+                        + "<source bridge='targetDeviceName'/>\n"
+                        + "<mac address='00:11:22:aa:bb:dd'/>\n"
+                        + "<model type='virtio'/>\n"
+                        + "<link state='up'/>\n"
+                        + "</interface>\n";
+        assertEquals(expected, ifDef.toString());
+        }
+
+    @Test
     public void testCpuModeDef() {
         LibvirtVMDef.CpuModeDef cpuModeDef = new LibvirtVMDef.CpuModeDef();
         cpuModeDef.setMode("custom");
diff --git a/plugins/hypervisors/ovm/pom.xml b/plugins/hypervisors/ovm/pom.xml
index 511e29f..24ce660 100644
--- a/plugins/hypervisors/ovm/pom.xml
+++ b/plugins/hypervisors/ovm/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/hypervisors/ovm/src/main/resources/META-INF/cloudstack/ovm-compute/module.properties b/plugins/hypervisors/ovm/src/main/resources/META-INF/cloudstack/ovm-compute/module.properties
index 1d93fa1..165a1c7 100644
--- a/plugins/hypervisors/ovm/src/main/resources/META-INF/cloudstack/ovm-compute/module.properties
+++ b/plugins/hypervisors/ovm/src/main/resources/META-INF/cloudstack/ovm-compute/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=ovm-compute
-parent=compute
\ No newline at end of file
+parent=compute
diff --git a/plugins/hypervisors/ovm/src/main/resources/META-INF/cloudstack/ovm-discoverer/module.properties b/plugins/hypervisors/ovm/src/main/resources/META-INF/cloudstack/ovm-discoverer/module.properties
index 3a4b1f8..9f432a5 100644
--- a/plugins/hypervisors/ovm/src/main/resources/META-INF/cloudstack/ovm-discoverer/module.properties
+++ b/plugins/hypervisors/ovm/src/main/resources/META-INF/cloudstack/ovm-discoverer/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=ovm-discoverer
-parent=discoverer
\ No newline at end of file
+parent=discoverer
diff --git a/plugins/hypervisors/ovm/src/main/scripts/vm/hypervisor/ovm/configureOvm.sh b/plugins/hypervisors/ovm/src/main/scripts/vm/hypervisor/ovm/configureOvm.sh
index 4ed8aa9..2cc3a0c 100755
--- a/plugins/hypervisors/ovm/src/main/scripts/vm/hypervisor/ovm/configureOvm.sh
+++ b/plugins/hypervisors/ovm/src/main/scripts/vm/hypervisor/ovm/configureOvm.sh
@@ -128,4 +128,3 @@
     *)
         errExit "Valid commands: preSetup postSetup"
 esac
-
diff --git a/plugins/hypervisors/ovm3/pom.xml b/plugins/hypervisors/ovm3/pom.xml
index 3020d1e..2be28bd 100644
--- a/plugins/hypervisors/ovm3/pom.xml
+++ b/plugins/hypervisors/ovm3/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/hypervisors/simulator/pom.xml b/plugins/hypervisors/simulator/pom.xml
index ce50a45..59c0553 100644
--- a/plugins/hypervisors/simulator/pom.xml
+++ b/plugins/hypervisors/simulator/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <artifactId>cloud-plugin-hypervisor-simulator</artifactId>
diff --git a/plugins/hypervisors/simulator/src/main/resources/META-INF/cloudstack/simulator-compute/module.properties b/plugins/hypervisors/simulator/src/main/resources/META-INF/cloudstack/simulator-compute/module.properties
index 7b12a08..6bb4e80 100644
--- a/plugins/hypervisors/simulator/src/main/resources/META-INF/cloudstack/simulator-compute/module.properties
+++ b/plugins/hypervisors/simulator/src/main/resources/META-INF/cloudstack/simulator-compute/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=simulator-compute
-parent=compute
\ No newline at end of file
+parent=compute
diff --git a/plugins/hypervisors/simulator/src/main/resources/META-INF/cloudstack/simulator-discoverer/module.properties b/plugins/hypervisors/simulator/src/main/resources/META-INF/cloudstack/simulator-discoverer/module.properties
index 536cf15..59ecba6 100644
--- a/plugins/hypervisors/simulator/src/main/resources/META-INF/cloudstack/simulator-discoverer/module.properties
+++ b/plugins/hypervisors/simulator/src/main/resources/META-INF/cloudstack/simulator-discoverer/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=simulator-discoverer
-parent=discoverer
\ No newline at end of file
+parent=discoverer
diff --git a/plugins/hypervisors/simulator/src/main/resources/META-INF/cloudstack/simulator-storage/module.properties b/plugins/hypervisors/simulator/src/main/resources/META-INF/cloudstack/simulator-storage/module.properties
index 97a1784..7a9bcd4 100644
--- a/plugins/hypervisors/simulator/src/main/resources/META-INF/cloudstack/simulator-storage/module.properties
+++ b/plugins/hypervisors/simulator/src/main/resources/META-INF/cloudstack/simulator-storage/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=simulator-storage
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/plugins/hypervisors/ucs/pom.xml b/plugins/hypervisors/ucs/pom.xml
index b21bc2f..c7e1871 100644
--- a/plugins/hypervisors/ucs/pom.xml
+++ b/plugins/hypervisors/ucs/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <artifactId>cloud-plugin-hypervisor-ucs</artifactId>
diff --git a/plugins/hypervisors/vmware/pom.xml b/plugins/hypervisors/vmware/pom.xml
index 5edc0ee..030da6d 100644
--- a/plugins/hypervisors/vmware/pom.xml
+++ b/plugins/hypervisors/vmware/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java
index fe35d56..8c49860 100644
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/guru/VMwareGuru.java
@@ -781,8 +781,7 @@
                 volume = createVolume(disk, vmToImport, domainId, zoneId, accountId, instanceId, poolId, templateId, backup, true);
                 operation = "created";
             }
-            s_logger.debug(String.format("VM [id: %s, instanceName: %s] backup restore operation %s volume [id: %s].", instanceId, vmInstanceVO.getInstanceName(),
-                    operation, volume.getUuid()));
+            s_logger.debug(String.format("Sync volumes to %s in backup restore operation: %s volume [id: %s].", vmInstanceVO, operation, volume.getUuid()));
         }
     }
 
@@ -879,9 +878,13 @@
         String tag = parts[parts.length - 1];
         String[] tagSplit = tag.split("-");
         tag = tagSplit[tagSplit.length - 1];
+
+        s_logger.debug(String.format("Trying to find network with vlan: [%s].", vlan));
         NetworkVO networkVO = networkDao.findByVlan(vlan);
         if (networkVO == null) {
             networkVO = createNetworkRecord(zoneId, tag, vlan, accountId, domainId);
+            s_logger.debug(String.format("Created new network record [id: %s] with details [zoneId: %s, tag: %s, vlan: %s, accountId: %s and domainId: %s].",
+                    networkVO.getUuid(), zoneId, tag, vlan, accountId, domainId));
         }
         return networkVO;
     }
@@ -893,6 +896,7 @@
         Map<String, NetworkVO> mapping = new HashMap<>();
         for (String networkName : vmNetworkNames) {
             NetworkVO networkVO = getGuestNetworkFromNetworkMorName(networkName, accountId, zoneId, domainId);
+            s_logger.debug(String.format("Mapping network name [%s] to networkVO [id: %s].", networkName, networkVO.getUuid()));
             mapping.put(networkName, networkVO);
         }
         return mapping;
@@ -927,12 +931,19 @@
             String macAddress = pair.first();
             String networkName = pair.second();
             NetworkVO networkVO = networksMapping.get(networkName);
-            NicVO nicVO = nicDao.findByNetworkIdAndMacAddress(networkVO.getId(), macAddress);
+            NicVO nicVO = nicDao.findByNetworkIdAndMacAddressIncludingRemoved(networkVO.getId(), macAddress);
             if (nicVO != null) {
+                s_logger.warn(String.format("Find NIC in DB with networkId [%s] and MAC Address [%s], so this NIC will be removed from list of unmapped NICs of VM [id: %s, name: %s].",
+                        networkVO.getId(), macAddress, vm.getUuid(), vm.getInstanceName()));
                 allNics.remove(nicVO);
+
+                if (nicVO.getRemoved() != null) {
+                    nicDao.unremove(nicVO.getId());
+                }
             }
         }
         for (final NicVO unMappedNic : allNics) {
+            s_logger.debug(String.format("Removing NIC [%s] from backup restored %s.", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(unMappedNic, "uuid", "macAddress"), vm));
             vmManager.removeNicFromVm(vm, unMappedNic);
         }
     }
diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
index 5b94858..80a4362 100644
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
@@ -198,7 +198,7 @@
     }
 
     //Fang: new command added;
-    // Important! we need to sync file system before we can safely use tar to work around a linux kernal bug(or feature)
+    // Important! we need to sync file system before we can safely use tar to work around a linux kernel bug(or feature)
     public String createOvaForVolume(VolumeObjectTO volume, int archiveTimeout) {
         DataStoreTO storeTO = volume.getDataStore();
         if (!(storeTO instanceof NfsTO)) {
@@ -1054,7 +1054,7 @@
             }
             String exportDir = ova_metafile.getParent();
             s_logger.info("exportDir: " + exportDir);
-            // Important! we need to sync file system before we can safely use tar to work around a linux kernal bug(or feature)
+            // Important! we need to sync file system before we can safely use tar to work around a linux kernel bug(or feature)
             s_logger.info("Sync file system before we package OVA..., before tar ");
             s_logger.info("ova: " + ovaFileName + ", ovf:" + ovfFileName + ", vmdk:" + disks[0] + ".");
             Script commandSync = new Script(true, "sync", 0, s_logger);
diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 8b833b8..90bfdd6 100644
--- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -73,6 +73,8 @@
 import com.cloud.agent.api.AttachIsoCommand;
 import com.cloud.agent.api.BackupSnapshotAnswer;
 import com.cloud.agent.api.BackupSnapshotCommand;
+import com.cloud.agent.api.CheckGuestOsMappingAnswer;
+import com.cloud.agent.api.CheckGuestOsMappingCommand;
 import com.cloud.agent.api.CheckHealthAnswer;
 import com.cloud.agent.api.CheckHealthCommand;
 import com.cloud.agent.api.CheckNetworkAnswer;
@@ -94,6 +96,8 @@
 import com.cloud.agent.api.DeleteVMSnapshotCommand;
 import com.cloud.agent.api.GetHostStatsAnswer;
 import com.cloud.agent.api.GetHostStatsCommand;
+import com.cloud.agent.api.GetHypervisorGuestOsNamesAnswer;
+import com.cloud.agent.api.GetHypervisorGuestOsNamesCommand;
 import com.cloud.agent.api.GetStoragePoolCapabilitiesAnswer;
 import com.cloud.agent.api.GetStoragePoolCapabilitiesCommand;
 import com.cloud.agent.api.GetStorageStatsAnswer;
@@ -308,6 +312,7 @@
 import com.vmware.vim25.DynamicProperty;
 import com.vmware.vim25.GuestInfo;
 import com.vmware.vim25.GuestNicInfo;
+import com.vmware.vim25.GuestOsDescriptor;
 import com.vmware.vim25.HostCapability;
 import com.vmware.vim25.HostConfigInfo;
 import com.vmware.vim25.HostFileSystemMountInfo;
@@ -606,6 +611,10 @@
                 answer = execute((GetVmVncTicketCommand) cmd);
             } else if (clz == GetAutoScaleMetricsCommand.class) {
                 answer = execute((GetAutoScaleMetricsCommand) cmd);
+            } else if (clz == CheckGuestOsMappingCommand.class) {
+                answer = execute((CheckGuestOsMappingCommand) cmd);
+            } else if (clz == GetHypervisorGuestOsNamesCommand.class) {
+                answer = execute((GetHypervisorGuestOsNamesCommand) cmd);
             } else {
                 answer = Answer.createUnsupportedCommandAnswer(cmd);
             }
@@ -7727,6 +7736,60 @@
         }
     }
 
+    protected CheckGuestOsMappingAnswer execute(CheckGuestOsMappingCommand cmd) {
+        String guestOsName = cmd.getGuestOsName();
+        String guestOsMappingName = cmd.getGuestOsHypervisorMappingName();
+        s_logger.info("Checking guest os mapping name: " + guestOsMappingName + " for the guest os: " + guestOsName + " in the hypervisor");
+        try {
+            VmwareContext context = getServiceContext();
+            VmwareHypervisorHost hyperHost = getHyperHost(context);
+            GuestOsDescriptor guestOsDescriptor = hyperHost.getGuestOsDescriptor(guestOsMappingName);
+            if (guestOsDescriptor == null) {
+                return new CheckGuestOsMappingAnswer(cmd, "Guest os mapping name: " + guestOsMappingName + " not found in the hypervisor");
+            }
+            s_logger.debug("Matching hypervisor guest os - id: " + guestOsDescriptor.getId() + ", full name: " + guestOsDescriptor.getFullName() + ", family: " + guestOsDescriptor.getFamily());
+            if (guestOsDescriptor.getFullName().equalsIgnoreCase(guestOsName)) {
+                s_logger.debug("Hypervisor guest os name in the descriptor matches with os name: " + guestOsName);
+            }
+            s_logger.info("Hypervisor guest os name in the descriptor matches with os mapping: " + guestOsMappingName + " from user");
+            return new CheckGuestOsMappingAnswer(cmd);
+        } catch (Exception e) {
+            s_logger.error("Failed to check the hypervisor guest os mapping name: " + guestOsMappingName, e);
+            return new CheckGuestOsMappingAnswer(cmd, e.getLocalizedMessage());
+        }
+    }
+
+    protected GetHypervisorGuestOsNamesAnswer execute(GetHypervisorGuestOsNamesCommand cmd) {
+        String keyword = cmd.getKeyword();
+        s_logger.info("Getting guest os names in the hypervisor");
+        try {
+            VmwareContext context = getServiceContext();
+            VmwareHypervisorHost hyperHost = getHyperHost(context);
+            List<GuestOsDescriptor> guestOsDescriptors = hyperHost.getGuestOsDescriptors();
+            if (guestOsDescriptors == null) {
+                return new GetHypervisorGuestOsNamesAnswer(cmd, "Guest os names not found in the hypervisor");
+            }
+            List<Pair<String, String>> hypervisorGuestOsNames = new ArrayList<>();
+            for (GuestOsDescriptor guestOsDescriptor : guestOsDescriptors) {
+                String osDescriptorFullName = guestOsDescriptor.getFullName();
+                String osDescriptorId = guestOsDescriptor.getId();
+                if (StringUtils.isNotBlank(keyword)) {
+                    if (osDescriptorFullName.toLowerCase().contains(keyword.toLowerCase()) || osDescriptorId.toLowerCase().contains(keyword.toLowerCase())) {
+                        Pair<String, String> hypervisorGuestOs = new Pair<>(osDescriptorFullName, osDescriptorId);
+                        hypervisorGuestOsNames.add(hypervisorGuestOs);
+                    }
+                } else {
+                    Pair<String, String> hypervisorGuestOs = new Pair<>(osDescriptorFullName, osDescriptorId);
+                    hypervisorGuestOsNames.add(hypervisorGuestOs);
+                }
+            }
+            return new GetHypervisorGuestOsNamesAnswer(cmd, hypervisorGuestOsNames);
+        } catch (Exception e) {
+            s_logger.error("Failed to get the hypervisor guest names due to: " + e.getLocalizedMessage(), e);
+            return new GetHypervisorGuestOsNamesAnswer(cmd, e.getLocalizedMessage());
+        }
+    }
+
     private Integer getVmwareWindowTimeInterval() {
         Integer windowInterval = VmwareManager.VMWARE_STATS_TIME_WINDOW.value();
         if (windowInterval == null || windowInterval < 20) {
diff --git a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/core/spring-vmware-core-context.xml b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/core/spring-vmware-core-context.xml
index a2d8314..79ed50b 100644
--- a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/core/spring-vmware-core-context.xml
+++ b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/core/spring-vmware-core-context.xml
@@ -39,4 +39,4 @@
 
     <bean id="ciscoNexusVSMDeviceDaoImpl" class="com.cloud.network.dao.CiscoNexusVSMDeviceDaoImpl" />
 
-</beans>
\ No newline at end of file
+</beans>
diff --git a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-compute/module.properties b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-compute/module.properties
index b605835..bb8972b 100644
--- a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-compute/module.properties
+++ b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-compute/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=vmware-compute
-parent=compute
\ No newline at end of file
+parent=compute
diff --git a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-discoverer/module.properties b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-discoverer/module.properties
index 0d726f8..cc9e0a5 100644
--- a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-discoverer/module.properties
+++ b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-discoverer/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=vmware-discoverer
-parent=discoverer
\ No newline at end of file
+parent=discoverer
diff --git a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-network/module.properties b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-network/module.properties
index 91ea24c..0a4f387 100644
--- a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-network/module.properties
+++ b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-network/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=vmware-network
-parent=network
\ No newline at end of file
+parent=network
diff --git a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-network/spring-vmware-network-context.xml b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-network/spring-vmware-network-context.xml
index cdfe009..e8eec03 100644
--- a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-network/spring-vmware-network-context.xml
+++ b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-network/spring-vmware-network-context.xml
@@ -31,4 +31,4 @@
         <property name="name" value="CiscoNexus1000vVSM" />
     </bean>
 
-</beans>
\ No newline at end of file
+</beans>
diff --git a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-storage/module.properties b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-storage/module.properties
index 9c3bab6..9ac4183 100644
--- a/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-storage/module.properties
+++ b/plugins/hypervisors/vmware/src/main/resources/META-INF/cloudstack/vmware-storage/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=vmware-storage
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VMwareGuruTest.java b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VMwareGuruTest.java
index 7398ef9..06bf539 100644
--- a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VMwareGuruTest.java
+++ b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VMwareGuruTest.java
@@ -25,6 +25,7 @@
 
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -34,8 +35,7 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.support.AnnotationConfigContextLoader;
 
@@ -54,8 +54,7 @@
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineManager;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({VMwareGuru.class})
+@RunWith(MockitoJUnitRunner.class)
 @ContextConfiguration(loader = AnnotationConfigContextLoader.class)
 public class VMwareGuruTest {
 
@@ -78,9 +77,16 @@
     @Mock
     ClusterDetailsDao _clusterDetailsDao;
 
+    AutoCloseable closeable;
+
     @Before
     public void testSetUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
@@ -99,7 +105,6 @@
         HostVO hostVO = Mockito.mock(HostVO.class);
 
         Mockito.when(localStorage.getId()).thenReturn(1L);
-        Mockito.when(vm.getId()).thenReturn(1L);
         Mockito.when(_storagePoolDao.findById(1L)).thenReturn(storagePoolVO);
         Mockito.when(rootVolume.getVolumeType()).thenReturn(Volume.Type.ROOT);
         Mockito.when(dataVolume.getVolumeType()).thenReturn(Volume.Type.DATADISK);
diff --git a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VmwareVmImplementerTest.java b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VmwareVmImplementerTest.java
index 309eb6d..80f73d6 100755
--- a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VmwareVmImplementerTest.java
+++ b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/guru/VmwareVmImplementerTest.java
@@ -23,7 +23,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.cloudstack.framework.config.ConfigKey;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -32,16 +32,14 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.support.AnnotationConfigContextLoader;
 
 import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.vm.VmDetailConstants;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({ConfigKey.class, VmwareVmImplementer.class})
+@RunWith(MockitoJUnitRunner.class)
 @ContextConfiguration(loader = AnnotationConfigContextLoader.class)
 public class VmwareVmImplementerTest {
 
@@ -54,9 +52,16 @@
 
     private Map<String,String> vmDetails = new HashMap<String, String>();
 
+    AutoCloseable closeable;
+
     @Before
     public void testSetUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     private void setConfigValues(Boolean globalNV, Boolean globalNVPVM, String localNV){
diff --git a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java
index f0a06d0..0629e45 100644
--- a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java
+++ b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java
@@ -80,12 +80,9 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Matchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.ComponentScan.Filter;
@@ -104,11 +101,11 @@
 import java.util.List;
 import java.util.UUID;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
 
 @RunWith(SpringJUnit4ClassRunner.class)
 @ContextConfiguration(loader = AnnotationConfigContextLoader.class)
-@PrepareForTest({ComponentContext.class, ApplicationContext.class})
 public class VmwareDatacenterApiUnitTest {
 
     @Inject
@@ -166,11 +163,13 @@
     @Mock
     private static RemoveVmwareDcCmd removeCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void testSetUp() {
         Mockito.when(_configDao.isPremium()).thenReturn(true);
         ComponentContext.initComponentsLifeCycle();
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
 
         DataCenterVO zone =
             new DataCenterVO(UUID.randomUUID().toString(), "test", "8.8.8.8", null, "10.0.0.1", null, "10.0.0.1/24", null, null, NetworkType.Basic, null, null, true,
@@ -208,21 +207,21 @@
 
         dcZoneMap = new VmwareDatacenterZoneMapVO(zoneId, vmwareDcId);
 
-        Mockito.when(_dcDao.persist(Matchers.any(DataCenterVO.class))).thenReturn(zone);
+        Mockito.when(_dcDao.persist(any(DataCenterVO.class))).thenReturn(zone);
         Mockito.when(_dcDao.findById(1L)).thenReturn(zone);
-        Mockito.when(_podDao.persist(Matchers.any(HostPodVO.class))).thenReturn(pod);
+        Mockito.when(_podDao.persist(any(HostPodVO.class))).thenReturn(pod);
         Mockito.when(_podDao.findById(1L)).thenReturn(pod);
-        Mockito.when(_clusterDao.persist(Matchers.any(ClusterVO.class))).thenReturn(cluster);
+        Mockito.when(_clusterDao.persist(any(ClusterVO.class))).thenReturn(cluster);
         Mockito.when(_clusterDao.findById(1L)).thenReturn(cluster);
         Mockito.when(_clusterDao.listByZoneId(1L)).thenReturn(null);
         Mockito.when(_clusterDao.expunge(1L)).thenReturn(true);
-        Mockito.when(_clusterDetailsDao.persist(Matchers.any(ClusterDetailsVO.class))).thenReturn(clusterDetails);
+        Mockito.when(_clusterDetailsDao.persist(any(ClusterDetailsVO.class))).thenReturn(clusterDetails);
         Mockito.when(_clusterDetailsDao.expunge(1L)).thenReturn(true);
-        Mockito.when(_vmwareDcDao.persist(Matchers.any(VmwareDatacenterVO.class))).thenReturn(dc);
+        Mockito.when(_vmwareDcDao.persist(any(VmwareDatacenterVO.class))).thenReturn(dc);
         Mockito.when(_vmwareDcDao.findById(1L)).thenReturn(null);
         Mockito.when(_vmwareDcDao.expunge(1L)).thenReturn(true);
         Mockito.when(_vmwareDcDao.getVmwareDatacenterByNameAndVcenter(vmwareDcName, vCenterHost)).thenReturn(null);
-        Mockito.when(_vmwareDcZoneMapDao.persist(Matchers.any(VmwareDatacenterZoneMapVO.class))).thenReturn(dcZoneMap);
+        Mockito.when(_vmwareDcZoneMapDao.persist(any(VmwareDatacenterZoneMapVO.class))).thenReturn(dcZoneMap);
         Mockito.when(_vmwareDcZoneMapDao.findByZoneId(1L)).thenReturn(null);
         Mockito.when(_vmwareDcZoneMapDao.expunge(1L)).thenReturn(true);
         Mockito.when(addCmd.getZoneId()).thenReturn(1L);
@@ -234,8 +233,9 @@
     }
 
     @After
-    public void tearDown() {
+    public void tearDown() throws Exception {
         CallContext.unregister();
+        closeable.close();
     }
 
     //@Test(expected = InvalidParameterValueException.class)
diff --git a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImplTest.java b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImplTest.java
index 714036d..0b7eff0 100644
--- a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImplTest.java
+++ b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImplTest.java
@@ -29,7 +29,7 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.Spy;
-import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.dc.ClusterDetailsDao;
 import com.cloud.dc.ClusterVO;
@@ -112,8 +112,8 @@
         Assert.assertEquals(vmwareDatacenter.getUser(), updateVmwareDcCmd.getUsername());
         Assert.assertEquals(vmwareDatacenter.getPassword(), updateVmwareDcCmd.getPassword());
         Mockito.verify(clusterDetails, Mockito.times(2)).put(Mockito.anyString(), Mockito.anyString());
-        Mockito.verify(clusterDetailsDao, Mockito.times(1)).persist(Mockito.anyLong(), Mockito.anyMapOf(String.class, String.class));
+        Mockito.verify(clusterDetailsDao, Mockito.times(1)).persist(Mockito.anyLong(), Mockito.anyMap());
         Mockito.verify(hostDetails, Mockito.times(3)).put(Mockito.anyString(), Mockito.anyString());
-        Mockito.verify(hostDetailsDao, Mockito.times(1)).persist(Mockito.anyLong(), Mockito.anyMapOf(String.class, String.class));
+        Mockito.verify(hostDetailsDao, Mockito.times(1)).persist(Mockito.anyLong(), Mockito.anyMap());
     }
 }
diff --git a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java
index e974c23..da4273d 100644
--- a/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java
+++ b/plugins/hypervisors/vmware/src/test/java/com/cloud/hypervisor/vmware/resource/VmwareResourceTest.java
@@ -19,14 +19,13 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.powermock.api.mockito.PowerMockito.whenNew;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -37,22 +36,25 @@
 
 import org.apache.cloudstack.storage.command.CopyCommand;
 import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InOrder;
 import org.mockito.InjectMocks;
-import org.mockito.Matchers;
 import org.mockito.Mock;
+import org.mockito.MockedConstruction;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.CheckGuestOsMappingAnswer;
+import com.cloud.agent.api.CheckGuestOsMappingCommand;
+import com.cloud.agent.api.GetHypervisorGuestOsNamesAnswer;
+import com.cloud.agent.api.GetHypervisorGuestOsNamesCommand;
 import com.cloud.agent.api.ScaleVmAnswer;
 import com.cloud.agent.api.ScaleVmCommand;
 import com.cloud.agent.api.routing.GetAutoScaleMetricsAnswer;
@@ -79,6 +81,7 @@
 import com.cloud.utils.ExecutionResult;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.VmDetailConstants;
+import com.vmware.vim25.GuestOsDescriptor;
 import com.vmware.vim25.HostCapability;
 import com.vmware.vim25.ManagedObjectReference;
 import com.vmware.vim25.VimPortType;
@@ -87,8 +90,7 @@
 import com.vmware.vim25.VirtualMachineConfigSpec;
 import com.vmware.vim25.VirtualMachineVideoCard;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({CopyCommand.class})
+@RunWith(MockitoJUnitRunner.class)
 public class VmwareResourceTest {
 
     private static final String VOLUME_PATH = "XXXXXXXXXXXX";
@@ -182,10 +184,12 @@
 
     private Map<String,String> specsArray = new HashMap<String,String>();
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        storageCmd = PowerMockito.mock(CopyCommand.class);
+        closeable = MockitoAnnotations.openMocks(this);
+        storageCmd = Mockito.mock(CopyCommand.class);
         doReturn(context).when(_resource).getServiceContext(null);
         when(cmd.getVirtualMachine()).thenReturn(vmSpec);
 
@@ -213,19 +217,17 @@
         when(hostCapability.isNestedHVSupported()).thenReturn(true);
     }
 
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
+    }
+
     //Test successful scaling up the vm
     @Test
     public void testScaleVMF1() throws Exception {
         when(_resource.getHyperHost(context, null)).thenReturn(hyperHost);
         doReturn("i-2-3-VM").when(cmd).getVmName();
         when(hyperHost.findVmOnHyperHost("i-2-3-VM")).thenReturn(vmMo);
-        doReturn(536870912L).when(vmSpec).getMinRam();
-        doReturn(1).when(vmSpec).getCpus();
-        doReturn(1000).when(vmSpec).getMinSpeed();
-        doReturn(1000).when(vmSpec).getMaxSpeed();
-        doReturn(536870912L).when(vmSpec).getMaxRam();
-        doReturn(false).when(vmSpec).getLimitCpuUse();
-        when(vmMo.configureVm(vmConfigSpec)).thenReturn(true);
 
         _resource.execute(cmd);
         verify(_resource).execute(cmd);
@@ -246,7 +248,7 @@
         final NicTO[] nics = new NicTO[] {nicTo1, nicTo2};
 
         String macSequence = _resource.generateMacSequence(nics);
-        assertEquals(macSequence, "02:00:65:b5:00:03|01:23:45:67:89:AB");
+        assertEquals("02:00:65:b5:00:03|01:23:45:67:89:AB", macSequence);
     }
 
     @Test
@@ -399,8 +401,8 @@
     @Test
     public void checkStorageProcessorAndHandlerNfsVersionAttributeVersionNotSet(){
         _resource.checkStorageProcessorAndHandlerNfsVersionAttribute(storageCmd);
-        verify(_resource).examineStorageSubSystemCommandNfsVersion(Matchers.eq(storageCmd), any(EnumMap.class));
-        verify(_resource).examineStorageSubSystemCommandFullCloneFlagForVmware(Matchers.eq(storageCmd), any(EnumMap.class));
+        verify(_resource).examineStorageSubSystemCommandNfsVersion(eq(storageCmd), any(EnumMap.class));
+        verify(_resource).examineStorageSubSystemCommandFullCloneFlagForVmware(eq(storageCmd), any(EnumMap.class));
         verify(_resource).reconfigureProcessorByHandler(any(EnumMap.class));
         assertEquals(NFS_VERSION, _resource.storageNfsVersion);
     }
@@ -410,24 +412,26 @@
     public void checkStorageProcessorAndHandlerNfsVersionAttributeVersionSet(){
         _resource.storageNfsVersion = NFS_VERSION;
         _resource.checkStorageProcessorAndHandlerNfsVersionAttribute(storageCmd);
-        verify(_resource, never()).examineStorageSubSystemCommandNfsVersion(Matchers.eq(storageCmd), any(EnumMap.class));
+        verify(_resource, never()).examineStorageSubSystemCommandNfsVersion(eq(storageCmd), any(EnumMap.class));
     }
 
-    @Test(expected= CloudRuntimeException.class)
+    @Test(expected=CloudRuntimeException.class)
     public void testFindVmOnDatacenterNullHyperHostReference() throws Exception {
-        when(hyperHost.getMor()).thenReturn(null);
-        _resource.findVmOnDatacenter(context, hyperHost, volume);
+        try (MockedConstruction<DatacenterMO> ignored = Mockito.mockConstruction(DatacenterMO.class)) {
+            _resource.findVmOnDatacenter(context, hyperHost, volume);
+        }
     }
 
     @Test
-    @PrepareForTest({DatacenterMO.class, VmwareResource.class})
     public void testFindVmOnDatacenter() throws Exception {
         when(hyperHost.getHyperHostDatacenter()).thenReturn(mor);
-        when(datacenter.getMor()).thenReturn(mor);
-        when(datacenter.findVm(VOLUME_PATH)).thenReturn(vmMo);
-        whenNew(DatacenterMO.class).withArguments(context, mor).thenReturn(datacenter);
-        VirtualMachineMO result = _resource.findVmOnDatacenter(context, hyperHost, volume);
-        assertEquals(vmMo, result);
+        try (MockedConstruction<DatacenterMO> ignored = Mockito.mockConstruction(DatacenterMO.class, (mock, context) -> {
+            when(mock.findVm(VOLUME_PATH)).thenReturn(vmMo);
+            when(mock.getMor()).thenReturn(mor);
+        })) {
+            VirtualMachineMO result = _resource.findVmOnDatacenter(context, hyperHost, volume);
+            assertEquals(vmMo, result);
+        }
     }
 
     @Test
@@ -554,4 +558,102 @@
         assertEquals(1, stats.length);
         assertEquals(lbStats[0], stats[0]);
     }
+
+    @Test
+    public void testCheckGuestOsMappingCommandFailure() throws Exception {
+        CheckGuestOsMappingCommand cmd = Mockito.mock(CheckGuestOsMappingCommand.class);
+        when(cmd.getGuestOsName()).thenReturn("CentOS 7.2");
+        when(cmd.getGuestOsHypervisorMappingName()).thenReturn("centosWrongName");
+        when(_resource.getHyperHost(context, null)).thenReturn(hyperHost);
+        when(hyperHost.getGuestOsDescriptor("centosWrongName")).thenReturn(null);
+
+        CheckGuestOsMappingAnswer answer = _resource.execute(cmd);
+
+        assertFalse(answer.getResult());
+    }
+
+    @Test
+    public void testCheckGuestOsMappingCommandSuccess() throws Exception {
+        CheckGuestOsMappingCommand cmd = Mockito.mock(CheckGuestOsMappingCommand.class);
+        when(cmd.getGuestOsName()).thenReturn("CentOS 7.2");
+        when(cmd.getGuestOsHypervisorMappingName()).thenReturn("centos64Guest");
+        when(_resource.getHyperHost(context, null)).thenReturn(hyperHost);
+        GuestOsDescriptor guestOsDescriptor = Mockito.mock(GuestOsDescriptor.class);
+        when(hyperHost.getGuestOsDescriptor("centos64Guest")).thenReturn(guestOsDescriptor);
+        when(guestOsDescriptor.getFullName()).thenReturn("centos64Guest");
+
+        CheckGuestOsMappingAnswer answer = _resource.execute(cmd);
+
+        assertTrue(answer.getResult());
+    }
+
+    @Test
+    public void testCheckGuestOsMappingCommandException() {
+        CheckGuestOsMappingCommand cmd = Mockito.mock(CheckGuestOsMappingCommand.class);
+        when(cmd.getGuestOsName()).thenReturn("CentOS 7.2");
+        when(cmd.getGuestOsHypervisorMappingName()).thenReturn("centos64Guest");
+        when(_resource.getHyperHost(context, null)).thenReturn(null);
+
+        CheckGuestOsMappingAnswer answer = _resource.execute(cmd);
+
+        assertFalse(answer.getResult());
+    }
+
+    @Test
+    public void testGetHypervisorGuestOsNamesCommandFailure() throws Exception {
+        GetHypervisorGuestOsNamesCommand cmd = Mockito.mock(GetHypervisorGuestOsNamesCommand.class);
+        when(cmd.getKeyword()).thenReturn("CentOS");
+        when(_resource.getHyperHost(context, null)).thenReturn(hyperHost);
+        when(hyperHost.getGuestOsDescriptors()).thenReturn(null);
+
+        GetHypervisorGuestOsNamesAnswer answer = _resource.execute(cmd);
+
+        assertFalse(answer.getResult());
+    }
+
+    @Test
+    public void testGetHypervisorGuestOsNamesCommandSuccessWithKeyword() throws Exception {
+        GetHypervisorGuestOsNamesCommand cmd = Mockito.mock(GetHypervisorGuestOsNamesCommand.class);
+        when(cmd.getKeyword()).thenReturn("CentOS");
+        when(_resource.getHyperHost(context, null)).thenReturn(hyperHost);
+        GuestOsDescriptor guestOsDescriptor = Mockito.mock(GuestOsDescriptor.class);
+        when(guestOsDescriptor.getFullName()).thenReturn("centos64Guest");
+        when(guestOsDescriptor.getId()).thenReturn("centos64Guest");
+        List<GuestOsDescriptor> guestOsDescriptors = new ArrayList<>();
+        guestOsDescriptors.add(guestOsDescriptor);
+        when(hyperHost.getGuestOsDescriptors()).thenReturn(guestOsDescriptors);
+
+        GetHypervisorGuestOsNamesAnswer answer = _resource.execute(cmd);
+
+        assertTrue(answer.getResult());
+        assertEquals("centos64Guest", answer.getHypervisorGuestOsNames().get(0).first());
+    }
+
+    @Test
+    public void testGetHypervisorGuestOsNamesCommandSuccessWithoutKeyword() throws Exception {
+        GetHypervisorGuestOsNamesCommand cmd = Mockito.mock(GetHypervisorGuestOsNamesCommand.class);
+        when(_resource.getHyperHost(context, null)).thenReturn(hyperHost);
+        GuestOsDescriptor guestOsDescriptor = Mockito.mock(GuestOsDescriptor.class);
+        when(guestOsDescriptor.getFullName()).thenReturn("centos64Guest");
+        when(guestOsDescriptor.getId()).thenReturn("centos64Guest");
+        List<GuestOsDescriptor> guestOsDescriptors = new ArrayList<>();
+        guestOsDescriptors.add(guestOsDescriptor);
+        when(hyperHost.getGuestOsDescriptors()).thenReturn(guestOsDescriptors);
+
+        GetHypervisorGuestOsNamesAnswer answer = _resource.execute(cmd);
+
+        assertTrue(answer.getResult());
+        assertEquals("centos64Guest", answer.getHypervisorGuestOsNames().get(0).first());
+    }
+
+    @Test
+    public void testGetHypervisorGuestOsNamesCommandException() throws Exception {
+        GetHypervisorGuestOsNamesCommand cmd = Mockito.mock(GetHypervisorGuestOsNamesCommand.class);
+        when(cmd.getKeyword()).thenReturn("CentOS");
+        when(_resource.getHyperHost(context, null)).thenReturn(null);
+
+        GetHypervisorGuestOsNamesAnswer answer = _resource.execute(cmd);
+
+        assertFalse(answer.getResult());
+    }
 }
diff --git a/plugins/hypervisors/vmware/src/test/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategyTest.java b/plugins/hypervisors/vmware/src/test/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategyTest.java
index fa1137f..35a8ffa 100644
--- a/plugins/hypervisors/vmware/src/test/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategyTest.java
+++ b/plugins/hypervisors/vmware/src/test/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategyTest.java
@@ -18,8 +18,8 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.isA;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.isA;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
diff --git a/plugins/hypervisors/vmware/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/plugins/hypervisors/vmware/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d4
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/plugins/hypervisors/xenserver/pom.xml b/plugins/hypervisors/xenserver/pom.xml
index 721200f..3326d15 100644
--- a/plugins/hypervisors/xenserver/pom.xml
+++ b/plugins/hypervisors/xenserver/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCheckGuestOsMappingCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCheckGuestOsMappingCommandWrapper.java
new file mode 100644
index 0000000..68403d7
--- /dev/null
+++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCheckGuestOsMappingCommandWrapper.java
@@ -0,0 +1,67 @@
+//
+// 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.hypervisor.xenserver.resource.wrapper.xenbase;
+
+import java.util.Set;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.CheckGuestOsMappingAnswer;
+import com.cloud.agent.api.CheckGuestOsMappingCommand;
+import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase;
+import com.cloud.resource.CommandWrapper;
+import com.cloud.resource.ResourceWrapper;
+import com.xensource.xenapi.Connection;
+import com.xensource.xenapi.VM;
+
+@ResourceWrapper(handles =  CheckGuestOsMappingCommand.class)
+public final class CitrixCheckGuestOsMappingCommandWrapper extends CommandWrapper<CheckGuestOsMappingCommand, Answer, CitrixResourceBase> {
+
+    private static final Logger s_logger = Logger.getLogger(CitrixCheckGuestOsMappingCommandWrapper.class);
+
+    @Override
+    public Answer execute(final CheckGuestOsMappingCommand command, final CitrixResourceBase citrixResourceBase) {
+        final Connection conn = citrixResourceBase.getConnection();
+        String guestOsName = command.getGuestOsName();
+        String guestOsMappingName = command.getGuestOsHypervisorMappingName();
+        try {
+            s_logger.info("Checking guest os mapping name: " + guestOsMappingName + " for the guest os: " + guestOsName + " in the hypervisor");
+            final Set<VM> vms = VM.getAll(conn);
+            if (CollectionUtils.isEmpty(vms)) {
+                return new CheckGuestOsMappingAnswer(command, "Unable to match guest os mapping name: " + guestOsMappingName + " in the hypervisor");
+            }
+            for (VM vm : vms) {
+                if (vm != null && vm.getIsATemplate(conn) && guestOsMappingName.equalsIgnoreCase(vm.getNameLabel(conn))) {
+                    if (guestOsName.equalsIgnoreCase(vm.getNameLabel(conn))) {
+                        s_logger.debug("Hypervisor guest os name label matches with os name: " + guestOsName);
+                    }
+                    s_logger.info("Hypervisor guest os name label matches with os mapping: " + guestOsMappingName + " from user");
+                    return new CheckGuestOsMappingAnswer(command);
+                }
+            }
+            return new CheckGuestOsMappingAnswer(command, "Guest os mapping name: " + guestOsMappingName + " not found in the hypervisor");
+        } catch (final Exception e) {
+            s_logger.error("Failed to find the hypervisor guest os mapping name: " + guestOsMappingName, e);
+            return new CheckGuestOsMappingAnswer(command, e.getLocalizedMessage());
+        }
+    }
+}
diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetHypervisorGuestOsNamesCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetHypervisorGuestOsNamesCommandWrapper.java
new file mode 100644
index 0000000..0be3e5a
--- /dev/null
+++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixGetHypervisorGuestOsNamesCommandWrapper.java
@@ -0,0 +1,76 @@
+//
+// 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.hypervisor.xenserver.resource.wrapper.xenbase;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.GetHypervisorGuestOsNamesAnswer;
+import com.cloud.agent.api.GetHypervisorGuestOsNamesCommand;
+import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase;
+import com.cloud.resource.CommandWrapper;
+import com.cloud.resource.ResourceWrapper;
+import com.cloud.utils.Pair;
+import com.xensource.xenapi.Connection;
+import com.xensource.xenapi.VM;
+
+@ResourceWrapper(handles =  GetHypervisorGuestOsNamesCommand.class)
+public final class CitrixGetHypervisorGuestOsNamesCommandWrapper extends CommandWrapper<GetHypervisorGuestOsNamesCommand, Answer, CitrixResourceBase> {
+
+    private static final Logger s_logger = Logger.getLogger(CitrixGetHypervisorGuestOsNamesCommandWrapper.class);
+
+    @Override
+    public Answer execute(final GetHypervisorGuestOsNamesCommand command, final CitrixResourceBase citrixResourceBase) {
+        final Connection conn = citrixResourceBase.getConnection();
+        String keyword = command.getKeyword();
+        try {
+            s_logger.info("Getting guest os names in the hypervisor");
+            final Set<VM> vms = VM.getAll(conn);
+            if (CollectionUtils.isEmpty(vms)) {
+                return new GetHypervisorGuestOsNamesAnswer(command, "Guest os names not found in the hypervisor");
+            }
+            List<Pair<String, String>> hypervisorGuestOsNames = new ArrayList<>();
+            for (VM vm : vms) {
+                if (vm != null && vm.getIsATemplate(conn)) {
+                    String guestOSNameLabel = vm.getNameLabel(conn);
+                    if (StringUtils.isNotBlank(keyword)) {
+                        if (guestOSNameLabel.toLowerCase().contains(keyword.toLowerCase())) {
+                            Pair<String, String> hypervisorGuestOs = new Pair<>(guestOSNameLabel, guestOSNameLabel);
+                            hypervisorGuestOsNames.add(hypervisorGuestOs);
+                        }
+                    } else {
+                        Pair<String, String> hypervisorGuestOs = new Pair<>(guestOSNameLabel, guestOSNameLabel);
+                        hypervisorGuestOsNames.add(hypervisorGuestOs);
+                    }
+                }
+            }
+            return new GetHypervisorGuestOsNamesAnswer(command, hypervisorGuestOsNames);
+        } catch (final Exception e) {
+            s_logger.error("Failed to fetch hypervisor guest os names due to: " + e.getLocalizedMessage(), e);
+            return new GetHypervisorGuestOsNamesAnswer(command, e.getLocalizedMessage());
+        }
+    }
+}
diff --git a/plugins/hypervisors/xenserver/src/main/resources/META-INF/cloudstack/xenserver-compute/module.properties b/plugins/hypervisors/xenserver/src/main/resources/META-INF/cloudstack/xenserver-compute/module.properties
index c6c91f6..875ae36 100644
--- a/plugins/hypervisors/xenserver/src/main/resources/META-INF/cloudstack/xenserver-compute/module.properties
+++ b/plugins/hypervisors/xenserver/src/main/resources/META-INF/cloudstack/xenserver-compute/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=xenserver-compute
-parent=compute
\ No newline at end of file
+parent=compute
diff --git a/plugins/hypervisors/xenserver/src/main/resources/META-INF/cloudstack/xenserver-discoverer/module.properties b/plugins/hypervisors/xenserver/src/main/resources/META-INF/cloudstack/xenserver-discoverer/module.properties
index 10d0ecd..f24912b 100644
--- a/plugins/hypervisors/xenserver/src/main/resources/META-INF/cloudstack/xenserver-discoverer/module.properties
+++ b/plugins/hypervisors/xenserver/src/main/resources/META-INF/cloudstack/xenserver-discoverer/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=xenserver-discoverer
-parent=discoverer
\ No newline at end of file
+parent=discoverer
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java
index df9e9a4..27a1087 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java
@@ -24,6 +24,7 @@
 import java.util.Set;
 
 import org.apache.xmlrpc.XmlRpcException;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -31,11 +32,9 @@
 import org.mockito.BDDMockito;
 import org.mockito.InOrder;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 import org.mockito.Spy;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
 
 import com.cloud.agent.api.StartupStorageCommand;
 import com.cloud.agent.api.StoragePoolInfo;
@@ -52,13 +51,13 @@
 import com.xensource.xenapi.PBD;
 import com.xensource.xenapi.SR;
 import com.xensource.xenapi.Types.XenAPIException;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import static com.cloud.hypervisor.xenserver.resource.CitrixResourceBase.PLATFORM_CORES_PER_SOCKET_KEY;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.doReturn;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({Host.class, Script.class, SR.class})
+@RunWith(MockitoJUnitRunner.class)
 public class CitrixResourceBaseTest {
 
     @Spy
@@ -87,40 +86,48 @@
     final static String publicIp = "10.10.10.10";
     final static Integer port = 8080;
 
+    MockedStatic<Host> hostMocked;
+
     @Before
     public void beforeTest() throws XenAPIException, XmlRpcException {
         citrixResourceBase._host.setUuid(hostUuidMock);
 
-        PowerMockito.mockStatic(Host.class);
-        PowerMockito.when(Host.getByUuid(connectionMock, hostUuidMock)).thenReturn(hostMock);
+        hostMocked = Mockito.mockStatic(Host.class);
+        hostMocked.when(() -> Host.getByUuid(connectionMock, hostUuidMock)).thenReturn(hostMock);
 
         hostRecordMock.softwareVersion = new HashMap<>();
         Mockito.when(hostMock.getRecord(connectionMock)).thenReturn(hostRecordMock);
 
     }
 
-    public void testGetPathFilesExeption() {
+    public void testGetPathFilesException() {
         String patch = citrixResourceBase.getPatchFilePath();
 
-        PowerMockito.mockStatic(Script.class);
-        Mockito.when(Script.findScript("", patch)).thenReturn(null);
+        try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
+            Mockito.when(Script.findScript("", patch)).thenReturn(null);
 
-        citrixResourceBase.getPatchFiles();
-
+            citrixResourceBase.getPatchFiles();
+        }
     }
 
     public void testGetPathFilesListReturned() {
         String patch = citrixResourceBase.getPatchFilePath();
 
-        PowerMockito.mockStatic(Script.class);
-        Mockito.when(Script.findScript("", patch)).thenReturn(patch);
+        try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
+            Mockito.when(Script.findScript("", patch)).thenReturn(patch);
 
-        File expected = new File(patch);
-        String pathExpected = expected.getAbsolutePath();
+            File expected = new File(patch);
+            String pathExpected = expected.getAbsolutePath();
 
-        List<File> files = citrixResourceBase.getPatchFiles();
-        String receivedPath = files.get(0).getAbsolutePath();
-        Assert.assertEquals(receivedPath, pathExpected);
+            List<File> files = citrixResourceBase.getPatchFiles();
+            String receivedPath = files.get(0).getAbsolutePath();
+            Assert.assertEquals(receivedPath, pathExpected);
+        }
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        hostMocked.close();
     }
 
     @Test
@@ -233,14 +240,14 @@
         Map<SR, SR.Record> mapOfSrsRecords = new HashMap<>();
         mapOfSrsRecords.put(srExtShared, srExtSharedRecord);
         mapOfSrsRecords.put(srExtNonShared, srExtNonSharedRecord);
+        try (MockedStatic<SR> ignored = Mockito.mockStatic(SR.class)) {
+            BDDMockito.given(SR.getAllRecords(connectionMock)).willReturn(mapOfSrsRecords);
 
-        PowerMockito.mockStatic(SR.class);
-        BDDMockito.given(SR.getAllRecords(connectionMock)).willReturn(mapOfSrsRecords);
+            List<SR> allLocalSrForType = citrixResourceBase.getAllLocalSrForType(connectionMock, SRType.EXT);
 
-        List<SR> allLocalSrForType = citrixResourceBase.getAllLocalSrForType(connectionMock, SRType.EXT);
-
-        Assert.assertEquals(expectedListOfSrs.size(), allLocalSrForType.size());
-        Assert.assertEquals(expectedListOfSrs.get(0), allLocalSrForType.get(0));
+            Assert.assertEquals(expectedListOfSrs.size(), allLocalSrForType.size());
+            Assert.assertEquals(expectedListOfSrs.get(0), allLocalSrForType.get(0));
+        }
     }
 
     @Test
@@ -287,9 +294,7 @@
         String hostUuid = "hostUuid";
         citrixResourceBase._host.setUuid(hostUuid);
 
-        PowerMockito.mockStatic(Host.class);
-        PowerMockito.when(Host.getByUuid(connectionMock, hostUuid)).thenReturn(hostMock);
-
+        Mockito.when(Host.getByUuid(connectionMock, hostUuid)).thenReturn(hostMock);
         String srType = "ext";
         String srUuid = "srUuid";
         long srPhysicalSize = 100l;
@@ -432,7 +437,6 @@
         CitrixResourceBase citrixResourceBaseSpy = Mockito.spy(CitrixResourceBase.class);
         Connection connection = Mockito.mock(Connection.class);
 
-        String args = "-g -l " + publicIp;
         doReturn(networkStats[0] + ":" + networkStats[1]).when(citrixResourceBaseSpy).networkUsage(Mockito.any(Connection.class),
                 Mockito.eq(privateIp), Mockito.eq("get"), Mockito.any(), Mockito.eq(publicIp));
 
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java
index 8f703ed..e02279b 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XcpOssResourceTest.java
@@ -43,7 +43,7 @@
 
     @Test(expected = CloudRuntimeException.class)
     public void testGetFiles() {
-        testGetPathFilesExeption();
+        testGetPathFilesException();
     }
 
     @Test
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java
index 6a926a7..ed074be 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XcpServerResourceTest.java
@@ -46,8 +46,8 @@
     }
 
     @Test(expected = CloudRuntimeException.class)
-    public void testGetFilesExeption() {
-        testGetPathFilesExeption();
+    public void testGetFilesException() {
+        testGetPathFilesException();
     }
 
     @Test
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java
index 902e8fd..d7f1774 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer56FP1ResourceTest.java
@@ -43,7 +43,7 @@
 
     @Test(expected = CloudRuntimeException.class)
     public void testGetFiles() {
-        testGetPathFilesExeption();
+        testGetPathFilesException();
     }
 
     @Test
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java
index 1762772..a33549a 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer56ResourceTest.java
@@ -47,7 +47,7 @@
 
     @Test(expected = CloudRuntimeException.class)
     public void testGetFiles() {
-        testGetPathFilesExeption();
+        testGetPathFilesException();
     }
 
     @Test
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java
index 65a9b47..c3c8d46 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer56SP2ResourceTest.java
@@ -43,7 +43,7 @@
 
     @Test(expected = CloudRuntimeException.class)
     public void testGetFiles() {
-        testGetPathFilesExeption();
+        testGetPathFilesException();
     }
 
     @Test
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java
index 2175884..773dd57 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer600ResourceTest.java
@@ -43,7 +43,7 @@
 
     @Test(expected = CloudRuntimeException.class)
     public void testGetFiles() {
-        testGetPathFilesExeption();
+        testGetPathFilesException();
     }
 
     @Test
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java
index fc14d9f..7fb3f7e 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer625ResourceTest.java
@@ -43,7 +43,7 @@
 
     @Test(expected = CloudRuntimeException.class)
     public void testGetFiles() {
-        testGetPathFilesExeption();
+        testGetPathFilesException();
     }
 
     @Test
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java
index be41840..dbb4198 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/XenServer650ResourceTest.java
@@ -43,7 +43,7 @@
 
     @Test(expected = CloudRuntimeException.class)
     public void testGetFiles() {
-        testGetPathFilesExeption();
+        testGetPathFilesException();
     }
 
     @Test
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessorTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessorTest.java
index 0705194..5f2ae88 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessorTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/Xenserver625StorageProcessorTest.java
@@ -37,10 +37,9 @@
 import org.mockito.InOrder;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.xensource.xenapi.Connection;
@@ -51,7 +50,7 @@
 import com.xensource.xenapi.Types.InternalError;
 import com.xensource.xenapi.Types.XenAPIException;
 
-@RunWith(PowerMockRunner.class)
+@RunWith(MockitoJUnitRunner.class)
 public class Xenserver625StorageProcessorTest {
 
     @InjectMocks
@@ -109,10 +108,8 @@
     @Test
     public void createFileSRTestSrAlreadyConfigured() {
         SR srMockRetrievedMethod = Mockito.mock(SR.class);
-        SR srMockCreateMethod = Mockito.mock(SR.class);
 
         Mockito.doReturn(srMockRetrievedMethod).when(xenserver625StorageProcessor).retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
-        Mockito.doReturn(srMockCreateMethod).when(xenserver625StorageProcessor).createNewFileSr(connectionMock, pathMock);
 
         SR methodCreateFileSrResult = xenserver625StorageProcessor.createFileSR(connectionMock, pathMock);
 
@@ -172,47 +169,39 @@
     }
 
     @Test
-    @PrepareForTest(SR.class)
     public void retrieveAlreadyConfiguredSrTestNoSrFound() throws XenAPIException, XmlRpcException {
-        prepareToReturnSrs(null);
+        try (MockedStatic<SR> srMocked = Mockito.mockStatic(SR.class)) {
+            Mockito.when(SR.getByNameLabel(connectionMock, pathMock)).thenReturn(null);
+            SR sr = xenserver625StorageProcessor.retrieveAlreadyConfiguredSr(connectionMock, pathMock);
 
-        SR sr = xenserver625StorageProcessor.retrieveAlreadyConfiguredSr(connectionMock, pathMock);
-
-        PowerMockito.verifyStatic(SR.class);
-        SR.getByNameLabel(connectionMock, pathMock);
-        Assert.assertNull(sr);
+            srMocked.verify(() -> SR.getByNameLabel(connectionMock, pathMock), times(1));
+            Assert.assertNull(sr);
+        }
     }
 
-    private void prepareToReturnSrs(Set<SR> srs) throws XenAPIException, XmlRpcException {
-        PowerMockito.mockStatic(SR.class);
-        PowerMockito.when(SR.getByNameLabel(connectionMock, pathMock)).thenReturn(srs);
-    }
-
-    @PrepareForTest(SR.class)
     @Test(expected = CloudRuntimeException.class)
     public void retrieveAlreadyConfiguredSrTestMultipleSrsFound() throws XenAPIException, XmlRpcException {
         HashSet<SR> srs = new HashSet<>();
         srs.add(Mockito.mock(SR.class));
         srs.add(Mockito.mock(SR.class));
 
-        prepareToReturnSrs(srs);
+        try (MockedStatic<SR> ignored = Mockito.mockStatic(SR.class)) {
+            Mockito.when(SR.getByNameLabel(connectionMock, pathMock)).thenReturn(srs);
 
-        xenserver625StorageProcessor.retrieveAlreadyConfiguredSr(connectionMock, pathMock);
+            xenserver625StorageProcessor.retrieveAlreadyConfiguredSr(connectionMock, pathMock);
+        }
     }
 
     @Test
-    @PrepareForTest(SR.class)
     public void retrieveAlreadyConfiguredSrTestSrFailsSanityCheckWithXenAPIException() throws XenAPIException, XmlRpcException {
         configureAndExecuteMethodRetrieveAlreadyConfiguredSrTestSrFailsSanityCheckForException(XenAPIException.class);
     }
 
     @Test
-    @PrepareForTest(SR.class)
     public void retrieveAlreadyConfiguredSrTestSrFailsSanityCheckWithXmlRpcException() throws XenAPIException, XmlRpcException {
         configureAndExecuteMethodRetrieveAlreadyConfiguredSrTestSrFailsSanityCheckForException(XmlRpcException.class);
     }
 
-    @PrepareForTest(SR.class)
     @Test(expected = RuntimeException.class)
     public void retrieveAlreadyConfiguredSrTestSrFailsSanityCheckWithRuntimeException() throws XenAPIException, XmlRpcException {
         configureAndExecuteMethodRetrieveAlreadyConfiguredSrTestSrFailsSanityCheckForException(RuntimeException.class);
@@ -225,17 +214,18 @@
         HashSet<SR> srs = new HashSet<>();
         srs.add(srMock);
 
-        prepareToReturnSrs(srs);
-        Mockito.doNothing().when(xenserver625StorageProcessor).forgetSr(connectionMock, srMock);
+        try (MockedStatic<SR> ignored = Mockito.mockStatic(SR.class)) {
+            Mockito.when(SR.getByNameLabel(connectionMock, pathMock)).thenReturn(srs);
+            Mockito.doNothing().when(xenserver625StorageProcessor).forgetSr(connectionMock, srMock);
 
-        SR sr = xenserver625StorageProcessor.retrieveAlreadyConfiguredSr(connectionMock, pathMock);
+            SR sr = xenserver625StorageProcessor.retrieveAlreadyConfiguredSr(connectionMock, pathMock);
 
-        Assert.assertNull(sr);
-        Mockito.verify(xenserver625StorageProcessor).forgetSr(connectionMock, srMock);
+            Assert.assertNull(sr);
+            Mockito.verify(xenserver625StorageProcessor).forgetSr(connectionMock, srMock);
+        }
     }
 
     @Test
-    @PrepareForTest(SR.class)
     public void methodRetrieveAlreadyConfiguredSrTestSrScanSucceeds() throws XenAPIException, XmlRpcException {
         SR srMock = Mockito.mock(SR.class);
         Mockito.doNothing().when(srMock).scan(connectionMock);
@@ -243,13 +233,14 @@
         HashSet<SR> srs = new HashSet<>();
         srs.add(srMock);
 
-        prepareToReturnSrs(srs);
-        Mockito.doNothing().when(xenserver625StorageProcessor).forgetSr(connectionMock, srMock);
+        try (MockedStatic<SR> ignored = Mockito.mockStatic(SR.class)) {
+            Mockito.when(SR.getByNameLabel(connectionMock, pathMock)).thenReturn(srs);
 
-        SR sr = xenserver625StorageProcessor.retrieveAlreadyConfiguredSr(connectionMock, pathMock);
+            SR sr = xenserver625StorageProcessor.retrieveAlreadyConfiguredSr(connectionMock, pathMock);
 
-        Assert.assertEquals(srMock, sr);
-        Mockito.verify(xenserver625StorageProcessor, times(0)).forgetSr(connectionMock, srMock);
+            Assert.assertEquals(srMock, sr);
+            Mockito.verify(xenserver625StorageProcessor, times(0)).forgetSr(connectionMock, srMock);
+        }
     }
 
     @Test
@@ -301,19 +292,16 @@
     }
 
     @Test
-    @PrepareForTest({Host.class, SR.class})
     public void createNewFileSrTestThrowingXenAPIException() throws XenAPIException, XmlRpcException {
         prepareAndExecuteTestcreateNewFileSrTestThrowingException(XenAPIException.class);
     }
 
     @Test
-    @PrepareForTest({Host.class, SR.class})
     public void createNewFileSrTestThrowingXmlRpcException() throws XenAPIException, XmlRpcException {
         prepareAndExecuteTestcreateNewFileSrTestThrowingException(XmlRpcException.class);
     }
 
     @Test(expected = RuntimeException.class)
-    @PrepareForTest({Host.class, SR.class})
     public void createNewFileSrTestThrowingRuntimeException() throws XenAPIException, XmlRpcException {
         prepareAndExecuteTestcreateNewFileSrTestThrowingException(RuntimeException.class);
     }
@@ -326,23 +314,23 @@
 
         Host hostMock = Mockito.mock(Host.class);
 
-        PowerMockito.mockStatic(Host.class);
-        PowerMockito.when(Host.getByUuid(connectionMock, uuid)).thenReturn(hostMock);
+        try (MockedStatic<Host> ignored = Mockito.mockStatic(
+                Host.class); MockedStatic<SR> ignored1 = Mockito.mockStatic(SR.class)) {
+            Mockito.when(Host.getByUuid(connectionMock, uuid)).thenReturn(hostMock);
+            Mockito.when(SR.introduce(Mockito.eq(connectionMock), Mockito.eq(srUuid), Mockito.eq(pathMock),
+                    Mockito.eq(pathMock), Mockito.eq("file"), Mockito.eq("file"), Mockito.eq(false),
+                    Mockito.anyMap())).thenThrow(Mockito.mock(exceptionClass));
 
-        PowerMockito.mockStatic(SR.class);
-        PowerMockito.when(SR.introduce(Mockito.eq(connectionMock), Mockito.eq(srUuid), Mockito.eq(pathMock), Mockito.eq(pathMock), Mockito.eq("file"), Mockito.eq("file"), Mockito.eq(false),
-                Mockito.anyMapOf(String.class, String.class))).thenThrow(Mockito.mock(exceptionClass));
 
-        Mockito.doNothing().when(xenserver625StorageProcessor).removeSrAndPbdIfPossible(Mockito.eq(connectionMock), Mockito.any(SR.class), Mockito.any(PBD.class));
+            SR sr = xenserver625StorageProcessor.createNewFileSr(connectionMock, pathMock);
 
-        SR sr = xenserver625StorageProcessor.createNewFileSr(connectionMock, pathMock);
-
-        assertNull(sr);
-        Mockito.verify(xenserver625StorageProcessor).removeSrAndPbdIfPossible(Mockito.eq(connectionMock), nullable(SR.class), nullable(PBD.class));
+            assertNull(sr);
+            Mockito.verify(xenserver625StorageProcessor).removeSrAndPbdIfPossible(Mockito.eq(connectionMock),
+                    nullable(SR.class), nullable(PBD.class));
+        }
     }
 
     @Test
-    @PrepareForTest({Host.class, SR.class})
     public void createNewFileSrTestThrowingDbUniqueException() throws XenAPIException, XmlRpcException {
         String uuid = "hostUuid";
         Mockito.when(citrixResourceBase._host.getUuid()).thenReturn(uuid);
@@ -353,61 +341,66 @@
 
         Host hostMock = Mockito.mock(Host.class);
 
-        PowerMockito.mockStatic(Host.class);
-        PowerMockito.when(Host.getByUuid(connectionMock, uuid)).thenReturn(hostMock);
+        try (MockedStatic<Host> ignored = Mockito.mockStatic(Host.class);MockedStatic<SR> ignored1 =
+                Mockito.mockStatic(SR.class) ) {
+            Mockito.when(Host.getByUuid(connectionMock, uuid)).thenReturn(hostMock);
 
-        PowerMockito.mockStatic(SR.class);
-        InternalError dbUniquenessException = new InternalError("message: Db_exn.Uniqueness_constraint_violation(\"SR\", \"uuid\", \"fd3edbcf-f142-83d1-3fcb-029ca2446b68\")");
+            InternalError dbUniquenessException = new InternalError(
+                    "message: Db_exn.Uniqueness_constraint_violation(\"SR\", \"uuid\", \"fd3edbcf-f142-83d1-3fcb-029ca2446b68\")");
 
-        PowerMockito.when(SR.introduce(Mockito.eq(connectionMock), Mockito.eq(srUuid), Mockito.eq(pathMock), Mockito.eq(pathMock), Mockito.eq("file"), Mockito.eq("file"), Mockito.eq(false),
-                Mockito.anyMapOf(String.class, String.class))).thenThrow(dbUniquenessException);
+            Mockito.when(SR.introduce(Mockito.eq(connectionMock), Mockito.eq(srUuid), Mockito.eq(pathMock),
+                    Mockito.eq(pathMock), Mockito.eq("file"), Mockito.eq("file"), Mockito.eq(false),
+                    Mockito.anyMap())).thenThrow(dbUniquenessException);
 
-        Mockito.doNothing().when(xenserver625StorageProcessor).removeSrAndPbdIfPossible(Mockito.eq(connectionMock), Mockito.any(SR.class), Mockito.any(PBD.class));
+            SR sr = xenserver625StorageProcessor.createNewFileSr(connectionMock, pathMock);
 
-        SR sr = xenserver625StorageProcessor.createNewFileSr(connectionMock, pathMock);
-
-        Assert.assertEquals(srMock, sr);
-        Mockito.verify(xenserver625StorageProcessor, times(0)).removeSrAndPbdIfPossible(Mockito.eq(connectionMock), Mockito.any(SR.class), Mockito.any(PBD.class));
-        Mockito.verify(xenserver625StorageProcessor).retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+            Assert.assertEquals(srMock, sr);
+            Mockito.verify(xenserver625StorageProcessor, times(0)).removeSrAndPbdIfPossible(Mockito.eq(connectionMock),
+                    Mockito.any(SR.class), Mockito.any(PBD.class));
+            Mockito.verify(xenserver625StorageProcessor).retrieveAlreadyConfiguredSrWithoutException(connectionMock,
+                    pathMock);
+        }
     }
 
     @Test
-    @PrepareForTest({Host.class, SR.class, PBD.class})
     public void createNewFileSrTest() throws XenAPIException, XmlRpcException {
         String uuid = "hostUuid";
         Mockito.when(citrixResourceBase._host.getUuid()).thenReturn(uuid);
 
         SR srMock = Mockito.mock(SR.class);
-        Mockito.doReturn(srMock).when(xenserver625StorageProcessor).retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
         String srUuid = UUID.nameUUIDFromBytes(pathMock.getBytes()).toString();
 
         Host hostMock = Mockito.mock(Host.class);
 
-        PowerMockito.mockStatic(Host.class);
-        PowerMockito.when(Host.getByUuid(connectionMock, uuid)).thenReturn(hostMock);
+        try (MockedStatic<Host> ignored = Mockito.mockStatic(Host.class);MockedStatic<SR> ignored1 =
+                Mockito.mockStatic(SR.class);MockedStatic<PBD> pbdMockedStatic = Mockito.mockStatic(PBD.class)) {
+            Mockito.when(Host.getByUuid(connectionMock, uuid)).thenReturn(hostMock);
 
-        PowerMockito.mockStatic(SR.class);
-        PowerMockito.when(SR.introduce(Mockito.eq(connectionMock), Mockito.eq(srUuid), Mockito.eq(pathMock), Mockito.eq(pathMock), Mockito.eq("file"), Mockito.eq("file"), Mockito.eq(false),
-                Mockito.anyMapOf(String.class, String.class))).thenReturn(srMock);
 
-        PowerMockito.mockStatic(PBD.class);
-        PBD pbdMock = Mockito.mock(PBD.class);
-        PowerMockito.when(PBD.create(Mockito.eq(connectionMock), Mockito.any(Record.class))).thenReturn(pbdMock);
+            Mockito.when(SR.introduce(Mockito.eq(connectionMock), Mockito.eq(srUuid), Mockito.eq(pathMock),
+                    Mockito.eq(pathMock), Mockito.eq("file"), Mockito.eq("file"), Mockito.eq(false),
+                    Mockito.anyMap())).thenReturn(srMock);
 
-        Mockito.doNothing().when(xenserver625StorageProcessor).removeSrAndPbdIfPossible(Mockito.eq(connectionMock), Mockito.any(SR.class), Mockito.any(PBD.class));
-        SR sr = xenserver625StorageProcessor.createNewFileSr(connectionMock, pathMock);
+            PBD pbdMock = Mockito.mock(PBD.class);
+            Mockito.when(PBD.create(Mockito.eq(connectionMock), Mockito.any(Record.class))).thenReturn(pbdMock);
 
-        Assert.assertEquals(srMock, sr);
-        Mockito.verify(xenserver625StorageProcessor, times(0)).removeSrAndPbdIfPossible(Mockito.eq(connectionMock), Mockito.any(SR.class), Mockito.any(PBD.class));
-        Mockito.verify(xenserver625StorageProcessor, times(0)).retrieveAlreadyConfiguredSrWithoutException(connectionMock, pathMock);
+            SR sr = xenserver625StorageProcessor.createNewFileSr(connectionMock, pathMock);
 
-        Mockito.verify(srMock).scan(connectionMock);
-        Mockito.verify(pbdMock).plug(connectionMock);
+            Assert.assertEquals(srMock, sr);
+            Mockito.verify(xenserver625StorageProcessor, times(0)).removeSrAndPbdIfPossible(Mockito.eq(connectionMock),
+                    Mockito.any(SR.class), Mockito.any(PBD.class));
+            Mockito.verify(xenserver625StorageProcessor, times(0)).retrieveAlreadyConfiguredSrWithoutException(
+                    connectionMock, pathMock);
 
-        PowerMockito.verifyStatic(PBD.class);
-        SR.introduce(Mockito.eq(connectionMock), Mockito.eq(srUuid), Mockito.eq(pathMock), Mockito.eq(pathMock), Mockito.eq("file"), Mockito.eq("file"), Mockito.eq(false),
-                Mockito.anyMapOf(String.class, String.class));
-        PBD.create(Mockito.eq(connectionMock), Mockito.any(Record.class));
+            Mockito.verify(srMock).scan(connectionMock);
+            Mockito.verify(pbdMock).plug(connectionMock);
+
+            SR.introduce(Mockito.eq(connectionMock), Mockito.eq(srUuid), Mockito.eq(pathMock), Mockito.eq(pathMock),
+                    Mockito.eq("file"), Mockito.eq("file"), Mockito.eq(false),
+                    Mockito.anyMap());
+
+            pbdMockedStatic.verify(() -> PBD.create(Mockito.eq(connectionMock), Mockito.any(Record.class)));
+        }
     }
 
     @Test
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java
index 9d18e73..9ecb14d 100755
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRequestWrapperTest.java
@@ -40,14 +40,12 @@
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.storage.to.VolumeObjectTO;
 import org.apache.xmlrpc.XmlRpcException;
-import org.apache.xmlrpc.client.XmlRpcClient;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.AttachIsoCommand;
@@ -144,9 +142,9 @@
 import com.xensource.xenapi.Types.XenAPIException;
 import com.xensource.xenapi.VM;
 import com.xensource.xenapi.VMGuestMetrics;
+import org.springframework.test.util.ReflectionTestUtils;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(value = {Pool.Record.class})
+@RunWith(MockitoJUnitRunner.class)
 public class CitrixRequestWrapperTest {
 
     @Mock
@@ -411,15 +409,12 @@
     @Test
     public void testDeleteStoragePoolCommand() {
         final StoragePoolVO poolVO = Mockito.mock(StoragePoolVO.class);
-        final XsHost xsHost = Mockito.mock(XsHost.class);
 
         final DeleteStoragePoolCommand deleteStorageCommand = new DeleteStoragePoolCommand(poolVO);
 
         final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
         assertNotNull(wrapper);
 
-        when(citrixResourceBase.getHost()).thenReturn(xsHost);
-
         final Answer answer = wrapper.execute(deleteStorageCommand, citrixResourceBase);
         verify(citrixResourceBase, times(1)).getConnection();
 
@@ -536,7 +531,6 @@
 
     @Test
     public void testSetupCommand() {
-        final XsHost xsHost = Mockito.mock(XsHost.class);
         final HostEnvironment env = Mockito.mock(HostEnvironment.class);
 
         final SetupCommand setupCommand = new SetupCommand(env);
@@ -544,8 +538,6 @@
         final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
         assertNotNull(wrapper);
 
-        when(citrixResourceBase.getHost()).thenReturn(xsHost);
-
         final Answer answer = wrapper.execute(setupCommand, citrixResourceBase);
         verify(citrixResourceBase, times(1)).getConnection();
 
@@ -560,10 +552,6 @@
 
         final Connection conn = Mockito.mock(Connection.class);
         final XsHost xsHost = Mockito.mock(XsHost.class);
-        final XmlRpcClient client = Mockito.mock(XmlRpcClient.class);
-
-        // final Host.Record hr = PowerMockito.mock(Host.Record.class);
-        // final Host host = PowerMockito.mock(Host.class);
 
         final MaintainCommand maintainCommand = new MaintainCommand();
 
@@ -582,8 +570,8 @@
 
         try {
             final Object[] params = { Marshalling.toXMLRPC("befc4dcd"), Marshalling.toXMLRPC(uuid) };
-            when(client.execute("host.get_by_uuid", new Object[] { "befc4dcd", uuid })).thenReturn(spiedMap);
-            PowerMockito.when(conn, "dispatch", "host.get_by_uuid", params).thenReturn(spiedMap);
+
+            when(ReflectionTestUtils.invokeMethod(conn, "dispatch", "host.get_by_uuid", params)).thenReturn(spiedMap);
         } catch (final Exception e) {
             fail(e.getMessage());
         }
@@ -936,11 +924,6 @@
             when(citrixResourceBase.findOrCreateTunnelNetwork(conn, physicalTopology.getBridgeName())).thenReturn(network);
             when(network.getBridge(conn)).thenReturn(bridge);
 
-            when(
-                            citrixResourceBase.callHostPlugin(conn, "ovstunnel", "configure_ovs_bridge_for_network_topology", "bridge", bridge, "config",
-                                            physicalTopology.getVpcConfigInJson(), "host-id", ((Long) physicalTopology.getHostId()).toString(), "seq-no", Long.toString(1))).thenReturn(
-                            "SUCCESS");
-
         } catch (final BadServerResponse e) {
             fail(e.getMessage());
         } catch (final XenAPIException e) {
@@ -975,11 +958,6 @@
             when(citrixResourceBase.findOrCreateTunnelNetwork(conn, routingPolicy.getBridgeName())).thenReturn(network);
             when(network.getBridge(conn)).thenReturn(bridge);
 
-            when(
-                            citrixResourceBase.callHostPlugin(conn, "ovstunnel", "configure_ovs_bridge_for_routing_policies", "bridge", bridge, "host-id",
-                                            ((Long) routingPolicy.getHostId()).toString(), "config", routingPolicy.getVpcConfigInJson(), "seq-no", Long.toString(1))).thenReturn(
-                            "SUCCESS");
-
         } catch (final BadServerResponse e) {
             fail(e.getMessage());
         } catch (final XenAPIException e) {
@@ -1468,7 +1446,7 @@
         final Connection conn = Mockito.mock(Connection.class);
         final XsHost xsHost = Mockito.mock(XsHost.class);
 
-        final Pool pool = PowerMockito.mock(Pool.class);
+        final Pool pool = Mockito.mock(Pool.class);
         final Pool.Record poolr = Mockito.mock(Pool.Record.class);
         final Host.Record hostr = Mockito.mock(Host.Record.class);
         final Host master = Mockito.mock(Host.class);
@@ -1479,30 +1457,16 @@
         assertNotNull(wrapper);
 
         when(citrixResourceBase.getConnection()).thenReturn(conn);
-        try {
+        try (MockedStatic<Pool.Record> ignored = Mockito.mockStatic(Pool.Record.class)){
             when(citrixResourceBase.getHost()).thenReturn(xsHost);
-            when(citrixResourceBase.getHost().getUuid()).thenReturn(uuid);
-
-            PowerMockito.mockStatic(Pool.Record.class);
-
-            when(pool.getRecord(conn)).thenReturn(poolr);
             poolr.master = master;
-            when(poolr.master.getRecord(conn)).thenReturn(hostr);
-            hostr.uuid = uuid;
 
-        } catch (final BadServerResponse e) {
-            fail(e.getMessage());
-        } catch (final XenAPIException e) {
-            fail(e.getMessage());
-        } catch (final XmlRpcException e) {
-            fail(e.getMessage());
+            final Answer answer = wrapper.execute(vmDataSync, citrixResourceBase);
+
+            verify(citrixResourceBase, times(1)).getConnection();
+
+            assertTrue(answer.getResult());
         }
-
-        final Answer answer = wrapper.execute(vmDataSync, citrixResourceBase);
-
-        verify(citrixResourceBase, times(1)).getConnection();
-
-        assertTrue(answer.getResult());
     }
 
     @Test
@@ -1695,14 +1659,6 @@
         when(citrixResourceBase.getHost()).thenReturn(xsHost);
         when(citrixResourceBase.getHost().getUuid()).thenReturn(uuid);
 
-        try {
-            when(citrixResourceBase.isDmcEnabled(conn, host)).thenReturn(true);
-        } catch (final XenAPIException e) {
-            fail(e.getMessage());
-        } catch (final XmlRpcException e) {
-            fail(e.getMessage());
-        }
-
         final Answer answer = wrapper.execute(scaleVm, citrixResourceBase);
 
         verify(citrixResourceBase, times(1)).getConnection();
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XcpServerWrapperTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XcpServerWrapperTest.java
index 6b99905..98a6f2b 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XcpServerWrapperTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XcpServerWrapperTest.java
@@ -31,18 +31,17 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.NetworkUsageCommand;
 import com.cloud.hypervisor.xenserver.resource.XcpServerResource;
-import com.cloud.utils.exception.CloudRuntimeException;
 import com.xensource.xenapi.Connection;
 
 import java.util.ArrayList;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
+@RunWith(MockitoJUnitRunner.class)
 public class XcpServerWrapperTest {
 
     @Mock
@@ -116,7 +115,6 @@
         assertNotNull(wrapper);
 
         when(XcpServerResource.getConnection()).thenReturn(conn);
-        when(XcpServerResource.networkUsage(conn, usageCommand.getPrivateIP(), "create", null)).thenThrow(new CloudRuntimeException("FAILED"));
 
         final Answer answer = wrapper.execute(usageCommand, XcpServerResource);
 
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer56FP1WrapperTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer56FP1WrapperTest.java
index 77be68b..3b8525d 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer56FP1WrapperTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer56FP1WrapperTest.java
@@ -26,7 +26,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.FenceCommand;
@@ -35,7 +35,7 @@
 import com.cloud.vm.VMInstanceVO;
 import com.xensource.xenapi.Connection;
 
-@RunWith(PowerMockRunner.class)
+@RunWith(MockitoJUnitRunner.class)
 public class XenServer56FP1WrapperTest {
 
     @Mock
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer56WrapperTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer56WrapperTest.java
index 21d6c53..a0c3e45 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer56WrapperTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer56WrapperTest.java
@@ -28,7 +28,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.CheckOnHostCommand;
@@ -40,7 +40,6 @@
 import com.cloud.host.Host;
 import com.cloud.host.HostEnvironment;
 import com.cloud.hypervisor.xenserver.resource.XenServer56Resource;
-import com.cloud.hypervisor.xenserver.resource.XsHost;
 import com.cloud.network.router.VirtualRouterAutoScale;
 import com.cloud.network.router.VirtualRouterAutoScale.AutoScaleMetrics;
 import com.cloud.network.router.VirtualRouterAutoScale.AutoScaleMetricsValue;
@@ -52,7 +51,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
+@RunWith(MockitoJUnitRunner.class)
 public class XenServer56WrapperTest {
 
     @Mock
@@ -260,7 +259,6 @@
 
     @Test
     public void testSetupCommand() {
-        final XsHost xsHost = Mockito.mock(XsHost.class);
         final HostEnvironment env = Mockito.mock(HostEnvironment.class);
 
         final SetupCommand setupCommand = new SetupCommand(env);
@@ -268,8 +266,6 @@
         final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
         assertNotNull(wrapper);
 
-        when(xenServer56Resource.getHost()).thenReturn(xsHost);
-
         final Answer answer = wrapper.execute(setupCommand, xenServer56Resource);
         verify(xenServer56Resource, times(1)).getConnection();
 
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer610WrapperTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer610WrapperTest.java
index fdb09f1..73d2ca6 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer610WrapperTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer610WrapperTest.java
@@ -29,13 +29,12 @@
 import java.util.List;
 import java.util.Map;
 
-import com.google.gson.Gson;
 import org.apache.xmlrpc.XmlRpcException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.CheckNetworkCommand;
@@ -60,13 +59,12 @@
 import com.xensource.xenapi.Connection;
 import com.xensource.xenapi.Network;
 import com.xensource.xenapi.SR;
-import com.xensource.xenapi.Task;
-import com.xensource.xenapi.Types.BadServerResponse;
 import com.xensource.xenapi.Types.XenAPIException;
 import com.xensource.xenapi.VDI;
 import com.xensource.xenapi.VIF;
 
-@RunWith(PowerMockRunner.class)
+
+@RunWith(MockitoJUnitRunner.class)
 public class XenServer610WrapperTest {
 
     @Mock
@@ -105,7 +103,6 @@
     public void testMigrateWithStorageCommand() {
         final String vmName = "small";
         final String uuid = "206b21a7-c6ec-40e2-b5e2-f861b9612f04";
-        final String path = "/";
 
         final Connection conn = Mockito.mock(Connection.class);
         final VirtualMachineTO vmSpec = Mockito.mock(VirtualMachineTO.class);
@@ -128,12 +125,6 @@
         final Network networkForSm = Mockito.mock(Network.class);
         final XsHost xsHost = Mockito.mock(XsHost.class);
 
-        final SR sr1 = Mockito.mock(SR.class);
-        final SR sr2 = Mockito.mock(SR.class);
-
-        final VDI vdi1 = Mockito.mock(VDI.class);
-        final VDI vdi2 = Mockito.mock(VDI.class);
-
         final MigrateWithStorageCommand migrateStorageCommand = new MigrateWithStorageCommand(vmSpec, volumeToFiler);
 
         final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
@@ -143,17 +134,7 @@
         when(vmSpec.getName()).thenReturn(vmName);
         when(vmSpec.getNics()).thenReturn(nicTOs);
 
-        when(storage1.getUuid()).thenReturn(uuid);
-        when(storage2.getUuid()).thenReturn(uuid);
 
-        when(vol1.getPath()).thenReturn(path);
-        when(vol2.getPath()).thenReturn(path);
-
-        when(xenServer610Resource.getStorageRepository(conn, storage1.getUuid())).thenReturn(sr1);
-        when(xenServer610Resource.getStorageRepository(conn, storage2.getUuid())).thenReturn(sr2);
-
-        when(xenServer610Resource.getVDIbyUuid(conn, storage1.getPath())).thenReturn(vdi1);
-        when(xenServer610Resource.getVDIbyUuid(conn, storage2.getPath())).thenReturn(vdi2);
 
         try {
             when(xenServer610Resource.getNativeNetworkForTraffic(conn, TrafficType.Storage, null)).thenReturn(nativeNetworkForTraffic);
@@ -221,9 +202,6 @@
         final Network nw2 = Mockito.mock(Network.class);
         final Network nw3 = Mockito.mock(Network.class);
 
-        final SR sr1 = Mockito.mock(SR.class);
-        final SR sr2 = Mockito.mock(SR.class);
-
         final MigrateWithStorageReceiveCommand migrateStorageCommand = new MigrateWithStorageReceiveCommand(vmSpec, volumeToFiler);
 
         final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
@@ -233,14 +211,7 @@
         when(vmSpec.getName()).thenReturn(vmName);
         when(vmSpec.getNics()).thenReturn(nicTOs);
 
-        when(storage1.getUuid()).thenReturn(uuid);
-        when(storage2.getUuid()).thenReturn(uuid);
-
-        when(xenServer610Resource.getStorageRepository(conn, storage1.getUuid())).thenReturn(sr1);
-        when(xenServer610Resource.getStorageRepository(conn, storage2.getUuid())).thenReturn(sr2);
-
         try {
-
             when(xenServer610Resource.getNetwork(conn, nicTO1)).thenReturn(nw1);
             when(xenServer610Resource.getNetwork(conn, nicTO2)).thenReturn(nw2);
             when(xenServer610Resource.getNetwork(conn, nicTO3)).thenReturn(nw3);
@@ -410,7 +381,6 @@
         final NicTO nic1 = Mockito.mock(NicTO.class);
         final NicTO nic2 = Mockito.mock(NicTO.class);
 
-        Gson gson = new Gson();
         final List<Pair<VolumeTO, Object>> volumeToSr = new ArrayList<Pair<VolumeTO, Object>>();
         volumeToSr.add(new Pair<VolumeTO, Object>(volume1, sr1));
         volumeToSr.add(new Pair<VolumeTO, Object>(volume2, sr2));
@@ -471,12 +441,9 @@
 
     @Test
     public void testXenServer610MigrateVolumeCommandWrapper() {
-        final String uuid = "206b21a7-c6ec-40e2-b5e2-f861b9612f04";
 
         final Connection conn = Mockito.mock(Connection.class);
-        final SR destinationPool = Mockito.mock(SR.class);
         final VDI srcVolume = Mockito.mock(VDI.class);
-        final Task task = Mockito.mock(Task.class);
 
         final long volumeId = 1l;
         final String volumePath = "206b21a7-c6ec-40e2-b5e2-f861b9612f04";
@@ -492,19 +459,8 @@
         assertNotNull(wrapper);
 
         when(xenServer610Resource.getConnection()).thenReturn(conn);
-        when(pool.getUuid()).thenReturn(uuid);
-        when(xenServer610Resource.getStorageRepository(conn, uuid)).thenReturn(destinationPool);
         when(xenServer610Resource.getVDIbyUuid(conn, volumePath)).thenReturn(srcVolume);
 
-        try {
-            when(srcVolume.poolMigrateAsync(conn, destinationPool, other)).thenReturn(task);
-        } catch (final BadServerResponse e) {
-            fail(e.getMessage());
-        } catch (final XenAPIException e) {
-            fail(e.getMessage());
-        } catch (final XmlRpcException e) {
-            fail(e.getMessage());
-        }
 
         when(xenServer610Resource.getMigrateWait()).thenReturn(120);
 
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer620SP1WrapperTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer620SP1WrapperTest.java
index 2645229..495370d 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer620SP1WrapperTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer620SP1WrapperTest.java
@@ -31,7 +31,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.GetGPUStatsCommand;
@@ -41,7 +41,7 @@
 import com.xensource.xenapi.Connection;
 import com.xensource.xenapi.Types.XenAPIException;
 
-@RunWith(PowerMockRunner.class)
+@RunWith(MockitoJUnitRunner.class)
 public class XenServer620SP1WrapperTest {
 
     @Mock
diff --git a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer620WrapperTest.java b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer620WrapperTest.java
index fc3d003..fe694a6 100644
--- a/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer620WrapperTest.java
+++ b/plugins/hypervisors/xenserver/src/test/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/XenServer620WrapperTest.java
@@ -23,14 +23,14 @@
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.CheckNetworkCommand;
 import com.cloud.hypervisor.xenserver.resource.XenServer620Resource;
 import com.cloud.network.PhysicalNetworkSetupInfo;
 
-@RunWith(PowerMockRunner.class)
+@RunWith(MockitoJUnitRunner.class)
 public class XenServer620WrapperTest {
 
     @Test
diff --git a/plugins/hypervisors/xenserver/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/plugins/hypervisors/xenserver/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d4
--- /dev/null
+++ b/plugins/hypervisors/xenserver/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/plugins/integrations/cloudian/pom.xml b/plugins/integrations/cloudian/pom.xml
index 3f5c9d1..bf57a44 100644
--- a/plugins/integrations/cloudian/pom.xml
+++ b/plugins/integrations/cloudian/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/integrations/kubernetes-service/pom.xml b/plugins/integrations/kubernetes-service/pom.xml
index 7be1dec..5526358 100644
--- a/plugins/integrations/kubernetes-service/pom.xml
+++ b/plugins/integrations/kubernetes-service/pom.xml
@@ -26,7 +26,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesCluster.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesCluster.java
index b8f399b..591da07 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesCluster.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesCluster.java
@@ -32,6 +32,10 @@
  */
 public interface KubernetesCluster extends ControlledEntity, com.cloud.utils.fsm.StateObject<KubernetesCluster.State>, Identity, InternalIdentity, Displayable {
 
+    enum ClusterType {
+        CloudManaged, ExternalManaged;
+    };
+
     enum Event {
         StartRequested,
         StopRequested,
@@ -115,10 +119,10 @@
     String getName();
     String getDescription();
     long getZoneId();
-    long getKubernetesVersionId();
-    long getServiceOfferingId();
-    long getTemplateId();
-    long getNetworkId();
+    Long getKubernetesVersionId();
+    Long getServiceOfferingId();
+    Long getTemplateId();
+    Long getNetworkId();
     long getDomainId();
     long getAccountId();
     long getControlNodeCount();
@@ -137,4 +141,5 @@
     Long getMinSize();
     Long getMaxSize();
     Long getSecurityGroupId();
+    ClusterType getClusterType();
 }
diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java
index 0c07268..3551144 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java
@@ -17,6 +17,7 @@
 package com.cloud.kubernetes.cluster;
 
 import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
+import static com.cloud.vm.UserVmManager.AllowUserExpungeRecoverVm;
 
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -25,8 +26,11 @@
 import java.util.Date;
 import java.util.EnumSet;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.Executors;
@@ -36,17 +40,22 @@
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.uservm.UserVm;
+import com.cloud.vm.UserVmService;
 import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.acl.SecurityChecker;
 import org.apache.cloudstack.annotation.AnnotationService;
 import org.apache.cloudstack.annotation.dao.AnnotationDao;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiConstants.VMDetails;
+import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.ResponseObject.ResponseView;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.AddVirtualMachinesToKubernetesClusterCmd;
 import org.apache.cloudstack.api.command.user.kubernetes.cluster.CreateKubernetesClusterCmd;
 import org.apache.cloudstack.api.command.user.kubernetes.cluster.DeleteKubernetesClusterCmd;
 import org.apache.cloudstack.api.command.user.kubernetes.cluster.GetKubernetesClusterConfigCmd;
 import org.apache.cloudstack.api.command.user.kubernetes.cluster.ListKubernetesClustersCmd;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.RemoveVirtualMachinesFromKubernetesClusterCmd;
 import org.apache.cloudstack.api.command.user.kubernetes.cluster.ScaleKubernetesClusterCmd;
 import org.apache.cloudstack.api.command.user.kubernetes.cluster.StartKubernetesClusterCmd;
 import org.apache.cloudstack.api.command.user.kubernetes.cluster.StopKubernetesClusterCmd;
@@ -54,6 +63,7 @@
 import org.apache.cloudstack.api.response.KubernetesClusterConfigResponse;
 import org.apache.cloudstack.api.response.KubernetesClusterResponse;
 import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.RemoveVirtualMachinesFromKubernetesClusterResponse;
 import org.apache.cloudstack.api.response.UserVmResponse;
 import org.apache.cloudstack.config.ApiServiceConfiguration;
 import org.apache.cloudstack.context.CallContext;
@@ -244,6 +254,9 @@
     @Inject
     public SecurityGroupService securityGroupService;
 
+    @Inject
+    private UserVmService userVmService;
+
     private void logMessage(final Level logLevel, final String message, final Exception e) {
         if (logLevel == Level.WARN) {
             if (e != null) {
@@ -535,10 +548,14 @@
         response.setControlNodes(kubernetesCluster.getControlNodeCount());
         response.setClusterSize(kubernetesCluster.getNodeCount());
         VMTemplateVO template = ApiDBUtils.findTemplateById(kubernetesCluster.getTemplateId());
-        response.setTemplateId(template.getUuid());
+        if (template != null) {
+            response.setTemplateId(template.getUuid());
+        }
         ServiceOfferingVO offering = serviceOfferingDao.findById(kubernetesCluster.getServiceOfferingId());
-        response.setServiceOfferingId(offering.getUuid());
-        response.setServiceOfferingName(offering.getName());
+        if (offering != null) {
+            response.setServiceOfferingId(offering.getUuid());
+            response.setServiceOfferingName(offering.getName());
+        }
         KubernetesSupportedVersionVO version = kubernetesSupportedVersionDao.findById(kubernetesCluster.getKubernetesVersionId());
         if (version != null) {
             response.setKubernetesVersionId(version.getUuid());
@@ -561,13 +578,15 @@
         response.setMemory(String.valueOf(kubernetesCluster.getMemory()));
         NetworkVO ntwk = networkDao.findByIdIncludingRemoved(kubernetesCluster.getNetworkId());
         response.setEndpoint(kubernetesCluster.getEndpoint());
-        response.setNetworkId(ntwk.getUuid());
-        response.setAssociatedNetworkName(ntwk.getName());
-        if (ntwk.getGuestType() == Network.GuestType.Isolated) {
-            List<IPAddressVO> ipAddresses = ipAddressDao.listByAssociatedNetwork(ntwk.getId(), true);
-            if (ipAddresses != null && ipAddresses.size() == 1) {
-                response.setIpAddress(ipAddresses.get(0).getAddress().addr());
-                response.setIpAddressId(ipAddresses.get(0).getUuid());
+        if (ntwk != null) {
+            response.setNetworkId(ntwk.getUuid());
+            response.setAssociatedNetworkName(ntwk.getName());
+            if (ntwk.getGuestType() == Network.GuestType.Isolated) {
+                List<IPAddressVO> ipAddresses = ipAddressDao.listByAssociatedNetwork(ntwk.getId(), true);
+                if (ipAddresses != null && ipAddresses.size() == 1) {
+                    response.setIpAddress(ipAddresses.get(0).getAddress().addr());
+                    response.setIpAddressId(ipAddresses.get(0).getUuid());
+                }
             }
         }
 
@@ -595,6 +614,7 @@
         response.setAutoscalingEnabled(kubernetesCluster.getAutoscalingEnabled());
         response.setMinSize(kubernetesCluster.getMinSize());
         response.setMaxSize(kubernetesCluster.getMaxSize());
+        response.setClusterType(kubernetesCluster.getClusterType());
         response.setCreated(kubernetesCluster.getCreated());
         return response;
     }
@@ -608,7 +628,95 @@
         }
     }
 
-    private void validateKubernetesClusterCreateParameters(final CreateKubernetesClusterCmd cmd) throws CloudRuntimeException {
+    private DataCenter validateAndGetZoneForKubernetesCreateParameters(Long zoneId) {
+        DataCenter zone = dataCenterDao.findById(zoneId);
+        if (zone == null) {
+            throw new InvalidParameterValueException("Unable to find zone by ID: " + zoneId);
+        }
+        if (zone.getAllocationState() == Grouping.AllocationState.Disabled) {
+            throw new PermissionDeniedException(String.format("Cannot perform this operation, zone ID: %s is currently disabled", zone.getUuid()));
+        }
+        return zone;
+    }
+
+    private void validateSshKeyPairForKubernetesCreateParameters(String sshKeyPair, Account owner) {
+        if (!StringUtils.isBlank(sshKeyPair)) {
+            SSHKeyPairVO sshKeyPairVO = sshKeyPairDao.findByName(owner.getAccountId(), owner.getDomainId(), sshKeyPair);
+            if (sshKeyPairVO == null) {
+                throw new InvalidParameterValueException(String.format("Given SSH key pair with name: %s was not found for the account %s", sshKeyPair, owner.getAccountName()));
+            }
+        }
+    }
+
+    private Network validateAndGetNetworkForKubernetesCreateParameters(Long networkId) {
+        Network network = null;
+        if (networkId != null) {
+            network = networkService.getNetwork(networkId);
+            if (network == null) {
+                throw new InvalidParameterValueException("Unable to find network with given ID");
+            }
+        }
+        return network;
+    }
+
+    private void validateUnmanagedKubernetesClusterCreateParameters(final CreateKubernetesClusterCmd cmd) throws CloudRuntimeException {
+        final String name = cmd.getName();
+        final Long zoneId = cmd.getZoneId();
+        final Account owner = accountService.getActiveAccountById(cmd.getEntityOwnerId());
+        final Long networkId = cmd.getNetworkId();
+        final String sshKeyPair = cmd.getSSHKeyPairName();
+        final String dockerRegistryUserName = cmd.getDockerRegistryUserName();
+        final String dockerRegistryPassword = cmd.getDockerRegistryPassword();
+        final String dockerRegistryUrl = cmd.getDockerRegistryUrl();
+        final Long nodeRootDiskSize = cmd.getNodeRootDiskSize();
+        final String externalLoadBalancerIpAddress = cmd.getExternalLoadBalancerIpAddress();
+
+        if (name == null || name.isEmpty()) {
+            throw new InvalidParameterValueException("Invalid name for the Kubernetes cluster name: " + name);
+        }
+
+        validateAndGetZoneForKubernetesCreateParameters(zoneId);
+        validateSshKeyPairForKubernetesCreateParameters(sshKeyPair, owner);
+
+        if (nodeRootDiskSize != null && nodeRootDiskSize <= 0) {
+            throw new InvalidParameterValueException(String.format("Invalid value for %s", ApiConstants.NODE_ROOT_DISK_SIZE));
+        }
+
+        validateDockerRegistryParams(dockerRegistryUserName, dockerRegistryPassword, dockerRegistryUrl);
+
+        validateAndGetNetworkForKubernetesCreateParameters(networkId);
+
+        if (StringUtils.isNotEmpty(externalLoadBalancerIpAddress) && (!NetUtils.isValidIp4(externalLoadBalancerIpAddress) && !NetUtils.isValidIp6(externalLoadBalancerIpAddress))) {
+            throw new InvalidParameterValueException("Invalid external load balancer IP address");
+        }
+    }
+
+    public boolean isCommandSupported(KubernetesCluster cluster, String cmdName) {
+        switch (cluster.getClusterType()) {
+            case CloudManaged:
+                return Arrays.asList(
+                        BaseCmd.getCommandNameByClass(CreateKubernetesClusterCmd.class),
+                        BaseCmd.getCommandNameByClass(ListKubernetesClustersCmd.class),
+                        BaseCmd.getCommandNameByClass(DeleteKubernetesClusterCmd.class),
+                        BaseCmd.getCommandNameByClass(ScaleKubernetesClusterCmd.class),
+                        BaseCmd.getCommandNameByClass(StartKubernetesClusterCmd.class),
+                        BaseCmd.getCommandNameByClass(StopKubernetesClusterCmd.class),
+                        BaseCmd.getCommandNameByClass(UpgradeKubernetesClusterCmd.class)
+                ).contains(cmdName);
+            case ExternalManaged:
+                return Arrays.asList(
+                        BaseCmd.getCommandNameByClass(CreateKubernetesClusterCmd.class),
+                        BaseCmd.getCommandNameByClass(ListKubernetesClustersCmd.class),
+                        BaseCmd.getCommandNameByClass(DeleteKubernetesClusterCmd.class),
+                        BaseCmd.getCommandNameByClass(AddVirtualMachinesToKubernetesClusterCmd.class),
+                        BaseCmd.getCommandNameByClass(RemoveVirtualMachinesFromKubernetesClusterCmd.class)
+                ).contains(cmdName);
+            default:
+                return false;
+        }
+    }
+
+    private void validateManagedKubernetesClusterCreateParameters(final CreateKubernetesClusterCmd cmd) throws CloudRuntimeException {
         validateEndpointUrl();
         final String name = cmd.getName();
         final Long zoneId = cmd.getZoneId();
@@ -619,7 +727,6 @@
         final String sshKeyPair = cmd.getSSHKeyPairName();
         final Long controlNodeCount = cmd.getControlNodes();
         final Long clusterSize = cmd.getClusterSize();
-        final long totalNodeCount = controlNodeCount + clusterSize;
         final String dockerRegistryUserName = cmd.getDockerRegistryUserName();
         final String dockerRegistryPassword = cmd.getDockerRegistryPassword();
         final String dockerRegistryUrl = cmd.getDockerRegistryUrl();
@@ -627,31 +734,24 @@
         final String externalLoadBalancerIpAddress = cmd.getExternalLoadBalancerIpAddress();
 
         if (name == null || name.isEmpty()) {
-            throw new InvalidParameterValueException("Invalid name for the Kubernetes cluster name:" + name);
+            throw new InvalidParameterValueException("Invalid name for the Kubernetes cluster name: " + name);
         }
 
         if (controlNodeCount < 1) {
             throw new InvalidParameterValueException("Invalid cluster control nodes count: " + controlNodeCount);
         }
-
-        if (clusterSize < 1) {
+        if (clusterSize == null || clusterSize < 1) {
             throw new InvalidParameterValueException("Invalid cluster size: " + clusterSize);
         }
 
         int maxClusterSize = KubernetesMaxClusterSize.valueIn(owner.getId());
+        final long totalNodeCount = controlNodeCount + clusterSize;
         if (totalNodeCount > maxClusterSize) {
             throw new InvalidParameterValueException(
                 String.format("Maximum cluster size can not exceed %d. Please contact your administrator", maxClusterSize));
         }
 
-        DataCenter zone = dataCenterDao.findById(zoneId);
-        if (zone == null) {
-            throw new InvalidParameterValueException("Unable to find zone by ID: " + zoneId);
-        }
-
-        if (Grouping.AllocationState.Disabled == zone.getAllocationState()) {
-            throw new PermissionDeniedException(String.format("Cannot perform this operation, zone ID: %s is currently disabled", zone.getUuid()));
-        }
+        DataCenter zone = validateAndGetZoneForKubernetesCreateParameters(zoneId);
 
         if (!isKubernetesServiceConfigured(zone)) {
             throw new CloudRuntimeException("Kubernetes service has not been configured properly to provision Kubernetes clusters");
@@ -694,12 +794,7 @@
             throw new InvalidParameterValueException("No service offering with ID: " + serviceOfferingId);
         }
 
-        if (sshKeyPair != null && !sshKeyPair.isEmpty()) {
-            SSHKeyPairVO sshKeyPairVO = sshKeyPairDao.findByName(owner.getAccountId(), owner.getDomainId(), sshKeyPair);
-            if (sshKeyPairVO == null) {
-                throw new InvalidParameterValueException(String.format("Given SSH key pair with name: %s was not found for the account %s", sshKeyPair, owner.getAccountName()));
-            }
-        }
+        validateSshKeyPairForKubernetesCreateParameters(sshKeyPair, owner);
 
         if (nodeRootDiskSize != null && nodeRootDiskSize <= 0) {
             throw new InvalidParameterValueException(String.format("Invalid value for %s", ApiConstants.NODE_ROOT_DISK_SIZE));
@@ -711,13 +806,7 @@
 
         validateDockerRegistryParams(dockerRegistryUserName, dockerRegistryPassword, dockerRegistryUrl);
 
-        Network network = null;
-        if (networkId != null) {
-            network = networkService.getNetwork(networkId);
-            if (network == null) {
-                throw new InvalidParameterValueException("Unable to find network with given ID");
-            }
-        }
+        Network network = validateAndGetNetworkForKubernetesCreateParameters(networkId);
 
         if (StringUtils.isNotEmpty(externalLoadBalancerIpAddress)) {
             if (!NetUtils.isValidIp4(externalLoadBalancerIpAddress) && !NetUtils.isValidIp6(externalLoadBalancerIpAddress)) {
@@ -788,15 +877,16 @@
                 List<KubernetesClusterDetailsVO> details = new ArrayList<>();
                 long kubernetesClusterId = kubernetesCluster.getId();
 
-                if (Network.GuestType.Shared.equals(network.getGuestType())) {
+                if ((network != null && Network.GuestType.Shared.equals(network.getGuestType())) || kubernetesCluster.getClusterType() == KubernetesCluster.ClusterType.ExternalManaged) {
                     addKubernetesClusterDetailIfIsNotEmpty(details, kubernetesClusterId, ApiConstants.EXTERNAL_LOAD_BALANCER_IP_ADDRESS, externalLoadBalancerIpAddress, true);
                 }
 
                 addKubernetesClusterDetailIfIsNotEmpty(details, kubernetesClusterId, ApiConstants.DOCKER_REGISTRY_USER_NAME, dockerRegistryUserName, true);
                 addKubernetesClusterDetailIfIsNotEmpty(details, kubernetesClusterId, ApiConstants.DOCKER_REGISTRY_PASSWORD, dockerRegistryPassword, false);
                 addKubernetesClusterDetailIfIsNotEmpty(details, kubernetesClusterId, ApiConstants.DOCKER_REGISTRY_URL, dockerRegistryUrl, true);
-
-                details.add(new KubernetesClusterDetailsVO(kubernetesClusterId, "networkCleanup", String.valueOf(networkCleanup), true));
+                if (kubernetesCluster.getClusterType() == KubernetesCluster.ClusterType.CloudManaged) {
+                    details.add(new KubernetesClusterDetailsVO(kubernetesClusterId, "networkCleanup", String.valueOf(networkCleanup), true));
+                }
                 kubernetesClusterDetailsDao.saveDetails(details);
             }
         });
@@ -865,6 +955,9 @@
 
         Account caller = CallContext.current().getCallingAccount();
         accountManager.checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, kubernetesCluster);
+        if (!isCommandSupported(kubernetesCluster, cmd.getActualCommandName())) {
+            throw new InvalidParameterValueException(String.format("Scale kubernetes cluster is not supported for an externally managed cluster (%s)", kubernetesCluster.getName()));
+        }
 
         final KubernetesSupportedVersion clusterVersion = kubernetesSupportedVersionDao.findById(kubernetesCluster.getKubernetesVersionId());
         if (clusterVersion == null) {
@@ -973,6 +1066,9 @@
         if (kubernetesCluster == null || kubernetesCluster.getRemoved() != null) {
             throw new InvalidParameterValueException("Invalid Kubernetes cluster ID");
         }
+        if (!isCommandSupported(kubernetesCluster, cmd.getActualCommandName())) {
+            throw new InvalidParameterValueException(String.format("Upgrade kubernetes cluster is not supported for an externally managed cluster (%s)", kubernetesCluster.getName()));
+        }
         accountManager.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry, false, kubernetesCluster);
         if (!KubernetesCluster.State.Running.equals(kubernetesCluster.getState())) {
             throw new InvalidParameterValueException(String.format("Kubernetes cluster : %s is not in running state", kubernetesCluster.getName()));
@@ -1032,12 +1128,62 @@
     }
 
     @Override
-    public KubernetesCluster createKubernetesCluster(CreateKubernetesClusterCmd cmd) throws CloudRuntimeException {
+    public KubernetesCluster createUnmanagedKubernetesCluster(CreateKubernetesClusterCmd cmd) throws CloudRuntimeException {
         if (!KubernetesServiceEnabled.value()) {
             logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
         }
 
-        validateKubernetesClusterCreateParameters(cmd);
+        validateUnmanagedKubernetesClusterCreateParameters(cmd);
+
+        final DataCenter zone = dataCenterDao.findById(cmd.getZoneId());
+        final long controlNodeCount = cmd.getControlNodes();
+        final long clusterSize = Objects.requireNonNullElse(cmd.getClusterSize(), 0L);
+        final ServiceOffering serviceOffering = serviceOfferingDao.findById(cmd.getServiceOfferingId());
+        final Account owner = accountService.getActiveAccountById(cmd.getEntityOwnerId());
+        final KubernetesSupportedVersion clusterKubernetesVersion = kubernetesSupportedVersionDao.findById(cmd.getKubernetesVersionId());
+
+        final Network network = networkDao.findById(cmd.getNetworkId());
+        long cores = 0;
+        long memory = 0;
+        Long serviceOfferingId = null;
+        if (serviceOffering != null) {
+            serviceOfferingId = serviceOffering.getId();
+            cores = serviceOffering.getCpu() * (controlNodeCount + clusterSize);
+            memory = serviceOffering.getRamSize() * (controlNodeCount + clusterSize);
+        }
+
+        final Long finalServiceOfferingId = serviceOfferingId;
+        final Long defaultNetworkId = network == null ? null : network.getId();
+        final Long clusterKubernetesVersionId = clusterKubernetesVersion == null ? null : clusterKubernetesVersion.getId();
+        final long finalCores = cores;
+        final long finalMemory = memory;
+        final KubernetesClusterVO cluster = Transaction.execute(new TransactionCallback<KubernetesClusterVO>() {
+            @Override
+            public KubernetesClusterVO doInTransaction(TransactionStatus status) {
+                KubernetesClusterVO newCluster = new KubernetesClusterVO(cmd.getName(), cmd.getDisplayName(), zone.getId(), clusterKubernetesVersionId,
+                        finalServiceOfferingId, null, defaultNetworkId, owner.getDomainId(),
+                        owner.getAccountId(), controlNodeCount, clusterSize, KubernetesCluster.State.Running, cmd.getSSHKeyPairName(), finalCores, finalMemory,
+                        cmd.getNodeRootDiskSize(), "", KubernetesCluster.ClusterType.ExternalManaged);
+                kubernetesClusterDao.persist(newCluster);
+                return newCluster;
+            }
+        });
+
+        addKubernetesClusterDetails(cluster, network, cmd);
+
+        if (LOGGER.isInfoEnabled()) {
+            LOGGER.info(String.format("Kubernetes cluster with name: %s and ID: %s has been created", cluster.getName(), cluster.getUuid()));
+        }
+        return cluster;
+    }
+
+    @Override
+    public KubernetesCluster createManagedKubernetesCluster(CreateKubernetesClusterCmd cmd) throws CloudRuntimeException {
+        if (!KubernetesServiceEnabled.value()) {
+            logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
+        }
+
+        validateManagedKubernetesClusterCreateParameters(cmd);
 
         final DataCenter zone = dataCenterDao.findById(cmd.getZoneId());
         final long controlNodeCount = cmd.getControlNodes();
@@ -1086,7 +1232,8 @@
             public KubernetesClusterVO doInTransaction(TransactionStatus status) {
                 KubernetesClusterVO newCluster = new KubernetesClusterVO(cmd.getName(), cmd.getDisplayName(), zone.getId(), clusterKubernetesVersion.getId(),
                         serviceOffering.getId(), finalTemplate.getId(), defaultNetwork.getId(), owner.getDomainId(),
-                        owner.getAccountId(), controlNodeCount, clusterSize, KubernetesCluster.State.Created, cmd.getSSHKeyPairName(), cores, memory, cmd.getNodeRootDiskSize(), "");
+                        owner.getAccountId(), controlNodeCount, clusterSize, KubernetesCluster.State.Created, cmd.getSSHKeyPairName(), cores, memory,
+                        cmd.getNodeRootDiskSize(), "", KubernetesCluster.ClusterType.CloudManaged);
                 if (zone.isSecurityGroupEnabled()) {
                     newCluster.setSecurityGroupId(finalSecurityGroupVO.getId());
                 }
@@ -1183,7 +1330,8 @@
     }
 
     @Override
-    public boolean stopKubernetesCluster(long kubernetesClusterId) throws CloudRuntimeException {
+    public boolean stopKubernetesCluster(StopKubernetesClusterCmd cmd) throws CloudRuntimeException {
+        long kubernetesClusterId = cmd.getId();
         if (!KubernetesServiceEnabled.value()) {
             logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
         }
@@ -1191,6 +1339,9 @@
         if (kubernetesCluster == null) {
             throw new InvalidParameterValueException("Failed to find Kubernetes cluster with given ID");
         }
+        if (!isCommandSupported(kubernetesCluster, cmd.getActualCommandName())) {
+            throw new InvalidParameterValueException(String.format("Stop kubernetes cluster is not supported for an externally managed cluster (%s)", kubernetesCluster.getName()));
+        }
         if (kubernetesCluster.getRemoved() != null) {
             throw new InvalidParameterValueException(String.format("Kubernetes cluster : %s is already deleted", kubernetesCluster.getName()));
         }
@@ -1213,18 +1364,51 @@
     }
 
     @Override
-    public boolean deleteKubernetesCluster(Long kubernetesClusterId) throws CloudRuntimeException {
+    public boolean deleteKubernetesCluster(DeleteKubernetesClusterCmd cmd) throws CloudRuntimeException {
         if (!KubernetesServiceEnabled.value()) {
             logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
         }
+        Long kubernetesClusterId = cmd.getId();
         KubernetesClusterVO cluster = kubernetesClusterDao.findById(kubernetesClusterId);
         if (cluster == null) {
             throw new InvalidParameterValueException("Invalid cluster id specified");
         }
         accountManager.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry, false, cluster);
-        KubernetesClusterDestroyWorker destroyWorker = new KubernetesClusterDestroyWorker(cluster, this);
-        destroyWorker = ComponentContext.inject(destroyWorker);
-        return destroyWorker.destroy();
+        if (cluster.getClusterType() == KubernetesCluster.ClusterType.CloudManaged) {
+            KubernetesClusterDestroyWorker destroyWorker = new KubernetesClusterDestroyWorker(cluster, this);
+            destroyWorker = ComponentContext.inject(destroyWorker);
+            return destroyWorker.destroy();
+        } else {
+            boolean cleanup = cmd.getCleanup();
+            boolean expunge = cmd.getExpunge();
+            if (cleanup || expunge) {
+                CallContext ctx = CallContext.current();
+
+                if (expunge && !accountManager.isAdmin(ctx.getCallingAccount().getId()) && !AllowUserExpungeRecoverVm.valueIn(cmd.getEntityOwnerId())) {
+                    throw new PermissionDeniedException("Parameter " + ApiConstants.EXPUNGE + " can be passed by Admin only. Or when the allow.user.expunge.recover.vm key is set.");
+                }
+
+                List<KubernetesClusterVmMapVO> vmMapList = kubernetesClusterVmMapDao.listByClusterId(kubernetesClusterId);
+                for (KubernetesClusterVmMapVO vmMap : vmMapList) {
+                    try {
+                        userVmService.destroyVm(vmMap.getVmId(), expunge);
+                        if (expunge) {
+                            userVmService.expungeVm(vmMap.getVmId());
+                        }
+                    } catch (Exception exception) {
+                        logMessage(Level.WARN, String.format("Failed to destroy vm %d", vmMap.getVmId()), exception);
+                    }
+                }
+            }
+            return Transaction.execute(new TransactionCallback<Boolean>() {
+                @Override
+                public Boolean doInTransaction(TransactionStatus status) {
+                    kubernetesClusterDetailsDao.removeDetails(kubernetesClusterId);
+                    kubernetesClusterVmMapDao.removeByClusterId(kubernetesClusterId);
+                    return kubernetesClusterDao.remove(kubernetesClusterId);
+                }
+            });
+        }
     }
 
     @Override
@@ -1238,6 +1422,7 @@
         final String state = cmd.getState();
         final String name = cmd.getName();
         final String keyword = cmd.getKeyword();
+        final String cmdClusterType = cmd.getClusterType();
         List<KubernetesClusterResponse> responsesList = new ArrayList<KubernetesClusterResponse>();
         List<Long> permittedAccounts = new ArrayList<Long>();
         Ternary<Long, Boolean, Project.ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, Project.ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null);
@@ -1245,6 +1430,17 @@
         Long domainId = domainIdRecursiveListProject.first();
         Boolean isRecursive = domainIdRecursiveListProject.second();
         Project.ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
+
+        KubernetesCluster.ClusterType clusterType = null;
+
+        if (cmdClusterType != null) {
+            try {
+             clusterType = KubernetesCluster.ClusterType.valueOf(cmdClusterType);
+            } catch (IllegalArgumentException exception) {
+                throw new InvalidParameterValueException("Unable to resolve cluster type " + cmdClusterType + " to a supported value (CloudManaged, ExternalManaged)");
+            }
+        }
+
         Filter searchFilter = new Filter(KubernetesClusterVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());
         SearchBuilder<KubernetesClusterVO> sb = kubernetesClusterDao.createSearchBuilder();
         accountManager.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
@@ -1252,6 +1448,7 @@
         sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
         sb.and("keyword", sb.entity().getName(), SearchCriteria.Op.LIKE);
         sb.and("state", sb.entity().getState(), SearchCriteria.Op.IN);
+        sb.and("cluster_type", sb.entity().getClusterType(), SearchCriteria.Op.EQ);
         SearchCriteria<KubernetesClusterVO> sc = sb.create();
         accountManager.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
         if (state != null) {
@@ -1266,6 +1463,9 @@
         if (name != null) {
             sc.setParameters("name", name);
         }
+        if (clusterType != null) {
+            sc.setParameters("cluster_type", clusterType);
+        }
         List<KubernetesClusterVO> kubernetesClusters = kubernetesClusterDao.search(sc, searchFilter);
         for (KubernetesClusterVO cluster : kubernetesClusters) {
             KubernetesClusterResponse clusterResponse = createKubernetesClusterResponse(cluster.getId());
@@ -1342,6 +1542,114 @@
         return upgradeWorker.upgradeCluster();
     }
 
+    private void updateNodeCount(KubernetesClusterVO kubernetesCluster) {
+        List<KubernetesClusterVmMapVO> nodeList = kubernetesClusterVmMapDao.listByClusterId(kubernetesCluster.getId());
+        kubernetesCluster.setControlNodeCount(nodeList.stream().filter(KubernetesClusterVmMapVO::isControlNode).count());
+        kubernetesCluster.setNodeCount(nodeList.size());
+        kubernetesCluster.setNodeCount(nodeList.size());
+        kubernetesClusterDao.persist(kubernetesCluster);
+    }
+
+    @Override
+    public boolean addVmsToCluster(AddVirtualMachinesToKubernetesClusterCmd cmd) {
+        if (!KubernetesServiceEnabled.value()) {
+            logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
+        }
+        List<Long> vmIds = cmd.getVmIds();
+        Long clusterId = cmd.getId();
+
+        KubernetesClusterVO kubernetesCluster = kubernetesClusterDao.findById(clusterId);
+        if (kubernetesCluster == null) {
+            throw new InvalidParameterValueException("Invalid Kubernetes cluster ID specified");
+        }
+        if (!isCommandSupported(kubernetesCluster, cmd.getActualCommandName())) {
+            throw new InvalidParameterValueException("VM cannot be added to a CloudStack managed Kubernetes cluster");
+        }
+
+        // User should have access to both VM and Kubernetes cluster
+        accountManager.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry, false, kubernetesCluster);
+
+        for (Long vmId : vmIds) {
+            VMInstanceVO vmInstance = vmInstanceDao.findById(vmId);
+            if (vmInstance == null) {
+                throw new InvalidParameterValueException("Invalid VM ID specified");
+            }
+            accountManager.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry, false, vmInstance);
+        }
+
+        KubernetesClusterVmMapVO clusterVmMap = null;
+        List<KubernetesClusterVmMapVO> clusterVmMapList = kubernetesClusterVmMapDao.listByClusterIdAndVmIdsIn(clusterId, vmIds);
+        ArrayList<Long> alreadyExistingVmIds = new ArrayList<>();
+        for (KubernetesClusterVmMapVO clusterVmMapVO : clusterVmMapList) {
+            alreadyExistingVmIds.add(clusterVmMapVO.getVmId());
+        }
+        vmIds.removeAll(alreadyExistingVmIds);
+        for (Long vmId : vmIds) {
+            clusterVmMap = new KubernetesClusterVmMapVO(clusterId, vmId, cmd.isControlNode());
+            kubernetesClusterVmMapDao.persist(clusterVmMap);
+        }
+        updateNodeCount(kubernetesCluster);
+        return true;
+    }
+
+    @Override
+    public List<RemoveVirtualMachinesFromKubernetesClusterResponse> removeVmsFromCluster(RemoveVirtualMachinesFromKubernetesClusterCmd cmd) {
+        if (!KubernetesServiceEnabled.value()) {
+            logAndThrow(Level.ERROR, "Kubernetes Service plugin is disabled");
+        }
+        List<Long> vmIds = cmd.getVmIds();
+        Long clusterId = cmd.getId();
+
+        KubernetesClusterVO kubernetesCluster = kubernetesClusterDao.findById(clusterId);
+        if (kubernetesCluster == null) {
+            throw new InvalidParameterValueException("Invalid Kubernetes cluster ID specified");
+        }
+        if (!isCommandSupported(kubernetesCluster, cmd.getActualCommandName())) {
+            throw new InvalidParameterValueException("VM cannot be removed from a CloudStack Managed Kubernetes cluster");
+        }
+        accountManager.checkAccess(CallContext.current().getCallingAccount(), SecurityChecker.AccessType.OperateEntry, false, kubernetesCluster);
+
+        List<KubernetesClusterVmMapVO> kubernetesClusterVmMap = kubernetesClusterVmMapDao.listByClusterIdAndVmIdsIn(clusterId, vmIds);
+        List<RemoveVirtualMachinesFromKubernetesClusterResponse> responseList = new ArrayList<>();
+
+        Set<Long> vmIdsRemoved = new HashSet<>();
+
+        for (KubernetesClusterVmMapVO clusterVmMap : kubernetesClusterVmMap) {
+            RemoveVirtualMachinesFromKubernetesClusterResponse response = new RemoveVirtualMachinesFromKubernetesClusterResponse();
+            UserVm vm = userVmService.getUserVm(clusterVmMap.getVmId());
+            response.setVmId(vm.getUuid());
+            response.setSuccess(kubernetesClusterVmMapDao.remove(clusterVmMap.getId()));
+            response.setObjectName(cmd.getCommandName());
+            responseList.add(response);
+            vmIdsRemoved.add(clusterVmMap.getVmId());
+        }
+
+        for (Long vmId : vmIds) {
+            if (!vmIdsRemoved.contains(vmId)) {
+                RemoveVirtualMachinesFromKubernetesClusterResponse response = new RemoveVirtualMachinesFromKubernetesClusterResponse();
+                VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(vmId);
+                if (vm == null) {
+                    response.setVmId(vmId.toString());
+                    response.setDisplayText("Not a valid vm id");
+                    vmIdsRemoved.add(vmId);
+                } else {
+                    response.setVmId(vm.getUuid());
+                    vmIdsRemoved.add(vmId);
+                    if (vm.isRemoved()) {
+                        response.setDisplayText("VM is already removed");
+                    } else {
+                        response.setDisplayText("VM is not part of the cluster");
+                    }
+                }
+                response.setObjectName(cmd.getCommandName());
+                response.setSuccess(false);
+                responseList.add(response);
+            }
+        }
+        updateNodeCount(kubernetesCluster);
+        return responseList;
+    }
+
     @Override
     public List<Class<?>> getCommands() {
         List<Class<?>> cmdList = new ArrayList<Class<?>>();
@@ -1356,6 +1664,8 @@
         cmdList.add(GetKubernetesClusterConfigCmd.class);
         cmdList.add(ScaleKubernetesClusterCmd.class);
         cmdList.add(UpgradeKubernetesClusterCmd.class);
+        cmdList.add(AddVirtualMachinesToKubernetesClusterCmd.class);
+        cmdList.add(RemoveVirtualMachinesFromKubernetesClusterCmd.class);
         return cmdList;
     }
 
@@ -1442,7 +1752,7 @@
         public void reallyRun() {
             try {
                 // run through Kubernetes clusters in 'Running' state and ensure all the VM's are Running in the cluster
-                List<KubernetesClusterVO> runningKubernetesClusters = kubernetesClusterDao.findKubernetesClustersInState(KubernetesCluster.State.Running);
+                List<KubernetesClusterVO> runningKubernetesClusters = kubernetesClusterDao.findManagedKubernetesClustersInState(KubernetesCluster.State.Running);
                 for (KubernetesCluster kubernetesCluster : runningKubernetesClusters) {
                     if (LOGGER.isInfoEnabled()) {
                         LOGGER.info(String.format("Running Kubernetes cluster state scanner on Kubernetes cluster : %s", kubernetesCluster.getName()));
@@ -1457,7 +1767,7 @@
                 }
 
                 // run through Kubernetes clusters in 'Stopped' state and ensure all the VM's are Stopped in the cluster
-                List<KubernetesClusterVO> stoppedKubernetesClusters = kubernetesClusterDao.findKubernetesClustersInState(KubernetesCluster.State.Stopped);
+                List<KubernetesClusterVO> stoppedKubernetesClusters = kubernetesClusterDao.findManagedKubernetesClustersInState(KubernetesCluster.State.Stopped);
                 for (KubernetesCluster kubernetesCluster : stoppedKubernetesClusters) {
                     if (LOGGER.isInfoEnabled()) {
                         LOGGER.info(String.format("Running Kubernetes cluster state scanner on Kubernetes cluster : %s for state: %s", kubernetesCluster.getName(), KubernetesCluster.State.Stopped.toString()));
@@ -1472,7 +1782,7 @@
                 }
 
                 // run through Kubernetes clusters in 'Alert' state and reconcile state as 'Running' if the VM's are running or 'Stopped' if VM's are stopped
-                List<KubernetesClusterVO> alertKubernetesClusters = kubernetesClusterDao.findKubernetesClustersInState(KubernetesCluster.State.Alert);
+                List<KubernetesClusterVO> alertKubernetesClusters = kubernetesClusterDao.findManagedKubernetesClustersInState(KubernetesCluster.State.Alert);
                 for (KubernetesClusterVO kubernetesCluster : alertKubernetesClusters) {
                     if (LOGGER.isInfoEnabled()) {
                         LOGGER.info(String.format("Running Kubernetes cluster state scanner on Kubernetes cluster : %s for state: %s", kubernetesCluster.getName(), KubernetesCluster.State.Alert.toString()));
@@ -1495,7 +1805,7 @@
 
                 if (firstRun) {
                     // run through Kubernetes clusters in 'Starting' state and reconcile state as 'Alert' or 'Error' if the VM's are running
-                    List<KubernetesClusterVO> startingKubernetesClusters = kubernetesClusterDao.findKubernetesClustersInState(KubernetesCluster.State.Starting);
+                    List<KubernetesClusterVO> startingKubernetesClusters = kubernetesClusterDao.findManagedKubernetesClustersInState(KubernetesCluster.State.Starting);
                     for (KubernetesCluster kubernetesCluster : startingKubernetesClusters) {
                         if ((new Date()).getTime() - kubernetesCluster.getCreated().getTime() < 10*60*1000) {
                             continue;
@@ -1513,7 +1823,7 @@
                             LOGGER.warn(String.format("Failed to run Kubernetes cluster Starting state scanner on Kubernetes cluster : %s status scanner", kubernetesCluster.getName()), e);
                         }
                     }
-                    List<KubernetesClusterVO> destroyingKubernetesClusters = kubernetesClusterDao.findKubernetesClustersInState(KubernetesCluster.State.Destroying);
+                    List<KubernetesClusterVO> destroyingKubernetesClusters = kubernetesClusterDao.findManagedKubernetesClustersInState(KubernetesCluster.State.Destroying);
                     for (KubernetesCluster kubernetesCluster : destroyingKubernetesClusters) {
                         if (LOGGER.isInfoEnabled()) {
                             LOGGER.info(String.format("Running Kubernetes cluster state scanner on Kubernetes cluster : %s for state: %s", kubernetesCluster.getName(), KubernetesCluster.State.Destroying.toString()));
diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterService.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterService.java
index 420f355..0a988e5 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterService.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterService.java
@@ -16,20 +16,27 @@
 // under the License.
 package com.cloud.kubernetes.cluster;
 
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.AddVirtualMachinesToKubernetesClusterCmd;
 import org.apache.cloudstack.api.command.user.kubernetes.cluster.CreateKubernetesClusterCmd;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.DeleteKubernetesClusterCmd;
 import org.apache.cloudstack.api.command.user.kubernetes.cluster.GetKubernetesClusterConfigCmd;
 import org.apache.cloudstack.api.command.user.kubernetes.cluster.ListKubernetesClustersCmd;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.RemoveVirtualMachinesFromKubernetesClusterCmd;
 import org.apache.cloudstack.api.command.user.kubernetes.cluster.ScaleKubernetesClusterCmd;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.StopKubernetesClusterCmd;
 import org.apache.cloudstack.api.command.user.kubernetes.cluster.UpgradeKubernetesClusterCmd;
 import org.apache.cloudstack.api.response.KubernetesClusterConfigResponse;
 import org.apache.cloudstack.api.response.KubernetesClusterResponse;
 import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.RemoveVirtualMachinesFromKubernetesClusterResponse;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.config.Configurable;
 
 import com.cloud.utils.component.PluggableService;
 import com.cloud.utils.exception.CloudRuntimeException;
 
+import java.util.List;
+
 public interface KubernetesClusterService extends PluggableService, Configurable {
     static final String MIN_KUBERNETES_VERSION_HA_SUPPORT = "1.16.0";
     static final int MIN_KUBERNETES_CLUSTER_NODE_CPU = 2;
@@ -38,7 +45,7 @@
 
     static final ConfigKey<Boolean> KubernetesServiceEnabled = new ConfigKey<Boolean>("Advanced", Boolean.class,
             "cloud.kubernetes.service.enabled",
-            "false",
+            "true",
             "Indicates whether Kubernetes Service plugin is enabled or not. Management server restart needed on change",
             false);
     static final ConfigKey<String> KubernetesClusterNetworkOffering = new ConfigKey<String>("Advanced", String.class,
@@ -81,13 +88,17 @@
 
     KubernetesCluster findById(final Long id);
 
-    KubernetesCluster createKubernetesCluster(CreateKubernetesClusterCmd cmd) throws CloudRuntimeException;
+    KubernetesCluster createUnmanagedKubernetesCluster(CreateKubernetesClusterCmd cmd) throws CloudRuntimeException;
+
+    KubernetesCluster createManagedKubernetesCluster(CreateKubernetesClusterCmd cmd) throws CloudRuntimeException;
 
     boolean startKubernetesCluster(long kubernetesClusterId, boolean onCreate) throws CloudRuntimeException;
 
-    boolean stopKubernetesCluster(long kubernetesClusterId) throws CloudRuntimeException;
+    boolean stopKubernetesCluster(StopKubernetesClusterCmd cmd) throws CloudRuntimeException;
 
-    boolean deleteKubernetesCluster(Long kubernetesClusterId) throws CloudRuntimeException;
+    boolean deleteKubernetesCluster(DeleteKubernetesClusterCmd cmd) throws CloudRuntimeException;
+
+    boolean isCommandSupported(KubernetesCluster cluster, String cmdName);
 
     ListResponse<KubernetesClusterResponse> listKubernetesClusters(ListKubernetesClustersCmd cmd);
 
@@ -98,4 +109,8 @@
     boolean scaleKubernetesCluster(ScaleKubernetesClusterCmd cmd) throws CloudRuntimeException;
 
     boolean upgradeKubernetesCluster(UpgradeKubernetesClusterCmd cmd) throws CloudRuntimeException;
+
+    boolean addVmsToCluster(AddVirtualMachinesToKubernetesClusterCmd cmd);
+
+    List<RemoveVirtualMachinesFromKubernetesClusterResponse> removeVmsFromCluster(RemoveVirtualMachinesFromKubernetesClusterCmd cmd);
 }
diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterVO.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterVO.java
index 1b30b1b..270916a 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterVO.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterVO.java
@@ -52,16 +52,16 @@
     private long zoneId;
 
     @Column(name = "kubernetes_version_id")
-    private long kubernetesVersionId;
+    private Long kubernetesVersionId;
 
     @Column(name = "service_offering_id")
-    private long serviceOfferingId;
+    private Long serviceOfferingId;
 
     @Column(name = "template_id")
-    private long templateId;
+    private Long templateId;
 
     @Column(name = "network_id")
-    private long networkId;
+    private Long networkId;
 
     @Column(name = "domain_id")
     private long domainId;
@@ -114,6 +114,9 @@
     @Column(name = "security_group_id")
     private Long securityGroupId;
 
+    @Column(name = "cluster_type")
+    private ClusterType clusterType;
+
     @Override
     public long getId() {
         return id;
@@ -160,7 +163,7 @@
     }
 
     @Override
-    public long getKubernetesVersionId() {
+    public Long getKubernetesVersionId() {
         return kubernetesVersionId;
     }
 
@@ -169,7 +172,7 @@
     }
 
     @Override
-    public long getServiceOfferingId() {
+    public Long getServiceOfferingId() {
         return serviceOfferingId;
     }
 
@@ -178,7 +181,7 @@
     }
 
     @Override
-    public long getTemplateId() {
+    public Long getTemplateId() {
         return templateId;
     }
 
@@ -187,7 +190,7 @@
     }
 
     @Override
-    public long getNetworkId() {
+    public Long getNetworkId() {
         return networkId;
     }
 
@@ -350,13 +353,21 @@
         return securityGroupId;
     }
 
+    public ClusterType getClusterType() {
+        return clusterType;
+    }
+
+    public void setClusterType(ClusterType clusterType) {
+        this.clusterType = clusterType;
+    }
+
     public KubernetesClusterVO() {
         this.uuid = UUID.randomUUID().toString();
     }
 
-    public KubernetesClusterVO(String name, String description, long zoneId, long kubernetesVersionId, long serviceOfferingId, long templateId,
-                               long networkId, long domainId, long accountId, long controlNodeCount, long nodeCount, State state,
-                               String keyPair, long cores, long memory, Long nodeRootDiskSize, String endpoint) {
+    public KubernetesClusterVO(String name, String description, long zoneId, Long kubernetesVersionId, Long serviceOfferingId, Long templateId,
+                               Long networkId, long domainId, long accountId, long controlNodeCount, long nodeCount, State state,
+                               String keyPair, long cores, long memory, Long nodeRootDiskSize, String endpoint, ClusterType clusterType) {
         this.uuid = UUID.randomUUID().toString();
         this.name = name;
         this.description = description;
@@ -377,14 +388,15 @@
             this.nodeRootDiskSize = nodeRootDiskSize;
         }
         this.endpoint = endpoint;
+        this.clusterType = clusterType;
         this.checkForGc = false;
     }
 
     public KubernetesClusterVO(String name, String description, long zoneId, long kubernetesVersionId, long serviceOfferingId, long templateId,
         long networkId, long domainId, long accountId, long controlNodeCount, long nodeCount, State state, String keyPair, long cores,
-        long memory, Long nodeRootDiskSize, String endpoint, boolean autoscalingEnabled, Long minSize, Long maxSize) {
+        long memory, Long nodeRootDiskSize, String endpoint, ClusterType clusterType, boolean autoscalingEnabled, Long minSize, Long maxSize) {
         this(name, description, zoneId, kubernetesVersionId, serviceOfferingId, templateId, networkId, domainId, accountId, controlNodeCount,
-            nodeCount, state, keyPair, cores, memory, nodeRootDiskSize, endpoint);
+            nodeCount, state, keyPair, cores, memory, nodeRootDiskSize, endpoint, clusterType);
         this.autoscalingEnabled = autoscalingEnabled;
         this.minSize = minSize;
         this.maxSize = maxSize;
diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterDao.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterDao.java
index fe67323..9341912 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterDao.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterDao.java
@@ -28,7 +28,7 @@
 
     List<KubernetesClusterVO> listByAccount(long accountId);
     List<KubernetesClusterVO> findKubernetesClustersToGarbageCollect();
-    List<KubernetesClusterVO> findKubernetesClustersInState(KubernetesCluster.State state);
+    List<KubernetesClusterVO> findManagedKubernetesClustersInState(KubernetesCluster.State state);
     List<KubernetesClusterVO> listByNetworkId(long networkId);
     List<KubernetesClusterVO> listAllByKubernetesVersion(long kubernetesVersionId);
 }
diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterDaoImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterDaoImpl.java
index 003286c..63cca35 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterDaoImpl.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterDaoImpl.java
@@ -32,7 +32,7 @@
 
     private final SearchBuilder<KubernetesClusterVO> AccountIdSearch;
     private final SearchBuilder<KubernetesClusterVO> GarbageCollectedSearch;
-    private final SearchBuilder<KubernetesClusterVO> StateSearch;
+    private final SearchBuilder<KubernetesClusterVO> ManagedStateSearch;
     private final SearchBuilder<KubernetesClusterVO> SameNetworkSearch;
     private final SearchBuilder<KubernetesClusterVO> KubernetesVersionSearch;
 
@@ -44,11 +44,13 @@
         GarbageCollectedSearch = createSearchBuilder();
         GarbageCollectedSearch.and("gc", GarbageCollectedSearch.entity().isCheckForGc(), SearchCriteria.Op.EQ);
         GarbageCollectedSearch.and("state", GarbageCollectedSearch.entity().getState(), SearchCriteria.Op.EQ);
+        GarbageCollectedSearch.and("cluster_type", GarbageCollectedSearch.entity().getClusterType(), SearchCriteria.Op.EQ);
         GarbageCollectedSearch.done();
 
-        StateSearch = createSearchBuilder();
-        StateSearch.and("state", StateSearch.entity().getState(), SearchCriteria.Op.EQ);
-        StateSearch.done();
+        ManagedStateSearch = createSearchBuilder();
+        ManagedStateSearch.and("state", ManagedStateSearch.entity().getState(), SearchCriteria.Op.EQ);
+        ManagedStateSearch.and("cluster_type", ManagedStateSearch.entity().getClusterType(), SearchCriteria.Op.EQ);
+        ManagedStateSearch.done();
 
         SameNetworkSearch = createSearchBuilder();
         SameNetworkSearch.and("network_id", SameNetworkSearch.entity().getNetworkId(), SearchCriteria.Op.EQ);
@@ -71,13 +73,15 @@
         SearchCriteria<KubernetesClusterVO> sc = GarbageCollectedSearch.create();
         sc.setParameters("gc", true);
         sc.setParameters("state", KubernetesCluster.State.Destroying);
+        sc.setParameters("cluster_type", KubernetesCluster.ClusterType.CloudManaged);
         return listBy(sc);
     }
 
     @Override
-    public List<KubernetesClusterVO> findKubernetesClustersInState(KubernetesCluster.State state) {
-        SearchCriteria<KubernetesClusterVO> sc = StateSearch.create();
+    public List<KubernetesClusterVO> findManagedKubernetesClustersInState(KubernetesCluster.State state) {
+        SearchCriteria<KubernetesClusterVO> sc = ManagedStateSearch.create();
         sc.setParameters("state", state);
+        sc.setParameters("cluster_type", KubernetesCluster.ClusterType.CloudManaged);
         return listBy(sc);
     }
 
diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDao.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDao.java
index 42061cd..688a611 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDao.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDao.java
@@ -24,4 +24,8 @@
 public interface KubernetesClusterVmMapDao extends GenericDao<KubernetesClusterVmMapVO, Long> {
     public List<KubernetesClusterVmMapVO> listByClusterId(long clusterId);
     public List<KubernetesClusterVmMapVO> listByClusterIdAndVmIdsIn(long clusterId, List<Long> vmIds);
+
+    int removeByClusterIdAndVmIdsIn(long clusterId, List<Long> vmIds);
+
+    public int removeByClusterId(long clusterId);
 }
diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDaoImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDaoImpl.java
index c5a9ad4..b9f2ec9 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDaoImpl.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/dao/KubernetesClusterVmMapDaoImpl.java
@@ -54,4 +54,19 @@
         sc.setParameters("vmIdsIN", vmIds.toArray());
         return listBy(sc);
     }
+
+    @Override
+    public int removeByClusterIdAndVmIdsIn(long clusterId, List<Long> vmIds) {
+        SearchCriteria<KubernetesClusterVmMapVO> sc = clusterIdSearch.create();
+        sc.setParameters("clusterId", clusterId);
+        sc.setParameters("vmIdsIN", vmIds.toArray());
+        return remove(sc);
+    }
+
+    @Override
+    public int removeByClusterId(long clusterId) {
+        SearchCriteria<KubernetesClusterVmMapVO> sc = clusterIdSearch.create();
+        sc.setParameters("clusterId", clusterId);
+        return remove(sc);
+    }
 }
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/AddVirtualMachinesToKubernetesClusterCmd.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/AddVirtualMachinesToKubernetesClusterCmd.java
new file mode 100644
index 0000000..a7134f5
--- /dev/null
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/AddVirtualMachinesToKubernetesClusterCmd.java
@@ -0,0 +1,106 @@
+// 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.command.user.kubernetes.cluster;
+
+import com.cloud.kubernetes.cluster.KubernetesClusterService;
+import com.cloud.utils.exception.CloudRuntimeException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.KubernetesClusterResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.log4j.Logger;
+
+import javax.inject.Inject;
+import java.util.List;
+
+@APICommand(name = "addVirtualMachinesToKubernetesCluster",
+        description = "Add VMs to an ExternalManaged kubernetes cluster. Not applicable for CloudManaged kubernetes clusters.",
+        responseObject = SuccessResponse.class,
+        since = "4.19.0",
+        authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class AddVirtualMachinesToKubernetesClusterCmd extends BaseCmd {
+    public static final Logger LOGGER = Logger.getLogger(AddVirtualMachinesToKubernetesClusterCmd.class.getName());
+
+    @Inject
+    public KubernetesClusterService kubernetesClusterService;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name = ApiConstants.ID, type = CommandType.UUID,
+            entityType = KubernetesClusterResponse.class,
+            required = true,
+            description = "the ID of the Kubernetes cluster")
+    private Long id;
+
+    @Parameter(name = ApiConstants.VIRTUAL_MACHINE_IDS, type = CommandType.LIST,
+            collectionType=CommandType.UUID,
+            entityType = UserVmResponse.class,
+            required = true,
+            description = "the IDs of the VMs to add to the cluster")
+    private List<Long> vmIds;
+
+    @Parameter(name = ApiConstants.IS_CONTROL_NODE, type = CommandType.BOOLEAN,
+            description = "Is control node or not? Defaults to false.")
+    private Boolean isControlNode;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getId() {
+        return id;
+    }
+
+    public List<Long> getVmIds() {
+        return vmIds;
+    }
+
+    public boolean isControlNode() {
+        return (isControlNode != null) && isControlNode;
+    }
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public long getEntityOwnerId() {
+        return CallContext.current().getCallingAccount().getId();
+    }
+
+    @Override
+    public void execute() throws ServerApiException {
+        try {
+            if (!kubernetesClusterService.addVmsToCluster(this)) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add VMs to cluster");
+            }
+            final SuccessResponse response = new SuccessResponse();
+            response.setResponseName(getCommandName());
+            setResponseObject(response);
+        } catch (CloudRuntimeException e) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
+        }
+    }
+}
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java
index 5e4bd39..aa53a05 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/CreateKubernetesClusterCmd.java
@@ -20,6 +20,7 @@
 
 import javax.inject.Inject;
 
+import com.cloud.exception.InvalidParameterValueException;
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import org.apache.cloudstack.api.ACL;
@@ -39,6 +40,7 @@
 import org.apache.cloudstack.api.response.ServiceOfferingResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.context.CallContext;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
 import com.cloud.kubernetes.cluster.KubernetesCluster;
@@ -68,7 +70,7 @@
     @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "name for the Kubernetes cluster")
     private String name;
 
-    @Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, required = true, description = "description for the Kubernetes cluster")
+    @Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "description for the Kubernetes cluster")
     private String description;
 
     @ACL(accessType = AccessType.UseEntry)
@@ -76,13 +78,13 @@
             description = "availability zone in which Kubernetes cluster to be launched")
     private Long zoneId;
 
-    @Parameter(name = ApiConstants.KUBERNETES_VERSION_ID, type = CommandType.UUID, entityType = KubernetesSupportedVersionResponse.class, required = true,
+    @Parameter(name = ApiConstants.KUBERNETES_VERSION_ID, type = CommandType.UUID, entityType = KubernetesSupportedVersionResponse.class,
             description = "Kubernetes version with which cluster to be launched")
     private Long kubernetesVersionId;
 
     @ACL(accessType = AccessType.UseEntry)
     @Parameter(name = ApiConstants.SERVICE_OFFERING_ID, type = CommandType.UUID, entityType = ServiceOfferingResponse.class,
-            required = true, description = "the ID of the service offering for the virtual machines in the cluster.")
+            description = "the ID of the service offering for the virtual machines in the cluster.")
     private Long serviceOfferingId;
 
     @ACL(accessType = AccessType.UseEntry)
@@ -124,7 +126,7 @@
     private String externalLoadBalancerIpAddress;
 
     @Parameter(name=ApiConstants.SIZE, type = CommandType.LONG,
-            required = true, description = "number of Kubernetes cluster worker nodes")
+            description = "number of Kubernetes cluster worker nodes")
     private Long clusterSize;
 
     @Parameter(name = ApiConstants.DOCKER_REGISTRY_USER_NAME, type = CommandType.STRING,
@@ -143,6 +145,9 @@
             description = "root disk size in GB for each node")
     private Long nodeRootDiskSize;
 
+    @Parameter(name = ApiConstants.CLUSTER_TYPE, type = CommandType.STRING, required = true, description = "type of the cluster: CloudManaged, ExternalManaged", since="4.19.0")
+    private String clusterType;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -155,7 +160,7 @@
     }
 
     public String getDisplayName() {
-        return description;
+        return StringUtils.firstNonEmpty(description, name);
     }
 
     public Long getDomainId() {
@@ -232,6 +237,13 @@
         }
     }
 
+    public String getClusterType() {
+        if (clusterType == null) {
+            return KubernetesCluster.ClusterType.CloudManaged.toString();
+        }
+        return clusterType;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
@@ -278,7 +290,8 @@
     @Override
     public void execute() {
         try {
-            if (!kubernetesClusterService.startKubernetesCluster(getEntityId(), true)) {
+            if (KubernetesCluster.ClusterType.valueOf(getClusterType()) == KubernetesCluster.ClusterType.CloudManaged
+                    && !kubernetesClusterService.startKubernetesCluster(getEntityId(), true)) {
                 throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to start Kubernetes cluster");
             }
             KubernetesClusterResponse response = kubernetesClusterService.createKubernetesClusterResponse(getEntityId());
@@ -291,8 +304,20 @@
 
     @Override
     public void create() throws CloudRuntimeException {
+        KubernetesCluster cluster;
+        KubernetesCluster.ClusterType type;
         try {
-            KubernetesCluster cluster = kubernetesClusterService.createKubernetesCluster(this);
+            type = KubernetesCluster.ClusterType.valueOf(getClusterType());
+        } catch (IllegalArgumentException e) {
+            throw new InvalidParameterValueException("Unable to resolve cluster type " + getClusterType() + " to a supported value (CloudManaged, ExternalManaged)");
+        }
+
+        try {
+            if (type == KubernetesCluster.ClusterType.CloudManaged) {
+                cluster = kubernetesClusterService.createManagedKubernetesCluster(this);
+            } else {
+                cluster = kubernetesClusterService.createUnmanagedKubernetesCluster(this);
+            }
             if (cluster == null) {
                 throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create Kubernetes cluster");
             }
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/DeleteKubernetesClusterCmd.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/DeleteKubernetesClusterCmd.java
index 564ae78..2b4a128 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/DeleteKubernetesClusterCmd.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/DeleteKubernetesClusterCmd.java
@@ -58,6 +58,18 @@
             description = "the ID of the Kubernetes cluster")
     private Long id;
 
+    @Parameter(name = ApiConstants.CLEANUP,
+            type = CommandType.BOOLEAN,
+            since = "4.19.0",
+            description = "Destroy attached instances of the ExternalManaged Cluster. Default: false")
+    private Boolean cleanup;
+
+    @Parameter(name = ApiConstants.EXPUNGE,
+            type = CommandType.BOOLEAN,
+            since = "4.19.0",
+            description = "Expunge attached instances of the ExternalManaged Cluster. If true, value of cleanup is ignored. Default: false")
+    private Boolean expunge;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -66,6 +78,14 @@
         return id;
     }
 
+    public Boolean getCleanup() {
+        return cleanup != null && cleanup;
+    }
+
+    public Boolean getExpunge() {
+        return expunge != null && expunge;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
@@ -73,7 +93,7 @@
     @Override
     public void execute() throws ServerApiException, ConcurrentOperationException {
         try {
-            if (!kubernetesClusterService.deleteKubernetesCluster(id)) {
+            if (!kubernetesClusterService.deleteKubernetesCluster(this)) {
                 throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to delete Kubernetes cluster ID: %d", getId()));
             }
             SuccessResponse response = new SuccessResponse(getCommandName());
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/ListKubernetesClustersCmd.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/ListKubernetesClustersCmd.java
index 692b934..33eab2c 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/ListKubernetesClustersCmd.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/ListKubernetesClustersCmd.java
@@ -61,6 +61,10 @@
             " (a substring match is made against the parameter value, data for all matching Kubernetes clusters will be returned)")
     private String name;
 
+    @Parameter(name = ApiConstants.CLUSTER_TYPE, type = CommandType.STRING, since = "4.19.0",
+            description = "type of the cluster: CloudManaged, ExternalManaged")
+    private String clusterType;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -77,6 +81,10 @@
         return name;
     }
 
+    public String getClusterType() {
+        return clusterType;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/RemoveVirtualMachinesFromKubernetesClusterCmd.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/RemoveVirtualMachinesFromKubernetesClusterCmd.java
new file mode 100644
index 0000000..704d0b2
--- /dev/null
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/RemoveVirtualMachinesFromKubernetesClusterCmd.java
@@ -0,0 +1,103 @@
+// 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.command.user.kubernetes.cluster;
+
+import com.cloud.kubernetes.cluster.KubernetesClusterService;
+import com.cloud.utils.exception.CloudRuntimeException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.KubernetesClusterResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.RemoveVirtualMachinesFromKubernetesClusterResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.log4j.Logger;
+
+import javax.inject.Inject;
+import java.util.List;
+
+@APICommand(name = "removeVirtualMachinesFromKubernetesCluster",
+        description = "Remove VMs from an ExternalManaged kubernetes cluster. Not applicable for CloudManaged kubernetes clusters.",
+        responseObject = RemoveVirtualMachinesFromKubernetesClusterResponse.class,
+        since = "4.19.0",
+        authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class RemoveVirtualMachinesFromKubernetesClusterCmd extends BaseListCmd {
+    public static final Logger LOGGER = Logger.getLogger(RemoveVirtualMachinesFromKubernetesClusterCmd.class.getName());
+
+    @Inject
+    public KubernetesClusterService kubernetesClusterService;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID,
+            entityType = KubernetesClusterResponse.class,
+            required = true,
+            description = "the ID of the Kubernetes cluster")
+    private Long id;
+
+    @Parameter(name = ApiConstants.VIRTUAL_MACHINE_IDS, type = CommandType.LIST,
+            collectionType=CommandType.UUID,
+            entityType = UserVmResponse.class,
+            required = true,
+            description = "the IDs of the VMs to remove from the cluster")
+    private List<Long> vmIds;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getId() {
+        return id;
+    }
+
+    public List<Long> getVmIds() {
+        return vmIds;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public long getEntityOwnerId() {
+        return CallContext.current().getCallingAccount().getId();
+    }
+
+    @Override
+    public void execute() throws ServerApiException {
+        try {
+            List<RemoveVirtualMachinesFromKubernetesClusterResponse> responseList = kubernetesClusterService.removeVmsFromCluster(this);
+            if (responseList.size() < 1) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Provided VMs are not part of the CKS cluster");
+            }
+            ListResponse<RemoveVirtualMachinesFromKubernetesClusterResponse> listResponse = new ListResponse<>();
+            listResponse.setResponseName(getCommandName());
+            listResponse.setResponses(responseList);
+            setResponseObject(listResponse);
+        } catch (CloudRuntimeException e) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
+        }
+    }
+}
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/ScaleKubernetesClusterCmd.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/ScaleKubernetesClusterCmd.java
index f3c9939..e5a5c90 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/ScaleKubernetesClusterCmd.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/ScaleKubernetesClusterCmd.java
@@ -43,7 +43,7 @@
 import com.cloud.utils.exception.CloudRuntimeException;
 
 @APICommand(name = "scaleKubernetesCluster",
-        description = "Scales a created, running or stopped Kubernetes cluster",
+        description = "Scales a created, running or stopped CloudManaged Kubernetes cluster",
         responseObject = KubernetesClusterResponse.class,
         responseView = ResponseObject.ResponseView.Restricted,
         entityType = {KubernetesCluster.class},
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/StartKubernetesClusterCmd.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/StartKubernetesClusterCmd.java
index 1140cac..7a7c1e8 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/StartKubernetesClusterCmd.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/StartKubernetesClusterCmd.java
@@ -36,7 +36,7 @@
 import com.cloud.kubernetes.cluster.KubernetesClusterService;
 import com.cloud.utils.exception.CloudRuntimeException;
 
-@APICommand(name = "startKubernetesCluster", description = "Starts a stopped Kubernetes cluster",
+@APICommand(name = "startKubernetesCluster", description = "Starts a stopped CloudManaged Kubernetes cluster",
         responseObject = KubernetesClusterResponse.class,
         responseView = ResponseObject.ResponseView.Restricted,
         entityType = {KubernetesCluster.class},
@@ -99,6 +99,10 @@
         if (kubernetesCluster == null) {
             throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Given Kubernetes cluster was not found");
         }
+        if (!kubernetesClusterService.isCommandSupported(kubernetesCluster, getActualCommandName())) {
+            throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
+                    String.format("Start kubernetes cluster is not supported for an externally managed cluster (%s)", kubernetesCluster.getName()));
+        }
         return kubernetesCluster;
     }
 
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/StopKubernetesClusterCmd.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/StopKubernetesClusterCmd.java
index 393786f..866a7a8 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/StopKubernetesClusterCmd.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/StopKubernetesClusterCmd.java
@@ -37,7 +37,7 @@
 import com.cloud.kubernetes.cluster.KubernetesClusterService;
 import com.cloud.utils.exception.CloudRuntimeException;
 
-@APICommand(name = "stopKubernetesCluster", description = "Stops a running Kubernetes cluster",
+@APICommand(name = "stopKubernetesCluster", description = "Stops a running CloudManaged Kubernetes cluster",
         responseObject = SuccessResponse.class,
         responseView = ResponseObject.ResponseView.Restricted,
         entityType = {KubernetesCluster.class},
@@ -95,7 +95,7 @@
     @Override
     public void execute() throws ServerApiException, ConcurrentOperationException {
         try {
-            if (!kubernetesClusterService.stopKubernetesCluster(getId())) {
+            if (!kubernetesClusterService.stopKubernetesCluster(this)) {
                 throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to start Kubernetes cluster ID: %d", getId()));
             }
             final SuccessResponse response = new SuccessResponse(getCommandName());
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/UpgradeKubernetesClusterCmd.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/UpgradeKubernetesClusterCmd.java
index 3283ea0..2cbedf5 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/UpgradeKubernetesClusterCmd.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/user/kubernetes/cluster/UpgradeKubernetesClusterCmd.java
@@ -38,7 +38,7 @@
 import com.cloud.kubernetes.cluster.KubernetesClusterService;
 import com.cloud.utils.exception.CloudRuntimeException;
 
-@APICommand(name = "upgradeKubernetesCluster", description = "Upgrades a running Kubernetes cluster",
+@APICommand(name = "upgradeKubernetesCluster", description = "Upgrades a running CloudManaged Kubernetes cluster",
         responseObject = KubernetesClusterResponse.class,
         responseView = ResponseObject.ResponseView.Restricted,
         entityType = {KubernetesCluster.class},
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/KubernetesClusterResponse.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/KubernetesClusterResponse.java
index a67d41a..168dfaf 100644
--- a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/KubernetesClusterResponse.java
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/KubernetesClusterResponse.java
@@ -159,6 +159,10 @@
     @Param(description = "Maximum size of the cluster")
     private Long maxSize;
 
+    @SerializedName(ApiConstants.CLUSTER_TYPE)
+    @Param(description = "the type of the cluster")
+    private KubernetesCluster.ClusterType clusterType;
+
     @SerializedName(ApiConstants.CREATED)
     @Param(description = "the date when this Kubernetes cluster was created")
     private Date created;
@@ -386,4 +390,12 @@
     public void setCreated(Date created) {
         this.created = created;
     }
+
+    public KubernetesCluster.ClusterType getClusterType() {
+        return clusterType;
+    }
+
+    public void setClusterType(KubernetesCluster.ClusterType clusterType) {
+        this.clusterType = clusterType;
+    }
 }
diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/RemoveVirtualMachinesFromKubernetesClusterResponse.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/RemoveVirtualMachinesFromKubernetesClusterResponse.java
new file mode 100644
index 0000000..eb2dfce
--- /dev/null
+++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/response/RemoveVirtualMachinesFromKubernetesClusterResponse.java
@@ -0,0 +1,34 @@
+// 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.response;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.ApiConstants;
+
+public class RemoveVirtualMachinesFromKubernetesClusterResponse extends SuccessResponse {
+    @SerializedName(ApiConstants.ID)
+    @Param(description = "the id of the Kubernetes cluster")
+    private String vmId;
+
+    public RemoveVirtualMachinesFromKubernetesClusterResponse() {
+    }
+
+    public void setVmId(String vmId) {
+        this.vmId = vmId;
+    }
+}
diff --git a/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImplTest.java b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImplTest.java
index 52e555c..a6d46ff 100644
--- a/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImplTest.java
+++ b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImplTest.java
@@ -1,25 +1,52 @@
-// 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.
+/*
+ * 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.kubernetes.cluster;
 
-
-import java.util.ArrayList;
-import java.util.List;
-
+import com.cloud.api.query.dao.TemplateJoinDao;
+import com.cloud.api.query.vo.TemplateJoinVO;
+import com.cloud.dc.DataCenter;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.kubernetes.cluster.actionworkers.KubernetesClusterActionWorker;
+import com.cloud.kubernetes.cluster.dao.KubernetesClusterDao;
+import com.cloud.kubernetes.cluster.dao.KubernetesClusterVmMapDao;
+import com.cloud.network.Network;
+import com.cloud.network.dao.FirewallRulesDao;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.FirewallRuleVO;
+import com.cloud.network.vpc.NetworkACL;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.User;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.dao.VMInstanceDao;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.AddVirtualMachinesToKubernetesClusterCmd;
+import org.apache.cloudstack.api.command.user.kubernetes.cluster.RemoveVirtualMachinesFromKubernetesClusterCmd;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
@@ -28,19 +55,11 @@
 import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnitRunner;
 
-import com.cloud.api.query.dao.TemplateJoinDao;
-import com.cloud.api.query.vo.TemplateJoinVO;
-import com.cloud.dc.DataCenter;
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.exception.PermissionDeniedException;
-import com.cloud.kubernetes.cluster.actionworkers.KubernetesClusterActionWorker;
-import com.cloud.network.Network;
-import com.cloud.network.dao.FirewallRulesDao;
-import com.cloud.network.rules.FirewallRule;
-import com.cloud.network.rules.FirewallRuleVO;
-import com.cloud.network.vpc.NetworkACL;
-import com.cloud.storage.VMTemplateVO;
-import com.cloud.storage.dao.VMTemplateDao;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 @RunWith(MockitoJUnitRunner.class)
 public class KubernetesClusterManagerImplTest {
@@ -54,6 +73,18 @@
     @Mock
     TemplateJoinDao templateJoinDao;
 
+    @Mock
+    KubernetesClusterDao kubernetesClusterDao;
+
+    @Mock
+    KubernetesClusterVmMapDao kubernetesClusterVmMapDao;
+
+    @Mock
+    VMInstanceDao vmInstanceDao;
+
+    @Mock
+    private AccountManager accountManager;
+
     @Spy
     @InjectMocks
     KubernetesClusterManagerImpl kubernetesClusterManager;
@@ -171,7 +202,7 @@
     }
 
     @Test
-    public void testValidateKubernetesClusterScaleSizeDownsacaleNoError() {
+    public void testValidateKubernetesClusterScaleSizeDownscaleNoError() {
         KubernetesClusterVO clusterVO = Mockito.mock(KubernetesClusterVO.class);
         Mockito.when(clusterVO.getState()).thenReturn(KubernetesCluster.State.Running);
         Mockito.when(clusterVO.getControlNodeCount()).thenReturn(1L);
@@ -209,5 +240,56 @@
         Mockito.when(templateDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(VMTemplateVO.class));
         Mockito.when(templateJoinDao.newTemplateView(Mockito.any(VMTemplateVO.class), Mockito.anyLong(), Mockito.anyBoolean())).thenReturn(List.of(Mockito.mock(TemplateJoinVO.class)));
         kubernetesClusterManager.validateKubernetesClusterScaleSize(clusterVO, 4L, 10, Mockito.mock(DataCenter.class));
+
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        CallContext.register(Mockito.mock(User.class), Mockito.mock(Account.class));
+        overrideDefaultConfigValue(KubernetesClusterService.KubernetesServiceEnabled, "_defaultValue", "true");
+        Mockito.doNothing().when(accountManager).checkAccess(
+                Mockito.any(Account.class), Mockito.any(), Mockito.anyBoolean(), Mockito.any());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        CallContext.unregister();
+    }
+
+    private void overrideDefaultConfigValue(final ConfigKey configKey, final String name, final Object o) throws IllegalAccessException, NoSuchFieldException {
+        Field f = ConfigKey.class.getDeclaredField(name);
+        f.setAccessible(true);
+        f.set(configKey, o);
+    }
+
+    @Test
+    public void addVmsToCluster() {
+        KubernetesClusterVO cluster = Mockito.mock(KubernetesClusterVO.class);
+        VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
+        AddVirtualMachinesToKubernetesClusterCmd cmd = Mockito.mock(AddVirtualMachinesToKubernetesClusterCmd.class);
+        List<Long> vmIds = Arrays.asList(1L, 2L, 3L);
+
+        Mockito.when(cmd.getId()).thenReturn(1L);
+        Mockito.when(cmd.getVmIds()).thenReturn(vmIds);
+        Mockito.when(cmd.getActualCommandName()).thenReturn(BaseCmd.getCommandNameByClass(RemoveVirtualMachinesFromKubernetesClusterCmd.class));
+        Mockito.when(cluster.getClusterType()).thenReturn(KubernetesCluster.ClusterType.ExternalManaged);
+        Mockito.when(vmInstanceDao.findById(Mockito.anyLong())).thenReturn(vm);
+        Mockito.when(kubernetesClusterDao.findById(Mockito.anyLong())).thenReturn(cluster);
+        Mockito.when(kubernetesClusterVmMapDao.listByClusterIdAndVmIdsIn(1L, vmIds)).thenReturn(Collections.emptyList());
+        Assert.assertTrue(kubernetesClusterManager.addVmsToCluster(cmd));
+    }
+
+    @Test
+    public void removeVmsFromCluster() {
+        KubernetesClusterVO cluster = Mockito.mock(KubernetesClusterVO.class);
+        RemoveVirtualMachinesFromKubernetesClusterCmd cmd = Mockito.mock(RemoveVirtualMachinesFromKubernetesClusterCmd.class);
+        List<Long> vmIds = Arrays.asList(1L, 2L, 3L);
+
+        Mockito.when(cmd.getId()).thenReturn(1L);
+        Mockito.when(cmd.getVmIds()).thenReturn(vmIds);
+        Mockito.when(cmd.getActualCommandName()).thenReturn(BaseCmd.getCommandNameByClass(RemoveVirtualMachinesFromKubernetesClusterCmd.class));
+        Mockito.when(cluster.getClusterType()).thenReturn(KubernetesCluster.ClusterType.ExternalManaged);
+        Mockito.when(kubernetesClusterDao.findById(Mockito.anyLong())).thenReturn(cluster);
+        Assert.assertTrue(kubernetesClusterManager.removeVmsFromCluster(cmd).size() > 0);
     }
 }
diff --git a/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/utils/KubernetesClusterUtilTest.java b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/utils/KubernetesClusterUtilTest.java
index 53bc1a3..31363db 100644
--- a/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/utils/KubernetesClusterUtilTest.java
+++ b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/cluster/utils/KubernetesClusterUtilTest.java
@@ -16,35 +16,22 @@
 // under the License.
 package com.cloud.kubernetes.cluster.utils;
 
-import java.io.File;
-
+import com.cloud.utils.Pair;
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
-import com.cloud.utils.Pair;
-import com.cloud.utils.ssh.SshHelper;
-
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(SshHelper.class)
+@RunWith(MockitoJUnitRunner.class)
 public class KubernetesClusterUtilTest {
-    String ipAddress = "10.1.1.1";
-    int port = 2222;
-    String user = "user";
-    File sshKeyFile = Mockito.mock(File.class);
-    String hostName = "host";
 
-    private void mockSshHelperExecuteThrowAndTestVersionMatch() {
+    private void executeThrowAndTestVersionMatch() {
         Pair<Boolean, String> resultPair = null;
         boolean result = KubernetesClusterUtil.clusterNodeVersionMatches(resultPair, "1.24.0");
         Assert.assertFalse(result);
     }
 
-    private void mockSshHelperExecuteAndTestVersionMatch(boolean status, String response, boolean expectedResult) {
+    private void executeAndTestVersionMatch(boolean status, String response, boolean expectedResult) {
         Pair<Boolean, String> resultPair = new Pair<>(status, response);
         boolean result = KubernetesClusterUtil.clusterNodeVersionMatches(resultPair, "1.24.0");
         Assert.assertEquals(expectedResult, result);
@@ -52,17 +39,17 @@
 
     @Test
     public void testClusterNodeVersionMatches() {
-        PowerMockito.mockStatic(SshHelper.class);
         String v1233WorkerNodeOutput = "v1.23.3";
         String v1240WorkerNodeOutput = "v1.24.0";
-        mockSshHelperExecuteAndTestVersionMatch(true, v1240WorkerNodeOutput, true);
 
-        mockSshHelperExecuteAndTestVersionMatch(true, v1233WorkerNodeOutput, false);
+        executeAndTestVersionMatch(true, v1240WorkerNodeOutput, true);
 
-        mockSshHelperExecuteAndTestVersionMatch(false, v1240WorkerNodeOutput, false);
+        executeAndTestVersionMatch(true, v1233WorkerNodeOutput, false);
 
-        mockSshHelperExecuteAndTestVersionMatch(false, v1233WorkerNodeOutput, false);
+        executeAndTestVersionMatch(false, v1240WorkerNodeOutput, false);
 
-        mockSshHelperExecuteThrowAndTestVersionMatch();
+        executeAndTestVersionMatch(false, v1233WorkerNodeOutput, false);
+
+        executeThrowAndTestVersionMatch();
     }
 }
diff --git a/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/version/KubernetesVersionServiceTest.java b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/version/KubernetesVersionServiceTest.java
index 0427c35..d92b2c4 100644
--- a/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/version/KubernetesVersionServiceTest.java
+++ b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/version/KubernetesVersionServiceTest.java
@@ -30,20 +30,22 @@
 import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
 import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
 import org.apache.cloudstack.api.command.user.kubernetes.version.ListKubernetesSupportedVersionsCmd;
+import org.apache.cloudstack.api.response.KubernetesSupportedVersionResponse;
+import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.context.CallContext;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.api.query.dao.TemplateJoinDao;
 import com.cloud.api.query.vo.TemplateJoinVO;
@@ -70,8 +72,7 @@
 import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.exception.CloudRuntimeException;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({ComponentContext.class})
+@RunWith(MockitoJUnitRunner.class)
 public class KubernetesVersionServiceTest {
 
     @InjectMocks
@@ -92,6 +93,9 @@
     @Mock
     private TemplateApiService templateService;
 
+    AutoCloseable closeable;
+
+
     private void overrideDefaultConfigValue(final ConfigKey configKey, final String name, final Object o) throws IllegalAccessException, NoSuchFieldException {
         Field f = ConfigKey.class.getDeclaredField(name);
         f.setAccessible(true);
@@ -100,7 +104,7 @@
 
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
 
         overrideDefaultConfigValue(KubernetesClusterService.KubernetesServiceEnabled, "_defaultValue", "true");
 
@@ -114,12 +118,9 @@
         when(kubernetesSupportedVersionDao.createSearchCriteria()).thenReturn(versionSearchCriteria);
 
         DataCenterVO zone = Mockito.mock(DataCenterVO.class);
-        when(zone.getId()).thenReturn(1L);
         when(dataCenterDao.findById(Mockito.anyLong())).thenReturn(zone);
 
         TemplateJoinVO templateJoinVO = Mockito.mock(TemplateJoinVO.class);
-        when(templateJoinVO.getId()).thenReturn(1L);
-        when(templateJoinVO.getUrl()).thenReturn("https://download.cloudstack.com");
         when(templateJoinVO.getState()).thenReturn(ObjectInDataStoreStateMachine.State.Ready);
         when(templateJoinDao.findById(Mockito.anyLong())).thenReturn(templateJoinVO);
 
@@ -130,6 +131,7 @@
 
     @After
     public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
@@ -141,7 +143,13 @@
         versionVOs.add(versionVO);
         when(kubernetesSupportedVersionDao.findById(Mockito.anyLong())).thenReturn(versionVO);
         when(kubernetesSupportedVersionDao.search(Mockito.any(SearchCriteria.class), Mockito.any(Filter.class))).thenReturn(versionVOs);
-        kubernetesVersionService.listKubernetesSupportedVersions(cmd);
+        ListResponse<KubernetesSupportedVersionResponse> response =
+                kubernetesVersionService.listKubernetesSupportedVersions(
+                cmd);
+        Assert.assertNotNull(response);
+        Assert.assertEquals(Integer.valueOf(1), response.getCount());
+        Assert.assertEquals(1, response.getResponses().size());
+        Assert.assertEquals(KubernetesVersionService.MIN_KUBERNETES_VERSION, response.getResponses().get(0).getSemanticVersion());
     }
 
     @Test(expected = InvalidParameterValueException.class)
@@ -206,13 +214,19 @@
         when(cmd.getMinimumRamSize()).thenReturn(KubernetesClusterService.MIN_KUBERNETES_CLUSTER_NODE_RAM_SIZE);
         Account systemAccount =  new AccountVO("system", 1L, "", Account.Type.ADMIN, "uuid");
         when(accountManager.getSystemAccount()).thenReturn(systemAccount);
-        PowerMockito.mockStatic(ComponentContext.class);
-        when(ComponentContext.inject(Mockito.any(RegisterIsoCmd.class))).thenReturn(new RegisterIsoCmd());
-        when(templateService.registerIso(Mockito.any(RegisterIsoCmd.class))).thenReturn(Mockito.mock(VirtualMachineTemplate.class));
-        VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
-        when(templateVO.getId()).thenReturn(1L);
-        when(templateDao.findById(Mockito.anyLong())).thenReturn(templateVO);
-        kubernetesVersionService.addKubernetesSupportedVersion(cmd);
+        try (MockedStatic<ComponentContext> mockedComponentContext = Mockito.mockStatic(ComponentContext.class)) {
+            mockedComponentContext.when(() -> ComponentContext.inject(Mockito.any(RegisterIsoCmd.class))).thenReturn(
+                    new RegisterIsoCmd());
+
+            when(templateService.registerIso(Mockito.any(RegisterIsoCmd.class))).thenReturn(
+                    Mockito.mock(VirtualMachineTemplate.class));
+            VMTemplateVO templateVO = Mockito.mock(VMTemplateVO.class);
+            when(templateVO.getId()).thenReturn(1L);
+            when(templateDao.findById(Mockito.anyLong())).thenReturn(templateVO);
+            KubernetesSupportedVersionResponse response = kubernetesVersionService.addKubernetesSupportedVersion(cmd);
+            Assert.assertNotNull(response);
+            Mockito.verify(kubernetesSupportedVersionDao, Mockito.times(1)).persist(Mockito.any(KubernetesSupportedVersionVO.class));
+        }
     }
 
     @Test(expected = CloudRuntimeException.class)
@@ -237,12 +251,11 @@
         when(kubernetesSupportedVersionDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(KubernetesSupportedVersionVO.class));
         List<KubernetesClusterVO> clusters = new ArrayList<>();
         when(kubernetesClusterDao.listAllByKubernetesVersion(Mockito.anyLong())).thenReturn(clusters);
-        when(templateDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(VMTemplateVO.class));
-        PowerMockito.mockStatic(ComponentContext.class);
-        when(ComponentContext.inject(Mockito.any(DeleteIsoCmd.class))).thenReturn(new DeleteIsoCmd());
-        when(templateService.deleteIso(Mockito.any(DeleteIsoCmd.class))).thenReturn(true);
-        when(kubernetesClusterDao.remove(Mockito.anyLong())).thenReturn(true);
-        kubernetesVersionService.deleteKubernetesSupportedVersion(cmd);
+        try (MockedStatic<ComponentContext> mockedComponentContext = Mockito.mockStatic(ComponentContext.class)) {
+            mockedComponentContext.when(() -> ComponentContext.inject(Mockito.any(DeleteIsoCmd.class))).thenReturn(new DeleteIsoCmd());
+            kubernetesVersionService.deleteKubernetesSupportedVersion(cmd);
+            Mockito.verify(kubernetesSupportedVersionDao).remove(Mockito.anyLong());
+        }
     }
 
     @Test
@@ -254,11 +267,12 @@
         CallContext.register(user, account);
         when(kubernetesSupportedVersionDao.findById(Mockito.anyLong())).thenReturn(Mockito.mock(KubernetesSupportedVersionVO.class));
         KubernetesSupportedVersionVO version = Mockito.mock(KubernetesSupportedVersionVO.class);
-        when(kubernetesSupportedVersionDao.createForUpdate(Mockito.anyLong())).thenReturn(version);
-        when(kubernetesSupportedVersionDao.update(Mockito.anyLong(), Mockito.any(KubernetesSupportedVersionVO.class))).thenReturn(true);
         when(version.getState()).thenReturn(KubernetesSupportedVersion.State.Disabled);
         when(version.getSemanticVersion()).thenReturn(KubernetesVersionService.MIN_KUBERNETES_VERSION);
         when(kubernetesSupportedVersionDao.findById(Mockito.anyLong())).thenReturn(version);
-        kubernetesVersionService.updateKubernetesSupportedVersion(cmd);
+        KubernetesSupportedVersionResponse response = kubernetesVersionService.updateKubernetesSupportedVersion(cmd);
+        Assert.assertNotNull(response);
+        Assert.assertEquals(KubernetesSupportedVersion.State.Disabled.toString(), response.getState());
+        Assert.assertEquals(KubernetesVersionService.MIN_KUBERNETES_VERSION, response.getSemanticVersion());
     }
 }
diff --git a/plugins/integrations/kubernetes-service/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/plugins/integrations/kubernetes-service/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d4
--- /dev/null
+++ b/plugins/integrations/kubernetes-service/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/plugins/integrations/prometheus/pom.xml b/plugins/integrations/prometheus/pom.xml
index c5552f4..102deca 100644
--- a/plugins/integrations/prometheus/pom.xml
+++ b/plugins/integrations/prometheus/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/integrations/prometheus/src/main/java/org/apache/cloudstack/metrics/PrometheusExporterImpl.java b/plugins/integrations/prometheus/src/main/java/org/apache/cloudstack/metrics/PrometheusExporterImpl.java
index 171df35..7adb60a 100644
--- a/plugins/integrations/prometheus/src/main/java/org/apache/cloudstack/metrics/PrometheusExporterImpl.java
+++ b/plugins/integrations/prometheus/src/main/java/org/apache/cloudstack/metrics/PrometheusExporterImpl.java
@@ -222,9 +222,9 @@
     private String markTagMaps(HostVO host, Map<String, Integer> totalHosts, Map<String, Integer> upHosts, Map<String, Integer> downHosts) {
         List<String> hostTags = _hostTagsDao.getHostTags(host.getId());
         markTags(hostTags,totalHosts);
-        if (host.getStatus() == Status.Up) {
+        if (host.getStatus() == Status.Up && !host.isInMaintenanceStates()) {
             markTags(hostTags, upHosts);
-        } else if (host.getStatus() == Status.Disconnected || host.getStatus() == Status.Down) {
+        } else if (host.getStatus() == Status.Disconnected || host.getStatus() == Status.Down || host.isInMaintenanceStates()) {
             markTags(hostTags, downHosts);
         }
         return StringUtils.join(hostTags, ",");
diff --git a/plugins/metrics/pom.xml b/plugins/metrics/pom.xml
index c1d6b96..a5bfa46 100644
--- a/plugins/metrics/pom.xml
+++ b/plugins/metrics/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/network-elements/bigswitch/pom.xml b/plugins/network-elements/bigswitch/pom.xml
index c5f22df..f0a1e3d 100644
--- a/plugins/network-elements/bigswitch/pom.xml
+++ b/plugins/network-elements/bigswitch/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/network-elements/brocade-vcs/pom.xml b/plugins/network-elements/brocade-vcs/pom.xml
index a9d6903..d71d840 100644
--- a/plugins/network-elements/brocade-vcs/pom.xml
+++ b/plugins/network-elements/brocade-vcs/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <build>
diff --git a/plugins/network-elements/brocade-vcs/src/main/resources/META-INF/cloudstack/vcs/module.properties b/plugins/network-elements/brocade-vcs/src/main/resources/META-INF/cloudstack/vcs/module.properties
index db2c80d..b010fba 100644
--- a/plugins/network-elements/brocade-vcs/src/main/resources/META-INF/cloudstack/vcs/module.properties
+++ b/plugins/network-elements/brocade-vcs/src/main/resources/META-INF/cloudstack/vcs/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=vcs
-parent=network
\ No newline at end of file
+parent=network
diff --git a/plugins/network-elements/cisco-vnmc/pom.xml b/plugins/network-elements/cisco-vnmc/pom.xml
index f759de0..8360811 100644
--- a/plugins/network-elements/cisco-vnmc/pom.xml
+++ b/plugins/network-elements/cisco-vnmc/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/network-elements/cisco-vnmc/src/main/resources/META-INF/cloudstack/cisco-vnmc/module.properties b/plugins/network-elements/cisco-vnmc/src/main/resources/META-INF/cloudstack/cisco-vnmc/module.properties
index 69ffb6f..abaf575 100644
--- a/plugins/network-elements/cisco-vnmc/src/main/resources/META-INF/cloudstack/cisco-vnmc/module.properties
+++ b/plugins/network-elements/cisco-vnmc/src/main/resources/META-INF/cloudstack/cisco-vnmc/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=cisco-vnmc
-parent=network
\ No newline at end of file
+parent=network
diff --git a/plugins/network-elements/cisco-vnmc/src/main/scripts/network/cisco/create-acl-policy.xml b/plugins/network-elements/cisco-vnmc/src/main/scripts/network/cisco/create-acl-policy.xml
index c6f7d37..fc9e805 100755
--- a/plugins/network-elements/cisco-vnmc/src/main/scripts/network/cisco/create-acl-policy.xml
+++ b/plugins/network-elements/cisco-vnmc/src/main/scripts/network/cisco/create-acl-policy.xml
@@ -32,4 +32,4 @@
 <!--
     aclpolicydn="org-root/org-vlan-123/org-VDC-vlan-123/pol-test_policy"
     aclpolicyname="test_policy"
--->
\ No newline at end of file
+-->
diff --git a/plugins/network-elements/cisco-vnmc/src/main/scripts/network/cisco/create-ip-pool.xml b/plugins/network-elements/cisco-vnmc/src/main/scripts/network/cisco/create-ip-pool.xml
index 876fa21..0698c99 100755
--- a/plugins/network-elements/cisco-vnmc/src/main/scripts/network/cisco/create-ip-pool.xml
+++ b/plugins/network-elements/cisco-vnmc/src/main/scripts/network/cisco/create-ip-pool.xml
@@ -55,4 +55,4 @@
     ippooldn="org-root/org-vlan-123/org-VDC-vlan-123/objgrp-ccc"
     ippoolname="ccc"
     ipvalue="10.1.1.20"
--->
\ No newline at end of file
+-->
diff --git a/plugins/network-elements/dns-notifier/pom.xml b/plugins/network-elements/dns-notifier/pom.xml
index 714f4c7..c862a28 100644
--- a/plugins/network-elements/dns-notifier/pom.xml
+++ b/plugins/network-elements/dns-notifier/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <artifactId>cloud-plugin-example-dns-notifier</artifactId>
diff --git a/plugins/network-elements/elastic-loadbalancer/pom.xml b/plugins/network-elements/elastic-loadbalancer/pom.xml
index 8b3cbb4..abb64f0 100644
--- a/plugins/network-elements/elastic-loadbalancer/pom.xml
+++ b/plugins/network-elements/elastic-loadbalancer/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/network-elements/elastic-loadbalancer/src/main/resources/META-INF/cloudstack/elb/module.properties b/plugins/network-elements/elastic-loadbalancer/src/main/resources/META-INF/cloudstack/elb/module.properties
index a8e3b9c..559245d 100644
--- a/plugins/network-elements/elastic-loadbalancer/src/main/resources/META-INF/cloudstack/elb/module.properties
+++ b/plugins/network-elements/elastic-loadbalancer/src/main/resources/META-INF/cloudstack/elb/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=elb
-parent=network
\ No newline at end of file
+parent=network
diff --git a/plugins/network-elements/elastic-loadbalancer/src/test/java/com/cloud/network/lb/ElasticLoadBalancerManagerImplTest.java b/plugins/network-elements/elastic-loadbalancer/src/test/java/com/cloud/network/lb/ElasticLoadBalancerManagerImplTest.java
index 04f59bb..064bb3e 100644
--- a/plugins/network-elements/elastic-loadbalancer/src/test/java/com/cloud/network/lb/ElasticLoadBalancerManagerImplTest.java
+++ b/plugins/network-elements/elastic-loadbalancer/src/test/java/com/cloud/network/lb/ElasticLoadBalancerManagerImplTest.java
@@ -25,14 +25,14 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.agent.api.check.CheckSshAnswer;
 import com.cloud.agent.manager.Commands;
 import com.cloud.network.lb.dao.ElasticLbVmMapDao;
 import com.cloud.vm.ReservationContext;
 import com.cloud.vm.VirtualMachineProfile;
+import org.springframework.test.util.ReflectionTestUtils;
 
 @RunWith(MockitoJUnitRunner.class)
 public class ElasticLoadBalancerManagerImplTest {
@@ -90,7 +90,7 @@
     public void testGarbageCollectUnusedElbVmsWhenVariableUnusedElbVmsIsNull() throws Exception {
         ElasticLbVmMapDao elasticLbVmMapDaoMock = mock(ElasticLbVmMapDao.class);
         when(elasticLbVmMapDaoMock.listUnusedElbVms()).thenReturn(null);
-        Whitebox.setInternalState(elasticLoadBalancerManagerImpl, "_elbVmMapDao", elasticLbVmMapDaoMock);
+        ReflectionTestUtils.setField(elasticLoadBalancerManagerImpl, "_elbVmMapDao", elasticLbVmMapDaoMock);
 
         try {
             elasticLoadBalancerManagerImpl.garbageCollectUnusedElbVms();
diff --git a/plugins/network-elements/elastic-loadbalancer/src/test/java/com/cloud/network/lb/LoadBalanceRuleHandlerTest.java b/plugins/network-elements/elastic-loadbalancer/src/test/java/com/cloud/network/lb/LoadBalanceRuleHandlerTest.java
index cde56c1..18cdab9 100644
--- a/plugins/network-elements/elastic-loadbalancer/src/test/java/com/cloud/network/lb/LoadBalanceRuleHandlerTest.java
+++ b/plugins/network-elements/elastic-loadbalancer/src/test/java/com/cloud/network/lb/LoadBalanceRuleHandlerTest.java
@@ -36,8 +36,6 @@
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.powermock.reflect.Whitebox;
 
 import com.cloud.dc.PodVlanMapVO;
 import com.cloud.dc.dao.PodVlanMapDao;
@@ -47,6 +45,8 @@
 import com.cloud.vm.VirtualMachineManager;
 import com.cloud.vm.VirtualMachineProfile.Param;
 import com.cloud.vm.dao.DomainRouterDao;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 @RunWith(MockitoJUnitRunner.class)
 public class LoadBalanceRuleHandlerTest {
@@ -68,10 +68,10 @@
 
     @Before
     public void setup() {
-        Whitebox.setInternalState(loadBalanceRuleHandler, "_itMgr", virtualMachineManagerMock);
-        Whitebox.setInternalState(loadBalanceRuleHandler, "_routerDao", domainRouterDaoMock);
-        Whitebox.setInternalState(loadBalanceRuleHandler, "_elbVmMapDao", elasticLbVmMapDao);
-        Whitebox.setInternalState(loadBalanceRuleHandler, "_podVlanMapDao", podVlanMapDao);
+        ReflectionTestUtils.setField(loadBalanceRuleHandler, "_itMgr", virtualMachineManagerMock);
+        ReflectionTestUtils.setField(loadBalanceRuleHandler, "_routerDao", domainRouterDaoMock);
+        ReflectionTestUtils.setField(loadBalanceRuleHandler, "_elbVmMapDao", elasticLbVmMapDao);
+        ReflectionTestUtils.setField(loadBalanceRuleHandler, "_podVlanMapDao", podVlanMapDao);
     }
 
     @Test
diff --git a/plugins/network-elements/elastic-loadbalancer/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/plugins/network-elements/elastic-loadbalancer/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d4
--- /dev/null
+++ b/plugins/network-elements/elastic-loadbalancer/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/plugins/network-elements/globodns/pom.xml b/plugins/network-elements/globodns/pom.xml
index 3a14369..6aa8fb9 100644
--- a/plugins/network-elements/globodns/pom.xml
+++ b/plugins/network-elements/globodns/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/network-elements/globodns/src/main/resources/META-INF/cloudstack/globodns/module.properties b/plugins/network-elements/globodns/src/main/resources/META-INF/cloudstack/globodns/module.properties
index 6c74bd2..cd6bc77 100644
--- a/plugins/network-elements/globodns/src/main/resources/META-INF/cloudstack/globodns/module.properties
+++ b/plugins/network-elements/globodns/src/main/resources/META-INF/cloudstack/globodns/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=globodns
-parent=network
\ No newline at end of file
+parent=network
diff --git a/plugins/network-elements/internal-loadbalancer/pom.xml b/plugins/network-elements/internal-loadbalancer/pom.xml
index ae01363..c1e4224 100644
--- a/plugins/network-elements/internal-loadbalancer/pom.xml
+++ b/plugins/network-elements/internal-loadbalancer/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/network-elements/juniper-contrail/pom.xml b/plugins/network-elements/juniper-contrail/pom.xml
index e959418..53eddab 100644
--- a/plugins/network-elements/juniper-contrail/pom.xml
+++ b/plugins/network-elements/juniper-contrail/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <repositories>
diff --git a/plugins/network-elements/juniper-contrail/src/main/resources/META-INF/cloudstack/contrail/module.properties b/plugins/network-elements/juniper-contrail/src/main/resources/META-INF/cloudstack/contrail/module.properties
index ced0f3a..0c3091d 100644
--- a/plugins/network-elements/juniper-contrail/src/main/resources/META-INF/cloudstack/contrail/module.properties
+++ b/plugins/network-elements/juniper-contrail/src/main/resources/META-INF/cloudstack/contrail/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=contrail
-parent=network
\ No newline at end of file
+parent=network
diff --git a/plugins/network-elements/juniper-contrail/src/test/resources/log4j.properties b/plugins/network-elements/juniper-contrail/src/test/resources/log4j.properties
index 8c012b1..27276fc 100644
--- a/plugins/network-elements/juniper-contrail/src/test/resources/log4j.properties
+++ b/plugins/network-elements/juniper-contrail/src/test/resources/log4j.properties
@@ -32,4 +32,3 @@
 #log4j.category.com.cloud.utils.db.Transaction=ALL
 log4j.category.org.apache.cloudstack.network.contrail=ALL
 log4j.category.com.cloud.network=ALL
-
diff --git a/plugins/network-elements/juniper-contrail/src/test/resources/mysql_db_stop.sh b/plugins/network-elements/juniper-contrail/src/test/resources/mysql_db_stop.sh
index 62d70d3..7ac304f 100644
--- a/plugins/network-elements/juniper-contrail/src/test/resources/mysql_db_stop.sh
+++ b/plugins/network-elements/juniper-contrail/src/test/resources/mysql_db_stop.sh
@@ -27,5 +27,3 @@
 rm -rf /tmp/mysql$1
 
 echo "Deleting db directories"
-
-
diff --git a/plugins/network-elements/juniper-contrail/src/test/resources/providerContext.xml b/plugins/network-elements/juniper-contrail/src/test/resources/providerContext.xml
index 704466f..fc7e10b 100644
--- a/plugins/network-elements/juniper-contrail/src/test/resources/providerContext.xml
+++ b/plugins/network-elements/juniper-contrail/src/test/resources/providerContext.xml
@@ -31,4 +31,4 @@
     <import resource="commonContext.xml"/>
     <bean id="ProviderTestConfiguration"
     	class="org.apache.cloudstack.network.contrail.management.ProviderTestConfiguration"/>
-</beans>
\ No newline at end of file
+</beans>
diff --git a/plugins/network-elements/juniper-contrail/src/test/resources/publicNetworkContext.xml b/plugins/network-elements/juniper-contrail/src/test/resources/publicNetworkContext.xml
index d1c5f40..b2c28d2 100644
--- a/plugins/network-elements/juniper-contrail/src/test/resources/publicNetworkContext.xml
+++ b/plugins/network-elements/juniper-contrail/src/test/resources/publicNetworkContext.xml
@@ -23,4 +23,4 @@
     <import resource="commonContext.xml"/>
     <bean id="PublicNetworkTestConfiguration"
     	class="org.apache.cloudstack.network.contrail.management.PublicNetworkTestConfiguration"/>
-</beans>
\ No newline at end of file
+</beans>
diff --git a/plugins/network-elements/netscaler/pom.xml b/plugins/network-elements/netscaler/pom.xml
index 3fcaafb..931e89e 100644
--- a/plugins/network-elements/netscaler/pom.xml
+++ b/plugins/network-elements/netscaler/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/network-elements/netscaler/src/main/resources/META-INF/cloudstack/netscaler/module.properties b/plugins/network-elements/netscaler/src/main/resources/META-INF/cloudstack/netscaler/module.properties
index 2f1b641..8bf4e6a 100644
--- a/plugins/network-elements/netscaler/src/main/resources/META-INF/cloudstack/netscaler/module.properties
+++ b/plugins/network-elements/netscaler/src/main/resources/META-INF/cloudstack/netscaler/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=netscaler
-parent=network
\ No newline at end of file
+parent=network
diff --git a/plugins/network-elements/nicira-nvp/pom.xml b/plugins/network-elements/nicira-nvp/pom.xml
index 770612c..6eecde3 100644
--- a/plugins/network-elements/nicira-nvp/pom.xml
+++ b/plugins/network-elements/nicira-nvp/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/nicira/NiciraRestClient.java b/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/nicira/NiciraRestClient.java
index 73d08a0..a98480b 100644
--- a/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/nicira/NiciraRestClient.java
+++ b/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/nicira/NiciraRestClient.java
@@ -76,7 +76,7 @@
         return execute(request, 0);
     }
 
-    private CloseableHttpResponse execute(final HttpUriRequest request, final int previousStatusCode) throws CloudstackRESTException {
+    CloseableHttpResponse execute(final HttpUriRequest request, final int previousStatusCode) throws CloudstackRESTException {
         if (counter.hasReachedExecutionLimit()) {
             throw new CloudstackRESTException("Reached max executions limit of " + executionLimit);
         }
diff --git a/plugins/network-elements/nicira-nvp/src/main/resources/META-INF/cloudstack/nvp/module.properties b/plugins/network-elements/nicira-nvp/src/main/resources/META-INF/cloudstack/nvp/module.properties
index 5085fce..11bc471 100644
--- a/plugins/network-elements/nicira-nvp/src/main/resources/META-INF/cloudstack/nvp/module.properties
+++ b/plugins/network-elements/nicira-nvp/src/main/resources/META-INF/cloudstack/nvp/module.properties
@@ -18,4 +18,4 @@
 #
 
 name=nvp
-parent=network
\ No newline at end of file
+parent=network
diff --git a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraRestClientTest.java b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraRestClientTest.java
index d23c4dc..75b751c 100644
--- a/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraRestClientTest.java
+++ b/plugins/network-elements/nicira-nvp/src/test/java/com/cloud/network/nicira/NiciraRestClientTest.java
@@ -26,11 +26,11 @@
 import static org.hamcrest.Matchers.notNullValue;
 import static org.hamcrest.Matchers.sameInstance;
 import static org.junit.Assert.fail;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.powermock.api.mockito.PowerMockito.spy;
-import static org.powermock.api.mockito.PowerMockito.verifyPrivate;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -47,18 +47,14 @@
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import com.cloud.utils.rest.CloudstackRESTException;
 import com.cloud.utils.rest.HttpMethods;
 import com.cloud.utils.rest.HttpRequestMatcher;
 import com.cloud.utils.rest.HttpUriRequestBuilder;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(NiciraRestClient.class)
-@PowerMockIgnore({"javax.xml.*", "org.w3c.dom.*", "org.apache.xerces.*", "org.apache.log4j.*"})
+@RunWith(MockitoJUnitRunner.class)
 public class NiciraRestClientTest {
 
     private static final int HTTPS_PORT = 443;
@@ -120,7 +116,7 @@
 
         assertThat(response, notNullValue());
         assertThat(response, sameInstance(mockResponse));
-        verifyPrivate(client).invoke("execute", request, 0);
+        verify(client).execute(request, 0);
     }
 
     @Test
@@ -139,9 +135,9 @@
 
         assertThat(response, notNullValue());
         assertThat(response, sameInstance(mockResponse));
-        verifyPrivate(client).invoke("execute", HttpRequestMatcher.eq(request), eq(0));
-        verifyPrivate(client).invoke("execute", HttpRequestMatcher.eq(loginRequest), eq(401));
-        verifyPrivate(client).invoke("execute", HttpRequestMatcher.eq(request), eq(200));
+        verify(client).execute((HttpUriRequest)HttpRequestMatcher.eq(request), eq(0));
+        verify(client).execute((HttpUriRequest)HttpRequestMatcher.eq(request), eq(200));
+        verify(client).execute((HttpUriRequest)HttpRequestMatcher.eq(loginRequest), eq(401));
     }
 
     @Test
@@ -168,8 +164,8 @@
             fail("Expected CloudstackRESTException exception");
         } catch (final CloudstackRESTException e) {
             assertThat(e.getMessage(), not(isEmptyOrNullString()));
-            verifyPrivate(client).invoke("execute", HttpRequestMatcher.eq(request), eq(0));
-            verifyPrivate(client).invoke("execute", HttpRequestMatcher.eq(loginRequest), eq(401));
+            verify(client).execute((HttpUriRequest)HttpRequestMatcher.eq(request), eq(0));
+            verify(client).execute((HttpUriRequest)HttpRequestMatcher.eq(loginRequest), eq(401));
         }
     }
 
diff --git a/plugins/network-elements/nicira-nvp/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/plugins/network-elements/nicira-nvp/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d4
--- /dev/null
+++ b/plugins/network-elements/nicira-nvp/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/plugins/network-elements/opendaylight/pom.xml b/plugins/network-elements/opendaylight/pom.xml
index fc29d14..24ac605 100644
--- a/plugins/network-elements/opendaylight/pom.xml
+++ b/plugins/network-elements/opendaylight/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <profiles>
diff --git a/plugins/network-elements/opendaylight/src/main/resources/META-INF/cloudstack/opendaylight/spring-opendaylight-context.xml b/plugins/network-elements/opendaylight/src/main/resources/META-INF/cloudstack/opendaylight/spring-opendaylight-context.xml
index 244ded8..4e9c705 100644
--- a/plugins/network-elements/opendaylight/src/main/resources/META-INF/cloudstack/opendaylight/spring-opendaylight-context.xml
+++ b/plugins/network-elements/opendaylight/src/main/resources/META-INF/cloudstack/opendaylight/spring-opendaylight-context.xml
@@ -39,4 +39,3 @@
     <bean id="OpenDaylightControllerMappingDao" class="org.apache.cloudstack.network.opendaylight.dao.OpenDaylightControllerMappingDaoImpl" />
 
 </beans>
-
diff --git a/plugins/network-elements/ovs/pom.xml b/plugins/network-elements/ovs/pom.xml
index f7ab995..5b3b26d 100644
--- a/plugins/network-elements/ovs/pom.xml
+++ b/plugins/network-elements/ovs/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/network-elements/palo-alto/pom.xml b/plugins/network-elements/palo-alto/pom.xml
index 8ecc0a3..d2056c1 100644
--- a/plugins/network-elements/palo-alto/pom.xml
+++ b/plugins/network-elements/palo-alto/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/network-elements/palo-alto/src/main/resources/META-INF/cloudstack/paloalto/module.properties b/plugins/network-elements/palo-alto/src/main/resources/META-INF/cloudstack/paloalto/module.properties
index 960fdba..28ef552 100644
--- a/plugins/network-elements/palo-alto/src/main/resources/META-INF/cloudstack/paloalto/module.properties
+++ b/plugins/network-elements/palo-alto/src/main/resources/META-INF/cloudstack/paloalto/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=paloalto
-parent=network
\ No newline at end of file
+parent=network
diff --git a/plugins/network-elements/palo-alto/src/main/resources/META-INF/cloudstack/paloalto/spring-paloalto-context.xml b/plugins/network-elements/palo-alto/src/main/resources/META-INF/cloudstack/paloalto/spring-paloalto-context.xml
index d812ec0..137d8c9 100644
--- a/plugins/network-elements/palo-alto/src/main/resources/META-INF/cloudstack/paloalto/spring-paloalto-context.xml
+++ b/plugins/network-elements/palo-alto/src/main/resources/META-INF/cloudstack/paloalto/spring-paloalto-context.xml
@@ -30,4 +30,4 @@
     <bean id="PaloAlto" class="com.cloud.network.element.PaloAltoExternalFirewallElement">
         <property name="name" value="PaloAlto" />
     </bean>
-</beans>
\ No newline at end of file
+</beans>
diff --git a/plugins/network-elements/stratosphere-ssp/pom.xml b/plugins/network-elements/stratosphere-ssp/pom.xml
index ac0f856..e7e2c2b 100644
--- a/plugins/network-elements/stratosphere-ssp/pom.xml
+++ b/plugins/network-elements/stratosphere-ssp/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/network-elements/stratosphere-ssp/src/main/resources/META-INF/cloudstack/ssp/module.properties b/plugins/network-elements/stratosphere-ssp/src/main/resources/META-INF/cloudstack/ssp/module.properties
index 5a99e56..b4d6e1d 100644
--- a/plugins/network-elements/stratosphere-ssp/src/main/resources/META-INF/cloudstack/ssp/module.properties
+++ b/plugins/network-elements/stratosphere-ssp/src/main/resources/META-INF/cloudstack/ssp/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=ssp
-parent=network
\ No newline at end of file
+parent=network
diff --git a/plugins/network-elements/tungsten/pom.xml b/plugins/network-elements/tungsten/pom.xml
index d0f37c9..72a2923 100644
--- a/plugins/network-elements/tungsten/pom.xml
+++ b/plugins/network-elements/tungsten/pom.xml
@@ -26,7 +26,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 
@@ -44,4 +44,4 @@
             <version>2.0</version>
         </dependency>
     </dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/module.properties b/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/module.properties
index 72422a4..1e24c76 100644
--- a/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/module.properties
+++ b/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/module.properties
@@ -18,4 +18,4 @@
 #
 
 name=tungsten
-parent=network
\ No newline at end of file
+parent=network
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/AddTungstenFabricNetworkGatewayToLogicalRouterCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/AddTungstenFabricNetworkGatewayToLogicalRouterCmdTest.java
index 3e00748..b0ebb1e 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/AddTungstenFabricNetworkGatewayToLogicalRouterCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/AddTungstenFabricNetworkGatewayToLogicalRouterCmdTest.java
@@ -24,17 +24,21 @@
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.List;
 
+@RunWith(MockitoJUnitRunner.class)
 public class AddTungstenFabricNetworkGatewayToLogicalRouterCmdTest {
 
     @Mock
@@ -42,18 +46,25 @@
 
     AddTungstenFabricNetworkGatewayToLogicalRouterCmd addTungstenFabricNetworkGatewayToLogicalRouterCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         addTungstenFabricNetworkGatewayToLogicalRouterCmd = new AddTungstenFabricNetworkGatewayToLogicalRouterCmd();
         addTungstenFabricNetworkGatewayToLogicalRouterCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(addTungstenFabricNetworkGatewayToLogicalRouterCmd, "zoneId", 1L);
-        Whitebox.setInternalState(addTungstenFabricNetworkGatewayToLogicalRouterCmd, "networkUuid", "005f0dea-0196" +
+        ReflectionTestUtils.setField(addTungstenFabricNetworkGatewayToLogicalRouterCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(addTungstenFabricNetworkGatewayToLogicalRouterCmd, "networkUuid", "005f0dea-0196" +
                 "-11ec-a1ed-b42e99f6e187");
-        Whitebox.setInternalState(addTungstenFabricNetworkGatewayToLogicalRouterCmd, "logicalRouterUuid", "125f0dea" +
+        ReflectionTestUtils.setField(addTungstenFabricNetworkGatewayToLogicalRouterCmd, "logicalRouterUuid", "125f0dea" +
                 "-0196-11ec-a1ed-b42e99f6e187");
     }
 
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
+    }
+
     @Test
     public void executeTest() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException,
             ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/AddTungstenFabricPolicyRuleCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/AddTungstenFabricPolicyRuleCmdTest.java
index 5fb4b25..20898e4 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/AddTungstenFabricPolicyRuleCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/AddTungstenFabricPolicyRuleCmdTest.java
@@ -27,12 +27,15 @@
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class AddTungstenFabricPolicyRuleCmdTest {
 
     @Mock
@@ -40,26 +43,32 @@
 
     AddTungstenFabricPolicyRuleCmd addTungstenFabricPolicyRuleCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         addTungstenFabricPolicyRuleCmd = new AddTungstenFabricPolicyRuleCmd();
         addTungstenFabricPolicyRuleCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "zoneId", 1L);
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "policyUuid", "test");
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "action", "test");
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "direction", "oneway");
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "protocol", "test");
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "srcNetwork", "test");
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "srcIpPrefix", "test");
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "srcIpPrefixLen", 1);
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "srcStartPort", 1);
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "srcEndPort", 1);
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "destNetwork", "test");
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "destIpPrefix", "test");
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "destIpPrefixLen", 1);
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "destStartPort", 1);
-        Whitebox.setInternalState(addTungstenFabricPolicyRuleCmd, "destEndPort", 1);
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "policyUuid", "test");
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "action", "test");
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "direction", "oneway");
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "protocol", "test");
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "srcNetwork", "test");
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "srcIpPrefix", "test");
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "srcIpPrefixLen", 1);
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "srcStartPort", 1);
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "srcEndPort", 1);
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "destNetwork", "test");
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "destIpPrefix", "test");
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "destIpPrefixLen", 1);
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "destStartPort", 1);
+        ReflectionTestUtils.setField(addTungstenFabricPolicyRuleCmd, "destEndPort", 1);
+    }
+
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ApplyTungstenFabricPolicyCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ApplyTungstenFabricPolicyCmdTest.java
index 432aad0..3618869 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ApplyTungstenFabricPolicyCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ApplyTungstenFabricPolicyCmdTest.java
@@ -24,15 +24,19 @@
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.api.response.TungstenFabricPolicyResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class ApplyTungstenFabricPolicyCmdTest {
 
     @Mock
@@ -40,16 +44,23 @@
 
     ApplyTungstenFabricPolicyCmd applyTungstenFabricPolicyCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         applyTungstenFabricPolicyCmd = new ApplyTungstenFabricPolicyCmd();
         applyTungstenFabricPolicyCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(applyTungstenFabricPolicyCmd, "zoneId", 1L);
-        Whitebox.setInternalState(applyTungstenFabricPolicyCmd, "networkUuid", "test");
-        Whitebox.setInternalState(applyTungstenFabricPolicyCmd, "policyUuid", "test");
-        Whitebox.setInternalState(applyTungstenFabricPolicyCmd, "majorSequence", 1);
-        Whitebox.setInternalState(applyTungstenFabricPolicyCmd, "minorSequence", 1);
+        ReflectionTestUtils.setField(applyTungstenFabricPolicyCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(applyTungstenFabricPolicyCmd, "networkUuid", "test");
+        ReflectionTestUtils.setField(applyTungstenFabricPolicyCmd, "policyUuid", "test");
+        ReflectionTestUtils.setField(applyTungstenFabricPolicyCmd, "majorSequence", 1);
+        ReflectionTestUtils.setField(applyTungstenFabricPolicyCmd, "minorSequence", 1);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ApplyTungstenFabricTagCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ApplyTungstenFabricTagCmdTest.java
index 4446356..a42cbdc 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ApplyTungstenFabricTagCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ApplyTungstenFabricTagCmdTest.java
@@ -24,17 +24,21 @@
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.api.response.TungstenFabricTagResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 
+@RunWith(MockitoJUnitRunner.class)
 public class ApplyTungstenFabricTagCmdTest {
 
     @Mock
@@ -42,18 +46,25 @@
 
     ApplyTungstenFabricTagCmd applyTungstenFabricTagCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         applyTungstenFabricTagCmd = new ApplyTungstenFabricTagCmd();
         applyTungstenFabricTagCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(applyTungstenFabricTagCmd, "zoneId", 1L);
-        Whitebox.setInternalState(applyTungstenFabricTagCmd, "networkUuids", Arrays.asList("test"));
-        Whitebox.setInternalState(applyTungstenFabricTagCmd, "vmUuids", Arrays.asList("test"));
-        Whitebox.setInternalState(applyTungstenFabricTagCmd, "nicUuids", Arrays.asList("test"));
-        Whitebox.setInternalState(applyTungstenFabricTagCmd, "policyUuid", "test");
-        Whitebox.setInternalState(applyTungstenFabricTagCmd, "applicationPolicySetUuid", "test");
-        Whitebox.setInternalState(applyTungstenFabricTagCmd, "tagUuid", "test");
+        ReflectionTestUtils.setField(applyTungstenFabricTagCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(applyTungstenFabricTagCmd, "networkUuids", Arrays.asList("test"));
+        ReflectionTestUtils.setField(applyTungstenFabricTagCmd, "vmUuids", Arrays.asList("test"));
+        ReflectionTestUtils.setField(applyTungstenFabricTagCmd, "nicUuids", Arrays.asList("test"));
+        ReflectionTestUtils.setField(applyTungstenFabricTagCmd, "policyUuid", "test");
+        ReflectionTestUtils.setField(applyTungstenFabricTagCmd, "applicationPolicySetUuid", "test");
+        ReflectionTestUtils.setField(applyTungstenFabricTagCmd, "tagUuid", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ConfigTungstenFabricServiceCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ConfigTungstenFabricServiceCmdTest.java
index 057a490..4fea9dd 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ConfigTungstenFabricServiceCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ConfigTungstenFabricServiceCmdTest.java
@@ -28,27 +28,25 @@
 import com.cloud.utils.db.Transaction;
 import com.cloud.utils.db.TransactionCallbackNoReturn;
 import org.apache.cloudstack.api.response.SuccessResponse;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.powermock.api.mockito.PowerMockito.mockStatic;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({Transaction.class, ConfigTungstenFabricServiceCmd.class})
+@RunWith(MockitoJUnitRunner.class)
 public class ConfigTungstenFabricServiceCmdTest {
     @Mock
     EntityManager entityManager;
@@ -65,9 +63,10 @@
 
     ConfigTungstenFabricServiceCmd configTungstenFabricServiceCmd;
 
+    AutoCloseable closeable;
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         configTungstenFabricServiceCmd = new ConfigTungstenFabricServiceCmd();
         configTungstenFabricServiceCmd._entityMgr = entityManager;
         configTungstenFabricServiceCmd.networkModel = networkModel;
@@ -75,8 +74,13 @@
         configTungstenFabricServiceCmd.networkOfferingServiceMapDao = networkOfferingServiceMapDao;
         configTungstenFabricServiceCmd.networkServiceMapDao = networkServiceMapDao;
         configTungstenFabricServiceCmd.physicalNetworkServiceProviderDao = physicalNetworkServiceProviderDao;
-        Whitebox.setInternalState(configTungstenFabricServiceCmd, "zoneId", 1L);
-        Whitebox.setInternalState(configTungstenFabricServiceCmd, "physicalNetworkId", 1L);
+        ReflectionTestUtils.setField(configTungstenFabricServiceCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(configTungstenFabricServiceCmd, "physicalNetworkId", 1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
@@ -86,16 +90,14 @@
         Network managementNetwork = Mockito.mock(Network.class);
         TransactionCallbackNoReturn transactionCallbackNoReturn = Mockito.mock(TransactionCallbackNoReturn.class);
         List<NetworkOfferingVO> systemNetworkOffering = Arrays.asList(Mockito.mock(NetworkOfferingVO.class));
-        mockStatic(Transaction.class);
         Mockito.when(entityManager.findById(ArgumentMatchers.any(), ArgumentMatchers.anyLong())).thenReturn(dataCenter);
         Mockito.when(dataCenter.isSecurityGroupEnabled()).thenReturn(true);
-        Mockito.when(networkModel.getSystemNetworkByZoneAndTrafficType(ArgumentMatchers.anyLong(),
-                ArgumentMatchers.any())).thenReturn(managementNetwork);
-        Mockito.when(networkOfferingDao.listSystemNetworkOfferings()).thenReturn(systemNetworkOffering);
-        PowerMockito.when(Transaction.execute(any(TransactionCallbackNoReturn.class))).thenReturn(transactionCallbackNoReturn);
-        PowerMockito.whenNew(SuccessResponse.class).withAnyArguments().thenReturn(successResponse);
-        configTungstenFabricServiceCmd.execute();
-        Assert.assertEquals(successResponse, configTungstenFabricServiceCmd.getResponseObject());
+        try (MockedStatic<Transaction> transactionMocked = Mockito.mockStatic(Transaction.class)) {
+            transactionMocked.when(() -> Transaction.execute(any(TransactionCallbackNoReturn.class))).thenReturn(transactionCallbackNoReturn);
+            configTungstenFabricServiceCmd.execute();
+            SuccessResponse response = (SuccessResponse) configTungstenFabricServiceCmd.getResponseObject();
+            Assert.assertTrue(response.getSuccess());
+        }
     }
 
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricAddressGroupCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricAddressGroupCmdTest.java
index 2eb497e..79d8dc7 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricAddressGroupCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricAddressGroupCmdTest.java
@@ -24,15 +24,19 @@
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.api.response.TungstenFabricAddressGroupResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class CreateTungstenFabricAddressGroupCmdTest {
 
     @Mock
@@ -40,15 +44,22 @@
 
     CreateTungstenFabricAddressGroupCmd createTungstenFabricAddressGroupCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         createTungstenFabricAddressGroupCmd = new CreateTungstenFabricAddressGroupCmd();
         createTungstenFabricAddressGroupCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(createTungstenFabricAddressGroupCmd, "zoneId", 1L);
-        Whitebox.setInternalState(createTungstenFabricAddressGroupCmd, "name", "test");
-        Whitebox.setInternalState(createTungstenFabricAddressGroupCmd, "ipPrefix", "test");
-        Whitebox.setInternalState(createTungstenFabricAddressGroupCmd, "ipPrefixLen", 1);
+        ReflectionTestUtils.setField(createTungstenFabricAddressGroupCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(createTungstenFabricAddressGroupCmd, "name", "test");
+        ReflectionTestUtils.setField(createTungstenFabricAddressGroupCmd, "ipPrefix", "test");
+        ReflectionTestUtils.setField(createTungstenFabricAddressGroupCmd, "ipPrefixLen", 1);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricApplicationPolicySetCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricApplicationPolicySetCmdTest.java
index 9f1439c..c02ba33 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricApplicationPolicySetCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricApplicationPolicySetCmdTest.java
@@ -24,15 +24,19 @@
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.api.response.TungstenFabricApplicationPolicySetResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class CreateTungstenFabricApplicationPolicySetCmdTest {
 
     @Mock
@@ -40,13 +44,20 @@
 
     CreateTungstenFabricApplicationPolicySetCmd createTungstenFabricApplicationPolicySetCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         createTungstenFabricApplicationPolicySetCmd = new CreateTungstenFabricApplicationPolicySetCmd();
         createTungstenFabricApplicationPolicySetCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(createTungstenFabricApplicationPolicySetCmd, "zoneId", 1L);
-        Whitebox.setInternalState(createTungstenFabricApplicationPolicySetCmd, "name", "test");
+        ReflectionTestUtils.setField(createTungstenFabricApplicationPolicySetCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(createTungstenFabricApplicationPolicySetCmd, "name", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricFirewallPolicyCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricFirewallPolicyCmdTest.java
index 833cec0..7ea11b9 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricFirewallPolicyCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricFirewallPolicyCmdTest.java
@@ -24,15 +24,19 @@
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.api.response.TungstenFabricFirewallPolicyResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class CreateTungstenFabricFirewallPolicyCmdTest {
 
     @Mock
@@ -40,15 +44,22 @@
 
     CreateTungstenFabricFirewallPolicyCmd createTungstenFabricFirewallPolicyCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         createTungstenFabricFirewallPolicyCmd = new CreateTungstenFabricFirewallPolicyCmd();
         createTungstenFabricFirewallPolicyCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(createTungstenFabricFirewallPolicyCmd, "zoneId", 1L);
-        Whitebox.setInternalState(createTungstenFabricFirewallPolicyCmd, "applicationPolicySetUuid", "test");
-        Whitebox.setInternalState(createTungstenFabricFirewallPolicyCmd, "name", "test");
-        Whitebox.setInternalState(createTungstenFabricFirewallPolicyCmd, "sequence", 1);
+        ReflectionTestUtils.setField(createTungstenFabricFirewallPolicyCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(createTungstenFabricFirewallPolicyCmd, "applicationPolicySetUuid", "test");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallPolicyCmd, "name", "test");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallPolicyCmd, "sequence", 1);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricFirewallRuleCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricFirewallRuleCmdTest.java
index 72db94f..3b946fa 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricFirewallRuleCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricFirewallRuleCmdTest.java
@@ -27,12 +27,15 @@
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class CreateTungstenFabricFirewallRuleCmdTest {
 
     @Mock
@@ -40,25 +43,31 @@
 
     CreateTungstenFabricFirewallRuleCmd createTungstenFabricFirewallRuleCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         createTungstenFabricFirewallRuleCmd = new CreateTungstenFabricFirewallRuleCmd();
         createTungstenFabricFirewallRuleCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "zoneId", 1L);
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "firewallPolicyUuid", "test");
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "name", "test");
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "action", "test");
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "serviceGroupUuid", "test");
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "srcTagUuid", "test");
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "srcAddressGroupUuid", "test");
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "srcNetworkUuid", "test");
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "direction", "oneway");
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "destTagUuid", "test");
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "destAddressGroupUuid", "test");
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "destNetworkUuid", "test");
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "tagTypeUuid", "test");
-        Whitebox.setInternalState(createTungstenFabricFirewallRuleCmd, "sequence", 1);
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "firewallPolicyUuid", "test");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "name", "test");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "action", "test");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "serviceGroupUuid", "test");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "srcTagUuid", "test");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "srcAddressGroupUuid", "test");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "srcNetworkUuid", "test");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "direction", "oneway");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "destTagUuid", "test");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "destAddressGroupUuid", "test");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "destNetworkUuid", "test");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "tagTypeUuid", "test");
+        ReflectionTestUtils.setField(createTungstenFabricFirewallRuleCmd, "sequence", 1);
+    }
+
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricLogicalRouterCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricLogicalRouterCmdTest.java
index a6f0b03..39b209f 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricLogicalRouterCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricLogicalRouterCmdTest.java
@@ -24,15 +24,19 @@
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class CreateTungstenFabricLogicalRouterCmdTest {
 
     @Mock
@@ -40,13 +44,20 @@
 
     CreateTungstenFabricLogicalRouterCmd createTungstenFabricLogicalRouterCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         createTungstenFabricLogicalRouterCmd = new CreateTungstenFabricLogicalRouterCmd();
         createTungstenFabricLogicalRouterCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(createTungstenFabricLogicalRouterCmd, "zoneId", 1L);
-        Whitebox.setInternalState(createTungstenFabricLogicalRouterCmd, "name", "test");
+        ReflectionTestUtils.setField(createTungstenFabricLogicalRouterCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(createTungstenFabricLogicalRouterCmd, "name", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricManagementNetworkCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricManagementNetworkCmdTest.java
index 44ffe5d..17774e1 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricManagementNetworkCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricManagementNetworkCmdTest.java
@@ -20,6 +20,7 @@
 import com.cloud.dc.dao.HostPodDao;
 import org.apache.cloudstack.api.response.SuccessResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -28,13 +29,10 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(CreateTungstenFabricManagementNetworkCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class CreateTungstenFabricManagementNetworkCmdTest {
 
     @Mock
@@ -44,24 +42,29 @@
 
     CreateTungstenFabricManagementNetworkCmd createTungstenFabricManagementNetworkCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         createTungstenFabricManagementNetworkCmd = new CreateTungstenFabricManagementNetworkCmd();
         createTungstenFabricManagementNetworkCmd.tungstenService = tungstenService;
         createTungstenFabricManagementNetworkCmd.podDao = podDao;
-        Whitebox.setInternalState(createTungstenFabricManagementNetworkCmd, "podId", 1L);
+        ReflectionTestUtils.setField(createTungstenFabricManagementNetworkCmd, "podId", 1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        SuccessResponse successResponse = Mockito.mock(SuccessResponse.class);
         HostPodVO pod = Mockito.mock(HostPodVO.class);
         Mockito.when(podDao.findById(ArgumentMatchers.anyLong())).thenReturn(pod);
         Mockito.when(tungstenService.createManagementNetwork(ArgumentMatchers.anyLong())).thenReturn(true);
         Mockito.when(tungstenService.addManagementNetworkSubnet(ArgumentMatchers.any())).thenReturn(true);
-        PowerMockito.whenNew(SuccessResponse.class).withAnyArguments().thenReturn(successResponse);
         createTungstenFabricManagementNetworkCmd.execute();
-        Assert.assertEquals(successResponse, createTungstenFabricManagementNetworkCmd.getResponseObject());
+        Assert.assertTrue(((SuccessResponse)createTungstenFabricManagementNetworkCmd.getResponseObject()).getSuccess());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricPolicyCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricPolicyCmdTest.java
index f3e8399..94dc6dc 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricPolicyCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricPolicyCmdTest.java
@@ -24,15 +24,19 @@
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.api.response.TungstenFabricPolicyResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class CreateTungstenFabricPolicyCmdTest {
 
     @Mock
@@ -40,13 +44,20 @@
 
     CreateTungstenFabricPolicyCmd createTungstenFabricPolicyCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         createTungstenFabricPolicyCmd = new CreateTungstenFabricPolicyCmd();
         createTungstenFabricPolicyCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(createTungstenFabricPolicyCmd, "zoneId", 1L);
-        Whitebox.setInternalState(createTungstenFabricPolicyCmd, "name", "test");
+        ReflectionTestUtils.setField(createTungstenFabricPolicyCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(createTungstenFabricPolicyCmd, "name", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricProviderCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricProviderCmdTest.java
index 335c5f0..ef56b73 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricProviderCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricProviderCmdTest.java
@@ -28,12 +28,15 @@
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class CreateTungstenFabricProviderCmdTest {
 
     @Mock
@@ -41,18 +44,24 @@
 
     CreateTungstenFabricProviderCmd createTungstenFabricProviderCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         createTungstenFabricProviderCmd = new CreateTungstenFabricProviderCmd();
-        Whitebox.setInternalState(createTungstenFabricProviderCmd, "tungstenProviderService", tungstenProviderService);
-        Whitebox.setInternalState(createTungstenFabricProviderCmd, "zoneId", 1L);
-        Whitebox.setInternalState(createTungstenFabricProviderCmd, "name", "test");
-        Whitebox.setInternalState(createTungstenFabricProviderCmd, "hostname", "test");
-        Whitebox.setInternalState(createTungstenFabricProviderCmd, "port", "test");
-        Whitebox.setInternalState(createTungstenFabricProviderCmd, "gateway", "test");
-        Whitebox.setInternalState(createTungstenFabricProviderCmd, "vrouterPort", "test");
-        Whitebox.setInternalState(createTungstenFabricProviderCmd, "introspectPort", "test");
+        ReflectionTestUtils.setField(createTungstenFabricProviderCmd, "tungstenProviderService", tungstenProviderService);
+        ReflectionTestUtils.setField(createTungstenFabricProviderCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(createTungstenFabricProviderCmd, "name", "test");
+        ReflectionTestUtils.setField(createTungstenFabricProviderCmd, "hostname", "test");
+        ReflectionTestUtils.setField(createTungstenFabricProviderCmd, "port", "test");
+        ReflectionTestUtils.setField(createTungstenFabricProviderCmd, "gateway", "test");
+        ReflectionTestUtils.setField(createTungstenFabricProviderCmd, "vrouterPort", "test");
+        ReflectionTestUtils.setField(createTungstenFabricProviderCmd, "introspectPort", "test");
+    }
+
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricPublicNetworkCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricPublicNetworkCmdTest.java
index 3a98e61..c626f34 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricPublicNetworkCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricPublicNetworkCmdTest.java
@@ -23,6 +23,7 @@
 import com.cloud.utils.db.SearchCriteria;
 import org.apache.cloudstack.api.response.SuccessResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -31,16 +32,13 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(CreateTungstenFabricPublicNetworkCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class CreateTungstenFabricPublicNetworkCmdTest {
 
     @Mock
@@ -52,19 +50,25 @@
 
     CreateTungstenFabricPublicNetworkCmd createTungstenFabricPublicNetworkCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         createTungstenFabricPublicNetworkCmd = new CreateTungstenFabricPublicNetworkCmd();
         createTungstenFabricPublicNetworkCmd.tungstenService = tungstenService;
         createTungstenFabricPublicNetworkCmd.vlanDao = vlanDao;
         createTungstenFabricPublicNetworkCmd.networkModel = networkModel;
-        Whitebox.setInternalState(createTungstenFabricPublicNetworkCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(createTungstenFabricPublicNetworkCmd, "zoneId", 1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        SuccessResponse successResponse = Mockito.mock(SuccessResponse.class);
         Network publicNetwork = Mockito.mock(Network.class);
         SearchCriteria<VlanVO> sc = Mockito.mock(SearchCriteria.class);
         List<VlanVO> pubVlanVOList = Arrays.asList(Mockito.mock(VlanVO.class));
@@ -75,8 +79,7 @@
 
         Mockito.when(tungstenService.createPublicNetwork(ArgumentMatchers.anyLong())).thenReturn(true);
         Mockito.when(tungstenService.addPublicNetworkSubnet(ArgumentMatchers.any())).thenReturn(true);
-        PowerMockito.whenNew(SuccessResponse.class).withAnyArguments().thenReturn(successResponse);
         createTungstenFabricPublicNetworkCmd.execute();
-        Assert.assertEquals(successResponse, createTungstenFabricPublicNetworkCmd.getResponseObject());
+        Assert.assertTrue(((SuccessResponse) createTungstenFabricPublicNetworkCmd.getResponseObject()).getSuccess());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricServiceGroupCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricServiceGroupCmdTest.java
index d80a6fc..7591c4c 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricServiceGroupCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricServiceGroupCmdTest.java
@@ -24,15 +24,19 @@
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.api.response.TungstenFabricServiceGroupResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class CreateTungstenFabricServiceGroupCmdTest {
 
     @Mock
@@ -40,16 +44,23 @@
 
     CreateTungstenFabricServiceGroupCmd createTungstenFabricServiceGroupCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         createTungstenFabricServiceGroupCmd = new CreateTungstenFabricServiceGroupCmd();
         createTungstenFabricServiceGroupCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(createTungstenFabricServiceGroupCmd, "zoneId", 1L);
-        Whitebox.setInternalState(createTungstenFabricServiceGroupCmd, "name", "test");
-        Whitebox.setInternalState(createTungstenFabricServiceGroupCmd, "protocol", "test");
-        Whitebox.setInternalState(createTungstenFabricServiceGroupCmd, "startPort", 1);
-        Whitebox.setInternalState(createTungstenFabricServiceGroupCmd, "endPort", 1);
+        ReflectionTestUtils.setField(createTungstenFabricServiceGroupCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(createTungstenFabricServiceGroupCmd, "name", "test");
+        ReflectionTestUtils.setField(createTungstenFabricServiceGroupCmd, "protocol", "test");
+        ReflectionTestUtils.setField(createTungstenFabricServiceGroupCmd, "startPort", 1);
+        ReflectionTestUtils.setField(createTungstenFabricServiceGroupCmd, "endPort", 1);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricTagCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricTagCmdTest.java
index 1b953f9..29340d5 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricTagCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricTagCmdTest.java
@@ -24,15 +24,19 @@
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.api.response.TungstenFabricTagResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class CreateTungstenFabricTagCmdTest {
 
     @Mock
@@ -40,14 +44,21 @@
 
     CreateTungstenFabricTagCmd createTungstenFabricTagCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         createTungstenFabricTagCmd = new CreateTungstenFabricTagCmd();
         createTungstenFabricTagCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(createTungstenFabricTagCmd, "zoneId", 1L);
-        Whitebox.setInternalState(createTungstenFabricTagCmd, "tagType", "test");
-        Whitebox.setInternalState(createTungstenFabricTagCmd, "tagValue", "test");
+        ReflectionTestUtils.setField(createTungstenFabricTagCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(createTungstenFabricTagCmd, "tagType", "test");
+        ReflectionTestUtils.setField(createTungstenFabricTagCmd, "tagValue", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricTagTypeCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricTagTypeCmdTest.java
index 81b32f0..2530ec6 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricTagTypeCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenFabricTagTypeCmdTest.java
@@ -24,15 +24,19 @@
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.api.response.TungstenFabricTagTypeResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class CreateTungstenFabricTagTypeCmdTest {
 
     @Mock
@@ -40,13 +44,20 @@
 
     CreateTungstenFabricTagTypeCmd createTungstenFabricTagTypeCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         createTungstenFabricTagTypeCmd = new CreateTungstenFabricTagTypeCmd();
         createTungstenFabricTagTypeCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(createTungstenFabricTagTypeCmd, "zoneId", 1L);
-        Whitebox.setInternalState(createTungstenFabricTagTypeCmd, "name", "test");
+        ReflectionTestUtils.setField(createTungstenFabricTagTypeCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(createTungstenFabricTagTypeCmd, "name", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricAddressGroupCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricAddressGroupCmdTest.java
index 0e617ba..54b0a1a 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricAddressGroupCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricAddressGroupCmdTest.java
@@ -18,6 +18,7 @@
 
 import org.apache.cloudstack.api.response.SuccessResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -26,13 +27,10 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(DeleteTungstenFabricAddressGroupCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class DeleteTungstenFabricAddressGroupCmdTest {
 
     @Mock
@@ -40,13 +38,20 @@
 
     DeleteTungstenFabricAddressGroupCmd deleteTungstenFabricAddressGroupCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         deleteTungstenFabricAddressGroupCmd = new DeleteTungstenFabricAddressGroupCmd();
         deleteTungstenFabricAddressGroupCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(deleteTungstenFabricAddressGroupCmd, "zoneId", 1L);
-        Whitebox.setInternalState(deleteTungstenFabricAddressGroupCmd, "addressGroupUuid", "test");
+        ReflectionTestUtils.setField(deleteTungstenFabricAddressGroupCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(deleteTungstenFabricAddressGroupCmd, "addressGroupUuid", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
@@ -54,8 +59,7 @@
         SuccessResponse successResponse = Mockito.mock(SuccessResponse.class);
         Mockito.when(tungstenService.deleteTungstenAddressGroup(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(true);
-        PowerMockito.whenNew(SuccessResponse.class).withAnyArguments().thenReturn(successResponse);
         deleteTungstenFabricAddressGroupCmd.execute();
-        Assert.assertEquals(successResponse, deleteTungstenFabricAddressGroupCmd.getResponseObject());
+        Assert.assertTrue(((SuccessResponse) deleteTungstenFabricAddressGroupCmd.getResponseObject()).getSuccess());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricApplicationPolicySetCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricApplicationPolicySetCmdTest.java
index 0ff22ae..8ea3c09 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricApplicationPolicySetCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricApplicationPolicySetCmdTest.java
@@ -18,6 +18,7 @@
 
 import org.apache.cloudstack.api.response.SuccessResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -26,13 +27,10 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(DeleteTungstenFabricApplicationPolicySetCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class DeleteTungstenFabricApplicationPolicySetCmdTest {
 
     @Mock
@@ -40,22 +38,27 @@
 
     DeleteTungstenFabricApplicationPolicySetCmd deleteTungstenFabricApplicationPolicySetCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         deleteTungstenFabricApplicationPolicySetCmd = new DeleteTungstenFabricApplicationPolicySetCmd();
         deleteTungstenFabricApplicationPolicySetCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(deleteTungstenFabricApplicationPolicySetCmd, "zoneId", 1L);
-        Whitebox.setInternalState(deleteTungstenFabricApplicationPolicySetCmd, "applicationPolicySetUuid", "test");
+        ReflectionTestUtils.setField(deleteTungstenFabricApplicationPolicySetCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(deleteTungstenFabricApplicationPolicySetCmd, "applicationPolicySetUuid", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        SuccessResponse successResponse = Mockito.mock(SuccessResponse.class);
         Mockito.when(tungstenService.deleteTungstenApplicationPolicySet(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(true);
-        PowerMockito.whenNew(SuccessResponse.class).withAnyArguments().thenReturn(successResponse);
         deleteTungstenFabricApplicationPolicySetCmd.execute();
-        Assert.assertEquals(successResponse, deleteTungstenFabricApplicationPolicySetCmd.getResponseObject());
+        Assert.assertTrue(((SuccessResponse) deleteTungstenFabricApplicationPolicySetCmd.getResponseObject()).getSuccess());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricFirewallPolicyCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricFirewallPolicyCmdTest.java
index 4b3ce89..e5a23f1 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricFirewallPolicyCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricFirewallPolicyCmdTest.java
@@ -18,6 +18,7 @@
 
 import org.apache.cloudstack.api.response.SuccessResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -26,13 +27,10 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(DeleteTungstenFabricFirewallPolicyCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class DeleteTungstenFabricFirewallPolicyCmdTest {
 
     @Mock
@@ -40,22 +38,27 @@
 
     DeleteTungstenFabricFirewallPolicyCmd deleteTungstenFabricFirewallPolicyCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         deleteTungstenFabricFirewallPolicyCmd = new DeleteTungstenFabricFirewallPolicyCmd();
         deleteTungstenFabricFirewallPolicyCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(deleteTungstenFabricFirewallPolicyCmd, "zoneId", 1L);
-        Whitebox.setInternalState(deleteTungstenFabricFirewallPolicyCmd, "firewallPolicyUuid", "test");
+        ReflectionTestUtils.setField(deleteTungstenFabricFirewallPolicyCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(deleteTungstenFabricFirewallPolicyCmd, "firewallPolicyUuid", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        SuccessResponse successResponse = Mockito.mock(SuccessResponse.class);
         Mockito.when(tungstenService.deleteTungstenFirewallPolicy(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(true);
-        PowerMockito.whenNew(SuccessResponse.class).withAnyArguments().thenReturn(successResponse);
         deleteTungstenFabricFirewallPolicyCmd.execute();
-        Assert.assertEquals(successResponse, deleteTungstenFabricFirewallPolicyCmd.getResponseObject());
+        Assert.assertTrue(((SuccessResponse) deleteTungstenFabricFirewallPolicyCmd.getResponseObject()).getSuccess());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricFirewallRuleCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricFirewallRuleCmdTest.java
index 612a0e9..fea20ce 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricFirewallRuleCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricFirewallRuleCmdTest.java
@@ -18,6 +18,7 @@
 
 import org.apache.cloudstack.api.response.SuccessResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -26,13 +27,10 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(DeleteTungstenFabricFirewallRuleCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class DeleteTungstenFabricFirewallRuleCmdTest {
 
     @Mock
@@ -40,22 +38,27 @@
 
     DeleteTungstenFabricFirewallRuleCmd deleteTungstenFabricFirewallRuleCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         deleteTungstenFabricFirewallRuleCmd = new DeleteTungstenFabricFirewallRuleCmd();
         deleteTungstenFabricFirewallRuleCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(deleteTungstenFabricFirewallRuleCmd, "zoneId", 1L);
-        Whitebox.setInternalState(deleteTungstenFabricFirewallRuleCmd, "firewallRuleUuid", "test");
+        ReflectionTestUtils.setField(deleteTungstenFabricFirewallRuleCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(deleteTungstenFabricFirewallRuleCmd, "firewallRuleUuid", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        SuccessResponse successResponse = Mockito.mock(SuccessResponse.class);
         Mockito.when(tungstenService.deleteTungstenFirewallRule(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(true);
-        PowerMockito.whenNew(SuccessResponse.class).withAnyArguments().thenReturn(successResponse);
         deleteTungstenFabricFirewallRuleCmd.execute();
-        Assert.assertEquals(successResponse, deleteTungstenFabricFirewallRuleCmd.getResponseObject());
+        Assert.assertTrue(((SuccessResponse) deleteTungstenFabricFirewallRuleCmd.getResponseObject()).getSuccess());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricLogicalRouterCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricLogicalRouterCmdTest.java
index 710fea9..469fe2f 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricLogicalRouterCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricLogicalRouterCmdTest.java
@@ -18,6 +18,7 @@
 
 import org.apache.cloudstack.api.response.SuccessResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -26,16 +27,13 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.ArrayList;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(DeleteTungstenFabricLogicalRouterCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class DeleteTungstenFabricLogicalRouterCmdTest {
 
     @Mock
@@ -43,25 +41,30 @@
 
     DeleteTungstenFabricLogicalRouterCmd deleteTungstenFabricLogicalRouterCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         deleteTungstenFabricLogicalRouterCmd = new DeleteTungstenFabricLogicalRouterCmd();
         deleteTungstenFabricLogicalRouterCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(deleteTungstenFabricLogicalRouterCmd, "zoneId", 1L);
-        Whitebox.setInternalState(deleteTungstenFabricLogicalRouterCmd, "logicalRouterUuid", "test");
+        ReflectionTestUtils.setField(deleteTungstenFabricLogicalRouterCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(deleteTungstenFabricLogicalRouterCmd, "logicalRouterUuid", "test");
+    }
+
+    @After
+    public void close() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        SuccessResponse successResponse = Mockito.mock(SuccessResponse.class);
         List<String> networkList = new ArrayList<>();
         Mockito.when(tungstenService.listConnectedNetworkFromLogicalRouter(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(networkList);
         Mockito.when(tungstenService.deleteLogicalRouter(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(true);
-        PowerMockito.whenNew(SuccessResponse.class).withAnyArguments().thenReturn(successResponse);
         deleteTungstenFabricLogicalRouterCmd.execute();
-        Assert.assertEquals(successResponse, deleteTungstenFabricLogicalRouterCmd.getResponseObject());
+        Assert.assertTrue(((SuccessResponse) deleteTungstenFabricLogicalRouterCmd.getResponseObject()).getSuccess());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricPolicyCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricPolicyCmdTest.java
index 7f421dd..bce24ec 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricPolicyCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricPolicyCmdTest.java
@@ -18,6 +18,7 @@
 
 import org.apache.cloudstack.api.response.SuccessResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -26,13 +27,10 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(DeleteTungstenFabricPolicyCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class DeleteTungstenFabricPolicyCmdTest {
 
     @Mock
@@ -40,22 +38,27 @@
 
     DeleteTungstenFabricPolicyCmd deleteTungstenFabricPolicyCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         deleteTungstenFabricPolicyCmd = new DeleteTungstenFabricPolicyCmd();
         deleteTungstenFabricPolicyCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(deleteTungstenFabricPolicyCmd, "zoneId", 1L);
-        Whitebox.setInternalState(deleteTungstenFabricPolicyCmd, "policyUuid", "test");
+        ReflectionTestUtils.setField(deleteTungstenFabricPolicyCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(deleteTungstenFabricPolicyCmd, "policyUuid", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        SuccessResponse successResponse = Mockito.mock(SuccessResponse.class);
         Mockito.when(tungstenService.deleteTungstenPolicy(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(true);
-        PowerMockito.whenNew(SuccessResponse.class).withAnyArguments().thenReturn(successResponse);
         deleteTungstenFabricPolicyCmd.execute();
-        Assert.assertEquals(successResponse, deleteTungstenFabricPolicyCmd.getResponseObject());
+        Assert.assertTrue(((SuccessResponse) deleteTungstenFabricPolicyCmd.getResponseObject()).getSuccess());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricServiceGroupCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricServiceGroupCmdTest.java
index 2e32ced..08314be 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricServiceGroupCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricServiceGroupCmdTest.java
@@ -18,6 +18,7 @@
 
 import org.apache.cloudstack.api.response.SuccessResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -26,13 +27,10 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(DeleteTungstenFabricServiceGroupCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class DeleteTungstenFabricServiceGroupCmdTest {
 
     @Mock
@@ -40,22 +38,27 @@
 
     DeleteTungstenFabricServiceGroupCmd deleteTungstenFabricServiceGroupCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         deleteTungstenFabricServiceGroupCmd = new DeleteTungstenFabricServiceGroupCmd();
         deleteTungstenFabricServiceGroupCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(deleteTungstenFabricServiceGroupCmd, "zoneId", 1L);
-        Whitebox.setInternalState(deleteTungstenFabricServiceGroupCmd, "serviceGroupUuid", "test");
+        ReflectionTestUtils.setField(deleteTungstenFabricServiceGroupCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(deleteTungstenFabricServiceGroupCmd, "serviceGroupUuid", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        SuccessResponse successResponse = Mockito.mock(SuccessResponse.class);
         Mockito.when(tungstenService.deleteTungstenServiceGroup(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(true);
-        PowerMockito.whenNew(SuccessResponse.class).withAnyArguments().thenReturn(successResponse);
         deleteTungstenFabricServiceGroupCmd.execute();
-        Assert.assertEquals(successResponse, deleteTungstenFabricServiceGroupCmd.getResponseObject());
+        Assert.assertTrue(((SuccessResponse) deleteTungstenFabricServiceGroupCmd.getResponseObject()).getSuccess());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricTagCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricTagCmdTest.java
index 0bf3b09..c572fa1 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricTagCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricTagCmdTest.java
@@ -26,13 +26,10 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(DeleteTungstenFabricTagCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class DeleteTungstenFabricTagCmdTest {
 
     @Mock
@@ -40,22 +37,25 @@
 
     DeleteTungstenFabricTagCmd deleteTungstenFabricTagCmd;
 
+    AutoCloseable closeable;
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         deleteTungstenFabricTagCmd = new DeleteTungstenFabricTagCmd();
         deleteTungstenFabricTagCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(deleteTungstenFabricTagCmd, "zoneId", 1L);
-        Whitebox.setInternalState(deleteTungstenFabricTagCmd, "tagUuid", "test");
+        ReflectionTestUtils.setField(deleteTungstenFabricTagCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(deleteTungstenFabricTagCmd, "tagUuid", "test");
+    }
+
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        SuccessResponse successResponse = Mockito.mock(SuccessResponse.class);
         Mockito.when(tungstenService.deleteTungstenTag(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(true);
-        PowerMockito.whenNew(SuccessResponse.class).withAnyArguments().thenReturn(successResponse);
         deleteTungstenFabricTagCmd.execute();
-        Assert.assertEquals(successResponse, deleteTungstenFabricTagCmd.getResponseObject());
+        Assert.assertEquals(true, ((SuccessResponse) deleteTungstenFabricTagCmd.getResponseObject()).getSuccess());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricTagTypeCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricTagTypeCmdTest.java
index 3a78370..81393af 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricTagTypeCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenFabricTagTypeCmdTest.java
@@ -18,6 +18,7 @@
 
 import org.apache.cloudstack.api.response.SuccessResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -26,13 +27,10 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(DeleteTungstenFabricTagTypeCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class DeleteTungstenFabricTagTypeCmdTest {
 
     @Mock
@@ -40,13 +38,20 @@
 
     DeleteTungstenFabricTagTypeCmd deleteTungstenFabricTagTypeCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         deleteTungstenFabricTagTypeCmd = new DeleteTungstenFabricTagTypeCmd();
         deleteTungstenFabricTagTypeCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(deleteTungstenFabricTagTypeCmd, "zoneId", 1L);
-        Whitebox.setInternalState(deleteTungstenFabricTagTypeCmd, "tagTypeUuid", "test");
+        ReflectionTestUtils.setField(deleteTungstenFabricTagTypeCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(deleteTungstenFabricTagTypeCmd, "tagTypeUuid", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
@@ -54,8 +59,7 @@
         SuccessResponse successResponse = Mockito.mock(SuccessResponse.class);
         Mockito.when(tungstenService.deleteTungstenTagType(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(true);
-        PowerMockito.whenNew(SuccessResponse.class).withAnyArguments().thenReturn(successResponse);
         deleteTungstenFabricTagTypeCmd.execute();
-        Assert.assertEquals(successResponse, deleteTungstenFabricTagTypeCmd.getResponseObject());
+        Assert.assertTrue(((SuccessResponse)deleteTungstenFabricTagTypeCmd.getResponseObject()).getSuccess());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/GetLoadBalancerSslCertificateCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/GetLoadBalancerSslCertificateCmdTest.java
index dcf0737..6130779 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/GetLoadBalancerSslCertificateCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/GetLoadBalancerSslCertificateCmdTest.java
@@ -19,6 +19,8 @@
 import com.cloud.network.lb.LoadBalancingRule;
 import com.cloud.network.lb.LoadBalancingRulesManager;
 import org.apache.cloudstack.network.tungsten.api.response.TlsDataResponse;
+import org.apache.commons.codec.binary.Base64;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -27,13 +29,10 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(GetLoadBalancerSslCertificateCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class GetLoadBalancerSslCertificateCmdTest {
 
     @Mock
@@ -41,24 +40,34 @@
 
     GetLoadBalancerSslCertificateCmd getLoadBalancerSslCertificateCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         getLoadBalancerSslCertificateCmd = new GetLoadBalancerSslCertificateCmd();
-        Whitebox.setInternalState(getLoadBalancerSslCertificateCmd, "lbMgr", loadBalancingRulesManager);
-        Whitebox.setInternalState(getLoadBalancerSslCertificateCmd, "id", 1L);
+        ReflectionTestUtils.setField(getLoadBalancerSslCertificateCmd, "lbMgr", loadBalancingRulesManager);
+        ReflectionTestUtils.setField(getLoadBalancerSslCertificateCmd, "id", 1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
         LoadBalancingRule.LbSslCert lbSslCert = Mockito.mock(LoadBalancingRule.LbSslCert.class);
-        TlsDataResponse tlsDataResponse = Mockito.mock(TlsDataResponse.class);
-        Mockito.when(lbSslCert.getCert()).thenReturn("test");
-        Mockito.when(lbSslCert.getKey()).thenReturn("test");
-        Mockito.when(lbSslCert.getChain()).thenReturn("test");
+        Mockito.when(lbSslCert.getCert()).thenReturn("testCrt");
+        Mockito.when(lbSslCert.getKey()).thenReturn("testKey");
+        Mockito.when(lbSslCert.getChain()).thenReturn("testChain");
         Mockito.when(loadBalancingRulesManager.getLbSslCert(ArgumentMatchers.anyLong())).thenReturn(lbSslCert);
-        PowerMockito.whenNew(TlsDataResponse.class).withAnyArguments().thenReturn(tlsDataResponse);
         getLoadBalancerSslCertificateCmd.execute();
-        Assert.assertEquals(tlsDataResponse, getLoadBalancerSslCertificateCmd.getResponseObject());
+        TlsDataResponse response = (TlsDataResponse) getLoadBalancerSslCertificateCmd.getResponseObject();
+
+        Assert.assertEquals(Base64.encodeBase64String("testCrt".getBytes()), response.getCrt());
+        Assert.assertEquals(Base64.encodeBase64String("testChain".getBytes()), response.getChain());
+        Assert.assertEquals(Base64.encodeBase64String("testKey".getBytes()), response.getKey());
+
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricAddressGroupCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricAddressGroupCmdTest.java
index f741580..775a7bb 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricAddressGroupCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricAddressGroupCmdTest.java
@@ -16,11 +16,11 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -29,64 +29,62 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricAddressGroupCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricAddressGroupCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
     ListTungstenFabricAddressGroupCmd listTungstenFabricAddressGroupCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricAddressGroupCmd = new ListTungstenFabricAddressGroupCmd();
         listTungstenFabricAddressGroupCmd.tungstenService = tungstenService;
-        listTungstenFabricAddressGroupCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricAddressGroupCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricAddressGroupCmd, "addressGroupUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricAddressGroupCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricAddressGroupCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricAddressGroupCmd, "addressGroupUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricAddressGroupCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricAddressGroupCmd, "pageSize", 10);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        Whitebox.setInternalState(listTungstenFabricAddressGroupCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricAddressGroupCmd, "zoneId", 1L);
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenService.listTungstenAddressGroup(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricAddressGroupCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricAddressGroupCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricAddressGroupCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 
     @Test
     public void executeAllZoneTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         TungstenProviderVO tungstenProviderVO = Mockito.mock(TungstenProviderVO.class);
         List<TungstenProviderVO> tungstenProviderVOList = Arrays.asList(tungstenProviderVO);
         Mockito.when(tungstenService.getTungstenProviders()).thenReturn(tungstenProviderVOList);
         Mockito.when(tungstenService.listTungstenAddressGroup(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricAddressGroupCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricAddressGroupCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricAddressGroupCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricApplictionPolicySetCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricApplicationPolicySetCmdTest.java
similarity index 62%
rename from plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricApplictionPolicySetCmdTest.java
rename to plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricApplicationPolicySetCmdTest.java
index eff717d..8d7fddb 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricApplictionPolicySetCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricApplicationPolicySetCmdTest.java
@@ -16,11 +16,11 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -29,65 +29,63 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricApplictionPolicySetCmd.class)
-public class ListTungstenFabricApplictionPolicySetCmdTest {
+@RunWith(MockitoJUnitRunner.class)
+public class ListTungstenFabricApplicationPolicySetCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
     ListTungstenFabricApplictionPolicySetCmd listTungstenFabricApplictionPolicySetCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricApplictionPolicySetCmd = new ListTungstenFabricApplictionPolicySetCmd();
         listTungstenFabricApplictionPolicySetCmd.tungstenService = tungstenService;
-        listTungstenFabricApplictionPolicySetCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricApplictionPolicySetCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricApplictionPolicySetCmd, "zoneId", 1L);
-        Whitebox.setInternalState(listTungstenFabricApplictionPolicySetCmd, "applicationPolicySetUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricApplictionPolicySetCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricApplictionPolicySetCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricApplictionPolicySetCmd, "applicationPolicySetUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricApplictionPolicySetCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricApplictionPolicySetCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricApplictionPolicySetCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        Whitebox.setInternalState(listTungstenFabricApplictionPolicySetCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricApplictionPolicySetCmd, "zoneId", 1L);
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenService.listTungstenApplicationPolicySet(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricApplictionPolicySetCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricApplictionPolicySetCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricApplictionPolicySetCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 
     @Test
     public void executeAllZoneTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         TungstenProviderVO tungstenProviderVO = Mockito.mock(TungstenProviderVO.class);
         List<TungstenProviderVO> tungstenProviderVOList = Arrays.asList(tungstenProviderVO);
         Mockito.when(tungstenService.getTungstenProviders()).thenReturn(tungstenProviderVOList);
         Mockito.when(tungstenService.listTungstenApplicationPolicySet(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricApplictionPolicySetCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricApplictionPolicySetCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricApplictionPolicySetCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricFirewallPolicyCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricFirewallPolicyCmdTest.java
index ed3b68e..9764a54 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricFirewallPolicyCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricFirewallPolicyCmdTest.java
@@ -16,11 +16,11 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -29,65 +29,64 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricFirewallPolicyCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricFirewallPolicyCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
     ListTungstenFabricFirewallPolicyCmd listTungstenFabricFirewallPolicyCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricFirewallPolicyCmd = new ListTungstenFabricFirewallPolicyCmd();
         listTungstenFabricFirewallPolicyCmd.tungstenService = tungstenService;
-        listTungstenFabricFirewallPolicyCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricFirewallPolicyCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricFirewallPolicyCmd, "applicationPolicySetUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricFirewallPolicyCmd, "firewallPolicyUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricFirewallPolicyCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricFirewallPolicyCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricFirewallPolicyCmd, "applicationPolicySetUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricFirewallPolicyCmd, "firewallPolicyUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricFirewallPolicyCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricFirewallPolicyCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricFirewallPolicyCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        Whitebox.setInternalState(listTungstenFabricFirewallPolicyCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricFirewallPolicyCmd, "zoneId", 1L);
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenService.listTungstenFirewallPolicy(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString(), ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricFirewallPolicyCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricFirewallPolicyCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricFirewallPolicyCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 
     @Test
     public void executeAllZoneTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         TungstenProviderVO tungstenProviderVO = Mockito.mock(TungstenProviderVO.class);
         List<TungstenProviderVO> tungstenProviderVOList = Arrays.asList(tungstenProviderVO);
         Mockito.when(tungstenService.getTungstenProviders()).thenReturn(tungstenProviderVOList);
         Mockito.when(tungstenService.listTungstenFirewallPolicy(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString(), ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricFirewallPolicyCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricFirewallPolicyCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricFirewallPolicyCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricFirewallRuleCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricFirewallRuleCmdTest.java
index f267478..12fca75 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricFirewallRuleCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricFirewallRuleCmdTest.java
@@ -16,11 +16,11 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -29,65 +29,64 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricFirewallRuleCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricFirewallRuleCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
     ListTungstenFabricFirewallRuleCmd listTungstenFabricFirewallRuleCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricFirewallRuleCmd = new ListTungstenFabricFirewallRuleCmd();
         listTungstenFabricFirewallRuleCmd.tungstenService = tungstenService;
-        listTungstenFabricFirewallRuleCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricFirewallRuleCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricFirewallRuleCmd, "firewallPolicyUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricFirewallRuleCmd, "firewallRuleUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricFirewallRuleCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricFirewallRuleCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricFirewallRuleCmd, "firewallPolicyUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricFirewallRuleCmd, "firewallRuleUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricFirewallRuleCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricFirewallRuleCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricFirewallRuleCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        Whitebox.setInternalState(listTungstenFabricFirewallRuleCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricFirewallRuleCmd, "zoneId", 1L);
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenService.listTungstenFirewallRule(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString(), ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricFirewallRuleCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricFirewallRuleCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricFirewallRuleCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 
     @Test
     public void executeAllZoneTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         TungstenProviderVO tungstenProviderVO = Mockito.mock(TungstenProviderVO.class);
         List<TungstenProviderVO> tungstenProviderVOList = Arrays.asList(tungstenProviderVO);
         Mockito.when(tungstenService.getTungstenProviders()).thenReturn(tungstenProviderVOList);
         Mockito.when(tungstenService.listTungstenFirewallRule(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString(), ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricFirewallRuleCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricFirewallRuleCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricFirewallRuleCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricLBHealthMonitorCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricLBHealthMonitorCmdTest.java
index c9df935..c2ee9a9 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricLBHealthMonitorCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricLBHealthMonitorCmdTest.java
@@ -16,10 +16,10 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -28,47 +28,46 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricLBHealthMonitorCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricLBHealthMonitorCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
     ListTungstenFabricLBHealthMonitorCmd listTungstenFabricLBHealthMonitorCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricLBHealthMonitorCmd = new ListTungstenFabricLBHealthMonitorCmd();
         listTungstenFabricLBHealthMonitorCmd.tungstenService = tungstenService;
-        listTungstenFabricLBHealthMonitorCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricLBHealthMonitorCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricLBHealthMonitorCmd, "lbID", 1L);
-        Whitebox.setInternalState(listTungstenFabricLBHealthMonitorCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricLBHealthMonitorCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricLBHealthMonitorCmd, "lbID", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricLBHealthMonitorCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricLBHealthMonitorCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricLBHealthMonitorCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenService.listTungstenFabricLBHealthMonitor(ArgumentMatchers.anyLong())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricLBHealthMonitorCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricLBHealthMonitorCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricLBHealthMonitorCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricLogicalRouterCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricLogicalRouterCmdTest.java
index 34879d2..72cc0dd 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricLogicalRouterCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricLogicalRouterCmdTest.java
@@ -16,11 +16,11 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -29,65 +29,64 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricLogicalRouterCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricLogicalRouterCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
     ListTungstenFabricLogicalRouterCmd listTungstenFabricLogicalRouterCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricLogicalRouterCmd = new ListTungstenFabricLogicalRouterCmd();
         listTungstenFabricLogicalRouterCmd.tungstenService = tungstenService;
-        listTungstenFabricLogicalRouterCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricLogicalRouterCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricLogicalRouterCmd, "networkUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricLogicalRouterCmd, "logicalRouterUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricLogicalRouterCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricLogicalRouterCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricLogicalRouterCmd, "networkUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricLogicalRouterCmd, "logicalRouterUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricLogicalRouterCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricLogicalRouterCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricLogicalRouterCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        Whitebox.setInternalState(listTungstenFabricLogicalRouterCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricLogicalRouterCmd, "zoneId", 1L);
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenService.listRoutingLogicalRouter(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString(), ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricLogicalRouterCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricLogicalRouterCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricLogicalRouterCmd.getResponseObject();
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
     }
 
     @Test
     public void executeAllZoneTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         TungstenProviderVO tungstenProviderVO = Mockito.mock(TungstenProviderVO.class);
         List<TungstenProviderVO> tungstenProviderVOList = Arrays.asList(tungstenProviderVO);
         Mockito.when(tungstenService.getTungstenProviders()).thenReturn(tungstenProviderVOList);
         Mockito.when(tungstenService.listRoutingLogicalRouter(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString(), ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricLogicalRouterCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricLogicalRouterCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricLogicalRouterCmd.getResponseObject();
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricNetworkCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricNetworkCmdTest.java
index dbb3b60..a8eebe8 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricNetworkCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricNetworkCmdTest.java
@@ -16,11 +16,11 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -29,66 +29,67 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricNetworkCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricNetworkCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
     ListTungstenFabricNetworkCmd listTungstenFabricNetworkCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricNetworkCmd = new ListTungstenFabricNetworkCmd();
         listTungstenFabricNetworkCmd.tungstenService = tungstenService;
-        listTungstenFabricNetworkCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricNetworkCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricNetworkCmd, "networkUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricNetworkCmd, "listAll", true);
-        Whitebox.setInternalState(listTungstenFabricNetworkCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricNetworkCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricNetworkCmd, "networkUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricNetworkCmd, "listAll", true);
+        ReflectionTestUtils.setField(listTungstenFabricNetworkCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricNetworkCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricNetworkCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        Whitebox.setInternalState(listTungstenFabricNetworkCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricNetworkCmd, "zoneId", 1L);
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
+
         Mockito.when(tungstenService.listTungstenNetwork(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString(), ArgumentMatchers.anyBoolean())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(BaseResponse.class).withAnyArguments().thenReturn(baseResponse);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
+
         listTungstenFabricNetworkCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricNetworkCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricNetworkCmd.getResponseObject();
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
     }
 
     @Test
     public void executeAllZoneTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         TungstenProviderVO tungstenProviderVO = Mockito.mock(TungstenProviderVO.class);
         List<TungstenProviderVO> tungstenProviderVOList = Arrays.asList(tungstenProviderVO);
         Mockito.when(tungstenService.getTungstenProviders()).thenReturn(tungstenProviderVOList);
         Mockito.when(tungstenService.listTungstenNetwork(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString(), ArgumentMatchers.anyBoolean())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricNetworkCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricNetworkCmd.getResponseObject());
+
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricNetworkCmd.getResponseObject();
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricNicCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricNicCmdTest.java
index 8f43c25..64bc950 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricNicCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricNicCmdTest.java
@@ -16,77 +16,78 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
+import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricNicCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricNicCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
+    @InjectMocks
     ListTungstenFabricNicCmd listTungstenFabricNicCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricNicCmd = new ListTungstenFabricNicCmd();
         listTungstenFabricNicCmd.tungstenService = tungstenService;
-        listTungstenFabricNicCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricNicCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricNicCmd, "nicUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricNicCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricNicCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricNicCmd, "nicUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricNicCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricNicCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricNicCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        Whitebox.setInternalState(listTungstenFabricNicCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricNicCmd, "zoneId", 1L);
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenService.listTungstenNic(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricNicCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricNicCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricNicCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 
     @Test
     public void executeAllZoneTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         TungstenProviderVO tungstenProviderVO = Mockito.mock(TungstenProviderVO.class);
         List<TungstenProviderVO> tungstenProviderVOList = Arrays.asList(tungstenProviderVO);
         Mockito.when(tungstenService.getTungstenProviders()).thenReturn(tungstenProviderVOList);
         Mockito.when(tungstenService.listTungstenNic(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricNicCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricNicCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricNicCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricPolicyCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricPolicyCmdTest.java
index eddb6b9..b7348d1 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricPolicyCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricPolicyCmdTest.java
@@ -16,11 +16,11 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -29,61 +29,58 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricPolicyCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricPolicyCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
     ListTungstenFabricPolicyCmd listTungstenFabricPolicyCmd;
 
+    AutoCloseable closeable;
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricPolicyCmd = new ListTungstenFabricPolicyCmd();
         listTungstenFabricPolicyCmd.tungstenService = tungstenService;
-        listTungstenFabricPolicyCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricPolicyCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricPolicyCmd, "networkId", 1L);
-        Whitebox.setInternalState(listTungstenFabricPolicyCmd, "addressId", 1L);
-        Whitebox.setInternalState(listTungstenFabricPolicyCmd, "policyUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricPolicyCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricPolicyCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricPolicyCmd, "networkId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricPolicyCmd, "addressId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricPolicyCmd, "policyUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricPolicyCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricPolicyCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricPolicyCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        Whitebox.setInternalState(listTungstenFabricPolicyCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricPolicyCmd, "zoneId", 1L);
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenService.listTungstenPolicy(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricPolicyCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricPolicyCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricPolicyCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 
     @Test
     public void executeAllZoneTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         TungstenProviderVO tungstenProviderVO = Mockito.mock(TungstenProviderVO.class);
         List<TungstenProviderVO> tungstenProviderVOList = Arrays.asList(tungstenProviderVO);
         Mockito.when(tungstenService.getTungstenProviders()).thenReturn(tungstenProviderVOList);
@@ -91,8 +88,9 @@
                 ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricPolicyCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricPolicyCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricPolicyCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricPolicyRuleCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricPolicyRuleCmdTest.java
index e76b8a7..d90f9e5 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricPolicyRuleCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricPolicyRuleCmdTest.java
@@ -16,80 +16,81 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
+import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricPolicyRuleCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricPolicyRuleCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
+    @InjectMocks
     ListTungstenFabricPolicyRuleCmd listTungstenFabricPolicyRuleCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricPolicyRuleCmd = new ListTungstenFabricPolicyRuleCmd();
         listTungstenFabricPolicyRuleCmd.tungstenService = tungstenService;
-        listTungstenFabricPolicyRuleCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricPolicyRuleCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricPolicyRuleCmd, "policyUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricPolicyRuleCmd, "ruleUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricPolicyRuleCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricPolicyRuleCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricPolicyRuleCmd, "policyUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricPolicyRuleCmd, "ruleUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricPolicyRuleCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricPolicyRuleCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricPolicyRuleCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        Whitebox.setInternalState(listTungstenFabricPolicyRuleCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricPolicyRuleCmd, "zoneId", 1L);
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenService.listTungstenPolicyRule(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricPolicyRuleCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricPolicyRuleCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricPolicyRuleCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 
     @Test
     public void executeAllZoneTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         TungstenProviderVO tungstenProviderVO = Mockito.mock(TungstenProviderVO.class);
         List<TungstenProviderVO> tungstenProviderVOList = Arrays.asList(tungstenProviderVO);
         Mockito.when(tungstenService.getTungstenProviders()).thenReturn(tungstenProviderVOList);
         Mockito.when(tungstenService.listTungstenPolicyRule(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricPolicyRuleCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricPolicyRuleCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricPolicyRuleCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricProvidersCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricProvidersCmdTest.java
index 83eb037..4a3c088 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricProvidersCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricProvidersCmdTest.java
@@ -16,10 +16,10 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenProviderService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -28,47 +28,45 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricProvidersCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricProvidersCmdTest {
 
     @Mock
     TungstenProviderService tungstenProviderService;
 
-    @Mock
-    ConfigurationService configService;
-
     ListTungstenFabricProvidersCmd listTungstenFabricProvidersCmd;
 
+    AutoCloseable closeable;
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricProvidersCmd = new ListTungstenFabricProvidersCmd();
-        listTungstenFabricProvidersCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricProvidersCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricProvidersCmd, "tungstenProviderService", tungstenProviderService);
-        Whitebox.setInternalState(listTungstenFabricProvidersCmd, "zoneId", 1L);
-        Whitebox.setInternalState(listTungstenFabricProvidersCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricProvidersCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricProvidersCmd, "tungstenProviderService", tungstenProviderService);
+        ReflectionTestUtils.setField(listTungstenFabricProvidersCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricProvidersCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricProvidersCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricProvidersCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenProviderService.listTungstenProvider(ArgumentMatchers.anyLong())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricProvidersCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricProvidersCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricProvidersCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricServiceGroupCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricServiceGroupCmdTest.java
index 2aacd6d..493e024 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricServiceGroupCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricServiceGroupCmdTest.java
@@ -16,11 +16,11 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -29,64 +29,64 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricServiceGroupCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricServiceGroupCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
     ListTungstenFabricServiceGroupCmd listTungstenFabricServiceGroupCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricServiceGroupCmd = new ListTungstenFabricServiceGroupCmd();
         listTungstenFabricServiceGroupCmd.tungstenService = tungstenService;
-        listTungstenFabricServiceGroupCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricServiceGroupCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricServiceGroupCmd, "serviceGroupUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricServiceGroupCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricServiceGroupCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricServiceGroupCmd, "serviceGroupUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricServiceGroupCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricServiceGroupCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricServiceGroupCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        Whitebox.setInternalState(listTungstenFabricServiceGroupCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricServiceGroupCmd, "zoneId", 1L);
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenService.listTungstenServiceGroup(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricServiceGroupCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricServiceGroupCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricServiceGroupCmd.getResponseObject();
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+
     }
 
     @Test
     public void executeAllZoneTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         TungstenProviderVO tungstenProviderVO = Mockito.mock(TungstenProviderVO.class);
         List<TungstenProviderVO> tungstenProviderVOList = Arrays.asList(tungstenProviderVO);
         Mockito.when(tungstenService.getTungstenProviders()).thenReturn(tungstenProviderVOList);
         Mockito.when(tungstenService.listTungstenServiceGroup(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricServiceGroupCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricServiceGroupCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricServiceGroupCmd.getResponseObject();
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricTagCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricTagCmdTest.java
index a80fc70..afc473c 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricTagCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricTagCmdTest.java
@@ -16,11 +16,11 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -29,50 +29,48 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricTagCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricTagCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
     ListTungstenFabricTagCmd listTungstenFabricTagCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricTagCmd = new ListTungstenFabricTagCmd();
         listTungstenFabricTagCmd.tungstenService = tungstenService;
-        listTungstenFabricTagCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricTagCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricTagCmd, "networkUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricTagCmd, "vmUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricTagCmd, "nicUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricTagCmd, "policyUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricTagCmd, "applicationPolicySetUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricTagCmd, "tagUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricTagCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricTagCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricTagCmd, "networkUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricTagCmd, "vmUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricTagCmd, "nicUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricTagCmd, "policyUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricTagCmd, "applicationPolicySetUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricTagCmd, "tagUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricTagCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricTagCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricTagCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        Whitebox.setInternalState(listTungstenFabricTagCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricTagCmd, "zoneId", 1L);
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenService.listTungstenTags(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString(),
                 ArgumentMatchers.anyString(),
@@ -80,16 +78,17 @@
                 ArgumentMatchers.anyString(),
                 ArgumentMatchers.anyString(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricTagCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricTagCmd.getResponseObject());
+        listTungstenFabricTagCmd.execute();
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricTagCmd.getResponseObject();
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
     }
 
     @Test
     public void executeAllZoneTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         TungstenProviderVO tungstenProviderVO = Mockito.mock(TungstenProviderVO.class);
         List<TungstenProviderVO> tungstenProviderVOList = Arrays.asList(tungstenProviderVO);
         Mockito.when(tungstenService.getTungstenProviders()).thenReturn(tungstenProviderVOList);
@@ -100,8 +99,9 @@
                 ArgumentMatchers.anyString(),
                 ArgumentMatchers.anyString(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricTagCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricTagCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricTagCmd.getResponseObject();
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricTagTypeCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricTagTypeCmdTest.java
index 1eeb867..943ac18 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricTagTypeCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricTagTypeCmdTest.java
@@ -16,11 +16,11 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -29,64 +29,63 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricTagTypeCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricTagTypeCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
     ListTungstenFabricTagTypeCmd listTungstenFabricTagTypeCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricTagTypeCmd = new ListTungstenFabricTagTypeCmd();
         listTungstenFabricTagTypeCmd.tungstenService = tungstenService;
-        listTungstenFabricTagTypeCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricTagTypeCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricTagTypeCmd, "tagTypeUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricTagTypeCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricTagTypeCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricTagTypeCmd, "tagTypeUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricTagTypeCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricTagTypeCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricTagTypeCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        Whitebox.setInternalState(listTungstenFabricTagTypeCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricTagTypeCmd, "zoneId", 1L);
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenService.listTungstenTagTypes(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricTagTypeCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricTagTypeCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricTagTypeCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 
     @Test
     public void executeAllZoneTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         TungstenProviderVO tungstenProviderVO = Mockito.mock(TungstenProviderVO.class);
         List<TungstenProviderVO> tungstenProviderVOList = Arrays.asList(tungstenProviderVO);
         Mockito.when(tungstenService.getTungstenProviders()).thenReturn(tungstenProviderVOList);
         Mockito.when(tungstenService.listTungstenTagTypes(ArgumentMatchers.anyLong(),
                 ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricTagTypeCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricTagTypeCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricTagTypeCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricVmCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricVmCmdTest.java
index a347ca8..0e85a47 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricVmCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenFabricVmCmdTest.java
@@ -16,11 +16,11 @@
 // under the License.
 package org.apache.cloudstack.network.tungsten.api.command;
 
-import com.cloud.configuration.ConfigurationService;
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -29,62 +29,61 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(ListTungstenFabricVmCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ListTungstenFabricVmCmdTest {
 
     @Mock
     TungstenService tungstenService;
 
-    @Mock
-    ConfigurationService configService;
-
     ListTungstenFabricVmCmd listTungstenFabricVmCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         listTungstenFabricVmCmd = new ListTungstenFabricVmCmd();
         listTungstenFabricVmCmd.tungstenService = tungstenService;
-        listTungstenFabricVmCmd._configService = configService;
-        Mockito.when(configService.getDefaultPageSize()).thenReturn(-1L);
-        listTungstenFabricVmCmd.configure();
-        Whitebox.setInternalState(listTungstenFabricVmCmd, "vmUuid", "test");
-        Whitebox.setInternalState(listTungstenFabricVmCmd, "page", 1);
-        Whitebox.setInternalState(listTungstenFabricVmCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricVmCmd, "vmUuid", "test");
+        ReflectionTestUtils.setField(listTungstenFabricVmCmd, "page", 1);
+        ReflectionTestUtils.setField(listTungstenFabricVmCmd, "pageSize", 10);
+        ReflectionTestUtils.setField(listTungstenFabricVmCmd, "s_maxPageSize", -1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        Whitebox.setInternalState(listTungstenFabricVmCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(listTungstenFabricVmCmd, "zoneId", 1L);
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         Mockito.when(tungstenService.listTungstenVm(ArgumentMatchers.anyLong(), ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricVmCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricVmCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricVmCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 
     @Test
     public void executeAllZoneTest() throws Exception {
         BaseResponse baseResponse = Mockito.mock(BaseResponse.class);
         List<BaseResponse> baseResponseList = Arrays.asList(baseResponse);
-        ListResponse<BaseResponse> responseList = Mockito.mock(ListResponse.class);
         TungstenProviderVO tungstenProviderVO = Mockito.mock(TungstenProviderVO.class);
         List<TungstenProviderVO> tungstenProviderVOList = Arrays.asList(tungstenProviderVO);
         Mockito.when(tungstenService.getTungstenProviders()).thenReturn(tungstenProviderVOList);
         Mockito.when(tungstenService.listTungstenVm(ArgumentMatchers.anyLong(), ArgumentMatchers.anyString())).thenReturn(baseResponseList);
-        PowerMockito.whenNew(ListResponse.class).withAnyArguments().thenReturn(responseList);
         listTungstenFabricVmCmd.execute();
-        Assert.assertEquals(responseList, listTungstenFabricVmCmd.getResponseObject());
+        ListResponse<BaseResponse> responseList = (ListResponse<BaseResponse>) listTungstenFabricVmCmd.getResponseObject();
+        Assert.assertEquals(baseResponseList, responseList.getResponses());
+        Assert.assertEquals(Integer.valueOf(1), responseList.getCount());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricNetworkGatewayFromLogicalRouterCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricNetworkGatewayFromLogicalRouterCmdTest.java
index cb7aa9b..6598a3a 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricNetworkGatewayFromLogicalRouterCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricNetworkGatewayFromLogicalRouterCmdTest.java
@@ -24,18 +24,22 @@
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
+@RunWith(MockitoJUnitRunner.class)
 public class RemoveTungstenFabricNetworkGatewayFromLogicalRouterCmdTest {
 
     @Mock
@@ -43,15 +47,22 @@
 
     RemoveTungstenFabricNetworkGatewayFromLogicalRouterCmd removeTungstenFabricNetworkGatewayFromLogicalRouterCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         removeTungstenFabricNetworkGatewayFromLogicalRouterCmd =
                 new RemoveTungstenFabricNetworkGatewayFromLogicalRouterCmd();
         removeTungstenFabricNetworkGatewayFromLogicalRouterCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(removeTungstenFabricNetworkGatewayFromLogicalRouterCmd, "zoneId", 1L);
-        Whitebox.setInternalState(removeTungstenFabricNetworkGatewayFromLogicalRouterCmd, "networkUuid", "test");
-        Whitebox.setInternalState(removeTungstenFabricNetworkGatewayFromLogicalRouterCmd, "logicalRouterUuid", "test");
+        ReflectionTestUtils.setField(removeTungstenFabricNetworkGatewayFromLogicalRouterCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(removeTungstenFabricNetworkGatewayFromLogicalRouterCmd, "networkUuid", "test");
+        ReflectionTestUtils.setField(removeTungstenFabricNetworkGatewayFromLogicalRouterCmd, "logicalRouterUuid", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricPolicyCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricPolicyCmdTest.java
index f449104..abd72d3 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricPolicyCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricPolicyCmdTest.java
@@ -24,15 +24,19 @@
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.api.response.TungstenFabricPolicyResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class RemoveTungstenFabricPolicyCmdTest {
 
     @Mock
@@ -40,14 +44,21 @@
 
     RemoveTungstenFabricPolicyCmd removeTungstenFabricPolicyCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         removeTungstenFabricPolicyCmd = new RemoveTungstenFabricPolicyCmd();
         removeTungstenFabricPolicyCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(removeTungstenFabricPolicyCmd, "zoneId", 1L);
-        Whitebox.setInternalState(removeTungstenFabricPolicyCmd, "networkUuid", "test");
-        Whitebox.setInternalState(removeTungstenFabricPolicyCmd, "policyUuid", "test");
+        ReflectionTestUtils.setField(removeTungstenFabricPolicyCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(removeTungstenFabricPolicyCmd, "networkUuid", "test");
+        ReflectionTestUtils.setField(removeTungstenFabricPolicyCmd, "policyUuid", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricPolicyRuleCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricPolicyRuleCmdTest.java
index bb9acee..633c13f 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricPolicyRuleCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricPolicyRuleCmdTest.java
@@ -24,15 +24,19 @@
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.network.tungsten.api.response.TungstenFabricPolicyResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
+@RunWith(MockitoJUnitRunner.class)
 public class RemoveTungstenFabricPolicyRuleCmdTest {
 
     @Mock
@@ -40,14 +44,21 @@
 
     RemoveTungstenFabricPolicyRuleCmd removeTungstenFabricPolicyRuleCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         removeTungstenFabricPolicyRuleCmd = new RemoveTungstenFabricPolicyRuleCmd();
         removeTungstenFabricPolicyRuleCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(removeTungstenFabricPolicyRuleCmd, "zoneId", 1L);
-        Whitebox.setInternalState(removeTungstenFabricPolicyRuleCmd, "policyUuid", "test");
-        Whitebox.setInternalState(removeTungstenFabricPolicyRuleCmd, "ruleUuid", "test");
+        ReflectionTestUtils.setField(removeTungstenFabricPolicyRuleCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(removeTungstenFabricPolicyRuleCmd, "policyUuid", "test");
+        ReflectionTestUtils.setField(removeTungstenFabricPolicyRuleCmd, "ruleUuid", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricTagCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricTagCmdTest.java
index 399f80c..c03eab4 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricTagCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/RemoveTungstenFabricTagCmdTest.java
@@ -27,14 +27,17 @@
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 
+@RunWith(MockitoJUnitRunner.class)
 public class RemoveTungstenFabricTagCmdTest {
 
     @Mock
@@ -42,18 +45,24 @@
 
     RemoveTungstenFabricTagCmd removeTungstenFabricTagCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         removeTungstenFabricTagCmd = new RemoveTungstenFabricTagCmd();
         removeTungstenFabricTagCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(removeTungstenFabricTagCmd, "zoneId", 1L);
-        Whitebox.setInternalState(removeTungstenFabricTagCmd, "networkUuids", Arrays.asList("test"));
-        Whitebox.setInternalState(removeTungstenFabricTagCmd, "vmUuids", Arrays.asList("test"));
-        Whitebox.setInternalState(removeTungstenFabricTagCmd, "nicUuids", Arrays.asList("test"));
-        Whitebox.setInternalState(removeTungstenFabricTagCmd, "policyUuid", "test");
-        Whitebox.setInternalState(removeTungstenFabricTagCmd, "applicationPolicySetUuid", "test");
-        Whitebox.setInternalState(removeTungstenFabricTagCmd, "tagUuid", "test");
+        ReflectionTestUtils.setField(removeTungstenFabricTagCmd, "zoneId", 1L);
+        ReflectionTestUtils.setField(removeTungstenFabricTagCmd, "networkUuids", Arrays.asList("test"));
+        ReflectionTestUtils.setField(removeTungstenFabricTagCmd, "vmUuids", Arrays.asList("test"));
+        ReflectionTestUtils.setField(removeTungstenFabricTagCmd, "nicUuids", Arrays.asList("test"));
+        ReflectionTestUtils.setField(removeTungstenFabricTagCmd, "policyUuid", "test");
+        ReflectionTestUtils.setField(removeTungstenFabricTagCmd, "applicationPolicySetUuid", "test");
+        ReflectionTestUtils.setField(removeTungstenFabricTagCmd, "tagUuid", "test");
+    }
+
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/SynchronizeTungstenFabricDataCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/SynchronizeTungstenFabricDataCmdTest.java
index dfd6477..ac7b1cd 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/SynchronizeTungstenFabricDataCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/SynchronizeTungstenFabricDataCmdTest.java
@@ -18,6 +18,7 @@
 
 import org.apache.cloudstack.api.response.SuccessResponse;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -26,13 +27,10 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(SynchronizeTungstenFabricDataCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class SynchronizeTungstenFabricDataCmdTest {
 
     @Mock
@@ -40,20 +38,25 @@
 
     SynchronizeTungstenFabricDataCmd synchronizeTungstenFabricDataCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         synchronizeTungstenFabricDataCmd = new SynchronizeTungstenFabricDataCmd();
         synchronizeTungstenFabricDataCmd.tungstenService = tungstenService;
-        Whitebox.setInternalState(synchronizeTungstenFabricDataCmd, "tungstenProviderId", 1L);
+        ReflectionTestUtils.setField(synchronizeTungstenFabricDataCmd, "tungstenProviderId", 1L);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
     public void executeTest() throws Exception {
-        SuccessResponse successResponse = Mockito.mock(SuccessResponse.class);
         Mockito.when(tungstenService.synchronizeTungstenData(ArgumentMatchers.anyLong())).thenReturn(true);
-        PowerMockito.whenNew(SuccessResponse.class).withAnyArguments().thenReturn(successResponse);
         synchronizeTungstenFabricDataCmd.execute();
-        Assert.assertEquals(successResponse, synchronizeTungstenFabricDataCmd.getResponseObject());
+        Assert.assertTrue(((SuccessResponse) synchronizeTungstenFabricDataCmd.getResponseObject()).getSuccess());
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/UpdateTungstenFabricLBHealthMonitorCmdTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/UpdateTungstenFabricLBHealthMonitorCmdTest.java
index 7f0919f..f5c2e5f 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/UpdateTungstenFabricLBHealthMonitorCmdTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/api/command/UpdateTungstenFabricLBHealthMonitorCmdTest.java
@@ -24,6 +24,7 @@
 import org.apache.cloudstack.network.tungsten.api.response.TungstenFabricLBHealthMonitorResponse;
 import org.apache.cloudstack.network.tungsten.dao.TungstenFabricLBHealthMonitorVO;
 import org.apache.cloudstack.network.tungsten.service.TungstenService;
+import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -32,15 +33,12 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Optional;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(UpdateTungstenFabricLBHealthMonitorCmd.class)
+@RunWith(MockitoJUnitRunner.class)
 public class UpdateTungstenFabricLBHealthMonitorCmdTest {
     @Mock
     EntityManager entityManager;
@@ -49,20 +47,27 @@
 
     UpdateTungstenFabricLBHealthMonitorCmd updateTungstenFabricLBHealthMonitorCmd;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         updateTungstenFabricLBHealthMonitorCmd = new UpdateTungstenFabricLBHealthMonitorCmd();
         updateTungstenFabricLBHealthMonitorCmd.tungstenService = tungstenService;
         updateTungstenFabricLBHealthMonitorCmd._entityMgr = entityManager;
-        Whitebox.setInternalState(updateTungstenFabricLBHealthMonitorCmd, "lbId", 1L);
-        Whitebox.setInternalState(updateTungstenFabricLBHealthMonitorCmd, "type", "HTTP");
-        Whitebox.setInternalState(updateTungstenFabricLBHealthMonitorCmd, "retry", 1);
-        Whitebox.setInternalState(updateTungstenFabricLBHealthMonitorCmd, "timeout", 1);
-        Whitebox.setInternalState(updateTungstenFabricLBHealthMonitorCmd, "interval", 1);
-        Whitebox.setInternalState(updateTungstenFabricLBHealthMonitorCmd, "httpMethod", "GET");
-        Whitebox.setInternalState(updateTungstenFabricLBHealthMonitorCmd, "expectedCode", "test");
-        Whitebox.setInternalState(updateTungstenFabricLBHealthMonitorCmd, "urlPath", "test");
+        ReflectionTestUtils.setField(updateTungstenFabricLBHealthMonitorCmd, "lbId", 1L);
+        ReflectionTestUtils.setField(updateTungstenFabricLBHealthMonitorCmd, "type", "HTTP");
+        ReflectionTestUtils.setField(updateTungstenFabricLBHealthMonitorCmd, "retry", 1);
+        ReflectionTestUtils.setField(updateTungstenFabricLBHealthMonitorCmd, "timeout", 1);
+        ReflectionTestUtils.setField(updateTungstenFabricLBHealthMonitorCmd, "interval", 1);
+        ReflectionTestUtils.setField(updateTungstenFabricLBHealthMonitorCmd, "httpMethod", "GET");
+        ReflectionTestUtils.setField(updateTungstenFabricLBHealthMonitorCmd, "expectedCode", "test");
+        ReflectionTestUtils.setField(updateTungstenFabricLBHealthMonitorCmd, "urlPath", "test");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
@@ -83,13 +88,11 @@
     @Test
     public void executeTest() throws Exception {
         updateTungstenFabricLBHealthMonitorCmd.setEntityId(1L);
-        TungstenFabricLBHealthMonitorResponse tungstenFabricLBHealthMonitorResponse =
-                Mockito.mock(TungstenFabricLBHealthMonitorResponse.class);
         TungstenFabricLBHealthMonitorVO tungstenFabricLBHealthMonitorVO =
                 Mockito.mock(TungstenFabricLBHealthMonitorVO.class);
         tungstenFabricLBHealthMonitorVO.setType("test");
-        Whitebox.setInternalState(tungstenFabricLBHealthMonitorVO, "id", 1L);
-        Whitebox.setInternalState(tungstenFabricLBHealthMonitorVO, "uuid", "test");
+        ReflectionTestUtils.setField(tungstenFabricLBHealthMonitorVO, "id", 1L);
+        ReflectionTestUtils.setField(tungstenFabricLBHealthMonitorVO, "uuid", "test");
         tungstenFabricLBHealthMonitorVO.setRetry(1);
         tungstenFabricLBHealthMonitorVO.setTimeout(1);
         tungstenFabricLBHealthMonitorVO.setInterval(1);
@@ -106,9 +109,22 @@
         Mockito.when(entityManager.findById(ArgumentMatchers.eq(Network.class), ArgumentMatchers.anyLong())).thenReturn(network);
         Mockito.when(entityManager.findById(ArgumentMatchers.eq(DataCenter.class), ArgumentMatchers.anyLong())).thenReturn(dataCenter);
         Mockito.when(tungstenService.applyLBHealthMonitor(ArgumentMatchers.anyLong())).thenReturn(true);
-        PowerMockito.whenNew(TungstenFabricLBHealthMonitorResponse.class).withAnyArguments().thenReturn(tungstenFabricLBHealthMonitorResponse);
         updateTungstenFabricLBHealthMonitorCmd.execute();
-        Assert.assertEquals(tungstenFabricLBHealthMonitorResponse,
-                updateTungstenFabricLBHealthMonitorCmd.getResponseObject());
+        TungstenFabricLBHealthMonitorResponse tungstenFabricLBHealthMonitorResponse =
+                (TungstenFabricLBHealthMonitorResponse) updateTungstenFabricLBHealthMonitorCmd.getResponseObject();
+
+        Assert.assertEquals(tungstenFabricLBHealthMonitorVO.getType(), tungstenFabricLBHealthMonitorResponse.getType());
+        Assert.assertEquals(tungstenFabricLBHealthMonitorVO.getId(), tungstenFabricLBHealthMonitorResponse.getId());
+        Assert.assertEquals(tungstenFabricLBHealthMonitorVO.getUuid(), tungstenFabricLBHealthMonitorResponse.getUuid());
+        Assert.assertEquals(tungstenFabricLBHealthMonitorVO.getRetry(), tungstenFabricLBHealthMonitorResponse.getRetry());
+        Assert.assertEquals(tungstenFabricLBHealthMonitorVO.getTimeout(), tungstenFabricLBHealthMonitorResponse.getTimeout());
+        Assert.assertEquals(tungstenFabricLBHealthMonitorVO.getInterval(), tungstenFabricLBHealthMonitorResponse.getInterval());
+        Assert.assertEquals(tungstenFabricLBHealthMonitorVO.getHttpMethod(), tungstenFabricLBHealthMonitorResponse.getHttpMethod());
+        Assert.assertEquals(tungstenFabricLBHealthMonitorVO.getExpectedCode(), tungstenFabricLBHealthMonitorResponse.getExpectedCode());
+        Assert.assertEquals(tungstenFabricLBHealthMonitorVO.getUrlPath(), tungstenFabricLBHealthMonitorResponse.getUrlPath());
+
+        Assert.assertEquals(dataCenter.getId(), tungstenFabricLBHealthMonitorResponse.getZoneId());
+        Assert.assertEquals(dataCenter.getName(), tungstenFabricLBHealthMonitorResponse.getZoneName());
+
     }
 }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/resource/TungstenResourceTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/resource/TungstenResourceTest.java
index bd0b335..af46146 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/resource/TungstenResourceTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/resource/TungstenResourceTest.java
@@ -31,8 +31,7 @@
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-import static org.powermock.api.mockito.PowerMockito.mockStatic;
-import static org.powermock.api.mockito.PowerMockito.whenNew;
+
 
 import net.juniper.tungsten.api.ApiObjectBase;
 import net.juniper.tungsten.api.ApiPropertyBase;
@@ -159,15 +158,17 @@
 import org.apache.cloudstack.network.tungsten.service.TungstenApi;
 import org.apache.cloudstack.network.tungsten.service.TungstenVRouterApi;
 import org.apache.cloudstack.network.tungsten.vrouter.Port;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.mockito.stubbing.Answer;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -177,27 +178,36 @@
 
 import javax.naming.ConfigurationException;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({TungstenVRouterApi.class, TungstenResource.class, TungstenNetworkPolicy.class})
+@RunWith(MockitoJUnitRunner.class)
 public class TungstenResourceTest {
     @Mock
     TungstenApi tungstenApi;
 
     TungstenResource tungstenResource;
 
+    MockedStatic<TungstenVRouterApi> tungstenVRouterApiMocked;
+
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         tungstenResource = new TungstenResource();
         tungstenResource.tungstenApi = tungstenApi;
-        Whitebox.setInternalState(tungstenResource, "vrouterPort", "9091");
-        mockStatic(TungstenVRouterApi.class);
+        ReflectionTestUtils.setField(tungstenResource, "vrouterPort", "9091");
+        tungstenVRouterApiMocked = Mockito.mockStatic(TungstenVRouterApi.class);
 
         Project project = mock(Project.class);
         when(project.getUuid()).thenReturn("065eab99-b819-4f3f-8e97-99c2ab22e6ed");
         when(tungstenApi.getTungstenProjectByFqn(any())).thenReturn(project);
     }
 
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
+        tungstenVRouterApiMocked.close();
+    }
+
     @Test
     public void configureTest() throws ConfigurationException {
         Map<String, Object> map = new HashMap<>();
@@ -307,7 +317,9 @@
             anyString(), anyString(), anyBoolean())).thenReturn(virtualMachineInterface);
         when(tungstenApi.createTungstenInstanceIp(anyString(), anyString(), anyString(), anyString())).thenReturn(
             instanceIp);
-        when(TungstenVRouterApi.addTungstenVrouterPort(anyString(), anyString(), any(Port.class))).thenReturn(true);
+        tungstenVRouterApiMocked.when(
+                () -> TungstenVRouterApi.addTungstenVrouterPort(anyString(), anyString(), any(Port.class))
+                                     ).thenReturn(true);
 
         TungstenAnswer answer = (TungstenAnswer) tungstenResource.executeRequest(command);
         assertTrue(answer.getResult());
@@ -444,7 +456,9 @@
         TungstenCommand command = new DeleteTungstenVRouterPortCommand("10.0.0.10",
             "b604c7f7-1dbc-42d8-bceb-2c0898034a7a");
 
-        when(TungstenVRouterApi.deleteTungstenVrouterPort(anyString(), anyString(), anyString())).thenReturn(true);
+        tungstenVRouterApiMocked.when(
+                () -> TungstenVRouterApi.deleteTungstenVrouterPort(anyString(), anyString(), anyString())
+                                     ).thenReturn(true);
 
         TungstenAnswer answer = (TungstenAnswer) tungstenResource.executeRequest(command);
         assertTrue(answer.getResult());
@@ -543,10 +557,7 @@
         VirtualNetwork virtualNetwork1 = mock(VirtualNetwork.class);
         VirtualNetwork virtualNetwork2 = mock(VirtualNetwork.class);
         List<VirtualNetwork> virtualNetworkList = Arrays.asList(virtualNetwork1, virtualNetwork2);
-        TungstenNetworkPolicy tungstenNetworkPolicy = mock(TungstenNetworkPolicy.class);
 
-        whenNew(TungstenNetworkPolicy.class).withArguments(networkPolicy, virtualNetworkList)
-            .thenReturn(tungstenNetworkPolicy);
         when(networkPolicy.getUuid()).thenReturn("ac617be6-bf80-4086-9d6a-c05ff78e2264");
         when(tungstenApi.getTungstenObjectByName(eq(NetworkPolicy.class), any(), anyString())).thenReturn(
             networkPolicy);
@@ -556,7 +567,7 @@
 
         TungstenAnswer answer = (TungstenAnswer) tungstenResource.executeRequest(command);
         assertTrue(answer.getResult());
-        assertEquals(tungstenNetworkPolicy, answer.getTungstenModel());
+        assertEquals(networkPolicy, ((TungstenNetworkPolicy) answer.getTungstenModel()).getNetworkPolicy());
     }
 
     @Test
@@ -647,8 +658,6 @@
         when(loadbalancerListener.getUuid()).thenReturn("c877d37a-9ad4-4188-a09a-fb13f57f9be0");
         when(loadbalancerPool.getUuid()).thenReturn("baf714fa-80a1-454f-9c32-c4d4a6f5c5a4");
         when(tungstenApi.getTungstenObject(eq(VirtualNetwork.class), anyString())).thenReturn(virtualNetwork);
-        when(tungstenApi.getTungstenObjectByName(eq(FloatingIpPool.class), any(), anyString())).thenReturn(
-            floatingIpPool);
         when(tungstenApi.getSubnetUuid(anyString())).thenReturn("b604c7f7-1dbc-42d8-bceb-2c0898034a7a");
         when(tungstenApi.createTungstenLbVmi(anyString(), anyString(), anyString())).thenReturn(
             virtualMachineInterface);
@@ -952,8 +961,6 @@
         VirtualNetwork virtualNetwork1 = mock(VirtualNetwork.class);
         VirtualNetwork virtualNetwork2 = mock(VirtualNetwork.class);
         List<VirtualNetwork> virtualNetworks = Arrays.asList(virtualNetwork1, virtualNetwork2);
-        when(tungstenApi.listTungstenNetworkPolicy(anyString(), anyString())).thenAnswer(networkPoliciesAnswer);
-        when(tungstenApi.getNetworksFromNetworkPolicy(any(NetworkPolicy.class))).thenReturn(virtualNetworks);
         TungstenAnswer answer = (TungstenAnswer) tungstenResource.executeRequest(command);
         assertTrue(answer.getResult());
         assertNotNull(answer.getTungstenModelList());
@@ -1383,10 +1390,6 @@
         VirtualNetwork virtualNetwork1 = mock(VirtualNetwork.class);
         VirtualNetwork virtualNetwork2 = mock(VirtualNetwork.class);
         Answer<List<ApiObjectBase>> virtualNetworksAnswer = setupApiObjectBaseListAnswer(virtualNetwork1, virtualNetwork2);
-        when(virtualNetwork1.getUuid()).thenReturn("fe79e06a-1142-11ec-82a8-0242ac130003");
-        when(virtualNetwork2.getUuid()).thenReturn("efffa88c-1145-11ec-82a8-0242ac130003");
-        when(tungstenApi.getTungstenObject(eq(LogicalRouter.class), anyString())).thenReturn(logicalRouter);
-        when(tungstenApi.listConnectedNetworkFromLogicalRouter(any(LogicalRouter.class))).thenAnswer(virtualNetworksAnswer);
         when(tungstenApi.addNetworkGatewayToLogicalRouter(anyString(), anyString(), anyString())).thenReturn(logicalRouter);
         when(tungstenApi.listConnectedNetworkFromLogicalRouter(any(LogicalRouter.class))).thenAnswer(virtualNetworksAnswer);
         TungstenAnswer answer = (TungstenAnswer) tungstenResource.executeRequest(command);
@@ -1445,10 +1448,6 @@
         VirtualMachineInterface virtualMachineInterface = mock(VirtualMachineInterface.class);
 
         when(tungstenApi.getTungstenObject(eq(LogicalRouter.class), anyString())).thenReturn(logicalRouter);
-        when(logicalRouter.getVirtualMachineInterface()).thenReturn(List.of(objectReference));
-        when(tungstenApi.updateTungstenObject(any(LogicalRouter.class))).thenReturn(true);
-        when(tungstenApi.getTungstenObject(eq(VirtualMachineInterface.class), anyString())).thenReturn(virtualMachineInterface);
-        when(tungstenApi.deleteTungstenVmInterface(any(VirtualMachineInterface.class))).thenReturn(true);
         when(tungstenApi.deleteTungstenObject(any(LogicalRouter.class))).thenReturn(true);
 
         TungstenAnswer answer = (TungstenAnswer) tungstenResource.executeRequest(command);
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenApiTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenApiTest.java
index 5bd9221..3c12bfb 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenApiTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenApiTest.java
@@ -58,6 +58,8 @@
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -66,6 +68,7 @@
 import java.util.List;
 import java.util.UUID;
 
+@RunWith(MockitoJUnitRunner.class)
 public class TungstenApiTest {
 
     private static final Logger s_logger = Logger.getLogger(TungstenApiTest.class);
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenElementTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenElementTest.java
index bad5669..18f2954 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenElementTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenElementTest.java
@@ -28,7 +28,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.powermock.api.mockito.PowerMockito.mockStatic;
 
 import com.cloud.agent.AgentManager;
 import com.cloud.api.ApiDBUtils;
@@ -110,24 +109,24 @@
 import org.apache.cloudstack.network.tungsten.agent.api.SetupTungstenVRouterCommand;
 import org.apache.cloudstack.network.tungsten.agent.api.TungstenAnswer;
 import org.apache.cloudstack.network.tungsten.agent.api.UpdateTungstenLoadBalancerHealthMonitorCommand;
-import org.apache.cloudstack.network.tungsten.agent.api.UpdateTungstenLoadBalancerListenerCommand;
 import org.apache.cloudstack.network.tungsten.agent.api.UpdateTungstenLoadBalancerMemberCommand;
 import org.apache.cloudstack.network.tungsten.agent.api.UpdateTungstenLoadBalancerPoolCommand;
 import org.apache.cloudstack.network.tungsten.dao.TungstenFabricLBHealthMonitorDao;
 import org.apache.cloudstack.network.tungsten.dao.TungstenFabricLBHealthMonitorVO;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({ApiDBUtils.class, EncryptionUtil.class})
+@RunWith(MockitoJUnitRunner.class)
 public class TungstenElementTest {
     @Mock
     TungstenFabricUtils tungstenFabricUtils;
@@ -182,9 +181,15 @@
 
     TungstenElement tungstenElement;
 
+    MockedStatic<ApiDBUtils> apiDBUtilsMocked;
+
+    MockedStatic<EncryptionUtil> encryptionUtilMocked;
+
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         tungstenElement = new TungstenElement();
         tungstenElement.tungstenFabricUtils = tungstenFabricUtils;
         tungstenElement.networkModel = networkModel;
@@ -212,12 +217,19 @@
         tungstenElement.tungstenFabricLBHealthMonitorDao = tungstenFabricLBHealthMonitorDao;
         tungstenElement.loadBalancerCertMapDao = loadBalancerCertMapDao;
 
-        mockStatic(ApiDBUtils.class);
-        mockStatic(EncryptionUtil.class);
+        apiDBUtilsMocked = Mockito.mockStatic(ApiDBUtils.class);
+        encryptionUtilMocked = Mockito.mockStatic(EncryptionUtil.class);
 
         when(tungstenService.getTungstenProjectFqn(any())).thenReturn("default-domain:default-project");
     }
 
+    @After
+    public void tearDown() throws Exception {
+        apiDBUtilsMocked.close();
+        encryptionUtilMocked.close();
+        closeable.close();
+    }
+
     @Test
     public void canHandleSuccessTest() {
         Network network = mock(Network.class);
@@ -352,9 +364,6 @@
         when(lbStickinessPolicy.getMethodName()).thenReturn("AppCookie");
         List<Pair<String, String>> pairList = List.of(new Pair<>("cookieName", "cookieValue"));
 
-        when(accountMgr.getActiveUser(anyLong())).thenReturn(caller);
-        when(caller.getApiKey()).thenReturn("apikey");
-        when(caller.getSecretKey()).thenReturn("secreatekey");
         when(lbStickinessPolicy.getParams()).thenReturn(pairList);
         when(loadBalancingRule1.getId()).thenReturn(1L);
         when(loadBalancingRule1.getState()).thenReturn(FirewallRule.State.Add);
@@ -363,8 +372,6 @@
         when(loadBalancingRule1.getDefaultPortStart()).thenReturn(443);
         when(loadBalancingRule1.getStickinessPolicies()).thenReturn(lbStickinessPolicyList);
         when(loadBalancingRule1.getSourceIp()).thenReturn(ip);
-        when(loadBalancingRule1.getLbSslCert()).thenReturn(lbSslCert);
-        when(loadBalancingRule1.getUuid()).thenReturn("loadbalancingruleuuid");
         when(networkModel.getSystemNetworkByZoneAndTrafficType(anyLong(), any())).thenReturn(publicNetwork);
         when(ipAddressDao.findByIpAndDcId(anyLong(), anyString())).thenReturn(ipAddressVO);
         when(ipAddressVO.getAddress()).thenReturn(ip);
@@ -372,19 +379,15 @@
         when(tungstenGuestNetworkIpAddressVO.getGuestIpAddress()).thenReturn(ip);
         when(ip.addr()).thenReturn("10.10.10.10");
         when(tungstenGuestNetworkIpAddressDao.findByNetworkIdAndPublicIp(anyLong(), anyString())).thenReturn(tungstenGuestNetworkIpAddressVO);
-        when(ipAddressMgr.acquireGuestIpAddress(any(), any())).thenReturn("192.168.100.100");
         when(tungstenFabricUtils.sendTungstenCommand(any(CreateTungstenNetworkLoadbalancerCommand.class), anyLong())).thenReturn(createTungstenNetworkLoadbalancerAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(UpdateTungstenLoadBalancerPoolCommand.class), anyLong())).thenReturn(updateTungstenLoadBalancerPoolAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(UpdateTungstenLoadBalancerMemberCommand.class), anyLong())).thenReturn(updateTungstenLoadBalancerMemberAnswer);
-        when(tungstenFabricUtils.sendTungstenCommand(any(UpdateTungstenLoadBalancerListenerCommand.class), anyLong())).thenReturn(updateTungstenLoadBalancerListenerAnswer);
         when(createTungstenNetworkLoadbalancerAnswer.getResult()).thenReturn(true);
         when(updateTungstenLoadBalancerPoolAnswer.getResult()).thenReturn(true);
         when(updateTungstenLoadBalancerMemberAnswer.getResult()).thenReturn(true);
-        when(updateTungstenLoadBalancerListenerAnswer.getResult()).thenReturn(true);
         when(updateTungstenHealthMonitorAnswer.getResult()).thenReturn(true);
         when(configDao.getValue(Config.NetworkLBHaproxyStatsVisbility.key())).thenReturn("enabled");
         when(tungstenService.updateLoadBalancer(any(), any())).thenReturn(true);
-        when(lbDao.listByIpAddress(anyLong())).thenReturn(loadBalancerVOList);
         when(EncryptionUtil.generateSignature(anyString(), anyString())).thenReturn("generatedString");
         when(tungstenFabricLBHealthMonitorDao.findByLbId(anyLong())).thenReturn(tungstenFabricLBHealthMonitorVO);
         when(tungstenFabricUtils.sendTungstenCommand(any(UpdateTungstenLoadBalancerHealthMonitorCommand.class), anyLong())).thenReturn(updateTungstenHealthMonitorAnswer);
@@ -427,7 +430,6 @@
         when(ipAddressDao.findByIpAndDcId(anyLong(), anyString())).thenReturn(ipAddressVO);
         when(ipAddressVO.getAddress()).thenReturn(ip);
         when(lbVmMapDao.listByLoadBalancerId(anyLong(), anyBoolean())).thenReturn(loadBalancerVMMapVOList);
-        when(tungstenGuestNetworkIpAddressVO.getGuestIpAddress()).thenReturn(ip);
         when(ip.addr()).thenReturn("10.10.10.10");
         when(ipAddressMgr.acquireGuestIpAddress(any(), any())).thenReturn("192.168.100.100");
         when(tungstenFabricUtils.sendTungstenCommand(any(CreateTungstenNetworkLoadbalancerCommand.class), anyLong())).thenReturn(createTungstenNetworkLoadbalancerAnswer);
@@ -437,8 +439,6 @@
         when(updateTungstenLoadBalancerPoolAnswer.getResult()).thenReturn(true);
         when(updateTungstenLoadBalancerMemberAnswer.getResult()).thenReturn(true);
         when(configDao.getValue(Config.NetworkLBHaproxyStatsVisbility.key())).thenReturn("disabled");
-        when(tungstenService.updateLoadBalancerSsl(any(), any())).thenReturn(false);
-        when(lbDao.listByIpAddress(anyLong())).thenReturn(loadBalancerVOList);
         when(tungstenFabricLBHealthMonitorDao.findByLbId(anyLong())).thenReturn(tungstenFabricLBHealthMonitorVO);
         when(updateTungstenHealthMonitorAnswer.getResult()).thenReturn(true);
         when(tungstenFabricUtils.sendTungstenCommand(any(UpdateTungstenLoadBalancerHealthMonitorCommand.class), anyLong())).thenReturn(updateTungstenHealthMonitorAnswer);
@@ -466,11 +466,8 @@
         when(ipAddressDao.findByIpAndDcId(anyLong(), anyString())).thenReturn(ipAddressVO);
         when(ipAddressVO.getAddress()).thenReturn(ip1);
         when(ip1.addr()).thenReturn("10.10.10.10");
-        when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenLoadBalancerListenerCommand.class), anyLong())).thenReturn(deleteTungstenLoadBalancerListenerAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenLoadBalancerCommand.class), anyLong())).thenReturn(deleteTungstenLoadBalancerCommand);
-        when(deleteTungstenLoadBalancerListenerAnswer.getResult()).thenReturn(true);
         when(deleteTungstenLoadBalancerCommand.getResult()).thenReturn(true);
-        when(tungstenService.updateLoadBalancerSsl(any(), any())).thenReturn(false);
         when(lbDao.listByIpAddress(anyLong())).thenReturn(loadBalancerVOList1);
         when(tungstenGuestNetworkIpAddressDao.findByNetworkIdAndPublicIp(anyLong(),anyString())).thenReturn(tungstenGuestNetworkIpAddressVO);
         when(tungstenGuestNetworkIpAddressDao.remove(anyLong())).thenReturn(false);
@@ -497,15 +494,11 @@
         when(loadBalancingRule.getSourceIp()).thenReturn(ip);
         when(loadBalancingRule.getState()).thenReturn(FirewallRule.State.Revoke);
         when(ipAddressDao.findByIpAndDcId(anyLong(), anyString())).thenReturn(ipAddressVO);
-        when(ipAddressVO.getAddress()).thenReturn(ip);
         when(ip.addr()).thenReturn("10.10.10.10");
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenLoadBalancerListenerCommand.class), anyLong())).thenReturn(deleteTungstenLoadBalancerListenerAnswer);
-        when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenLoadBalancerCommand.class), anyLong())).thenReturn(deleteTungstenLoadBalancerCommand);
         when(deleteTungstenLoadBalancerListenerAnswer.getResult()).thenReturn(true);
-        when(deleteTungstenLoadBalancerCommand.getResult()).thenReturn(true);
         when(tungstenService.updateLoadBalancer(any(), any())).thenReturn(true);
         when(lbDao.listByIpAddress(anyLong())).thenReturn(loadBalancerVOList);
-        when(tungstenGuestNetworkIpAddressDao.findByNetworkIdAndPublicIp(anyLong(),anyString())).thenReturn(tungstenGuestNetworkIpAddressVO);
 
         assertTrue(tungstenElement.applyLBRules(network, loadBalancingRuleList));
     }
@@ -700,10 +693,6 @@
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenVmInterfaceCommand.class), anyLong())).thenReturn(deleteVmiAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenVmCommand.class), anyLong())).thenReturn(deleteVmAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenNetworkPolicyCommand.class), anyLong())).thenReturn(deleteTungstenNetworkPolicyAnswer);
-        when(deleteTungstenVRouterPortAnswer.getResult()).thenReturn(true);
-        when(deleteVmiAnswer.getResult()).thenReturn(true);
-        when(deleteVmAnswer.getResult()).thenReturn(true);
-        when(deleteTungstenNetworkPolicyAnswer.getResult()).thenReturn(true);
 
         assertTrue(tungstenElement.release(network, nicProfile, virtualMachineProfile, reservationContext));
     }
@@ -720,7 +709,6 @@
         TungstenAnswer deleteVmiAnswer = mock(TungstenAnswer.class);
         TungstenAnswer deleteVmAnswer = mock(TungstenAnswer.class);
 
-        when(nicProfile.getIPv4Address()).thenReturn("192.168.100.100");
         when(network.getTrafficType()).thenReturn(Networks.TrafficType.Management);
         when(vmInstanceDao.findById(anyLong())).thenReturn(vmInstanceVO);
         when(hostDao.findById(anyLong())).thenReturn(host);
@@ -728,9 +716,6 @@
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenVRouterPortCommand.class), anyLong())).thenReturn(deleteTungstenVRouterPortAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenVmInterfaceCommand.class), anyLong())).thenReturn(deleteVmiAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenVmCommand.class), anyLong())).thenReturn(deleteVmAnswer);
-        when(deleteTungstenVRouterPortAnswer.getResult()).thenReturn(true);
-        when(deleteVmiAnswer.getResult()).thenReturn(true);
-        when(deleteVmAnswer.getResult()).thenReturn(true);
 
         assertTrue(tungstenElement.release(network, nicProfile, virtualMachineProfile, reservationContext));
     }
@@ -746,7 +731,6 @@
         TungstenAnswer deleteTungstenVRouterPortAnswer = mock(TungstenAnswer.class);
         TungstenAnswer deleteVmiAnswer = mock(TungstenAnswer.class);
 
-        when(nicProfile.getIPv4Address()).thenReturn("192.168.100.100");
         when(network.getTrafficType()).thenReturn(Networks.TrafficType.Management);
         when(vmInstanceDao.findById(anyLong())).thenReturn(vmInstanceVO);
         when(hostDao.findById(anyLong())).thenReturn(host);
@@ -754,8 +738,6 @@
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenVRouterPortCommand.class), anyLong())).thenReturn(deleteTungstenVRouterPortAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenVmInterfaceCommand.class), anyLong())).thenReturn(deleteVmiAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenVmCommand.class), anyLong())).thenThrow(IllegalArgumentException.class);
-        when(deleteTungstenVRouterPortAnswer.getResult()).thenReturn(true);
-        when(deleteVmiAnswer.getResult()).thenReturn(true);
 
         tungstenElement.release(network, nicProfile, virtualMachineProfile, reservationContext);
     }
@@ -971,7 +953,6 @@
         when(firewallRuleVO.getPurpose()).thenReturn(FirewallRule.Purpose.Firewall);
         when(firewallRuleVO.getTrafficType()).thenReturn(FirewallRule.TrafficType.Ingress);
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenNetworkPolicyCommand.class), anyLong())).thenReturn(deleteNetworkPolicyAnswer);
-        when(deleteNetworkPolicyAnswer.getResult()).thenReturn(true);
 
         assertTrue(tungstenElement.applyFWRules(network, List.of(firewallRuleVO)));
     }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenFabricUtilsTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenFabricUtilsTest.java
index 2961826..7f2a579 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenFabricUtilsTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenFabricUtilsTest.java
@@ -28,11 +28,15 @@
 import com.cloud.network.element.TungstenProviderVO;
 import org.apache.cloudstack.network.tungsten.agent.api.TungstenAnswer;
 import org.apache.cloudstack.network.tungsten.agent.api.TungstenCommand;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
 
+@RunWith(MockitoJUnitRunner.class)
 public class TungstenFabricUtilsTest {
     @Mock
     AgentManager agentMgr;
@@ -41,14 +45,21 @@
 
     TungstenFabricUtils tungstenFabricUtils;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         tungstenFabricUtils = new TungstenFabricUtils();
         tungstenFabricUtils.agentMgr = agentMgr;
         tungstenFabricUtils.tungstenProviderDao = tungstenProviderDao;
     }
 
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
+    }
+
     @Test
     public void sendTungstenCommandSuccessTest() {
         TungstenProviderVO tungstenProviderVO = mock(TungstenProviderVO.class);
@@ -88,7 +99,6 @@
         when(tungstenProviderDao.findByZoneId(anyLong())).thenReturn(tungstenProviderVO);
         when(agentMgr.easySend(anyLong(), any(TungstenCommand.class))).thenReturn(tungstenAnswer);
         when(tungstenAnswer.getResult()).thenReturn(false);
-        when(tungstenAnswer.getDetails()).thenReturn("");
 
         tungstenFabricUtils.sendTungstenCommand(tungstenCommand, anyLong());
     }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuruTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuruTest.java
index 810ba64..6a5a013 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuruTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuruTest.java
@@ -85,27 +85,25 @@
 import org.apache.cloudstack.network.tungsten.agent.api.DeleteTungstenVmCommand;
 import org.apache.cloudstack.network.tungsten.agent.api.DeleteTungstenVmInterfaceCommand;
 import org.apache.cloudstack.network.tungsten.agent.api.GetTungstenNatIpCommand;
-import org.apache.cloudstack.network.tungsten.agent.api.ReleaseTungstenFloatingIpCommand;
 import org.apache.cloudstack.network.tungsten.agent.api.SetTungstenNetworkGatewayCommand;
 import org.apache.cloudstack.network.tungsten.agent.api.SetupTungstenVRouterCommand;
 import org.apache.cloudstack.network.tungsten.agent.api.TungstenAnswer;
 import org.apache.cloudstack.network.tungsten.agent.api.TungstenCommand;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(TungstenGuestNetworkGuru.class)
+@RunWith(MockitoJUnitRunner.class)
 public class TungstenGuestNetworkGuruTest {
 
     @Mock
@@ -155,14 +153,16 @@
 
     TungstenGuestNetworkGuru guru;
 
+    AutoCloseable closeable;
+
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         guru = new TungstenGuestNetworkGuru();
-        Whitebox.setInternalState(guru, "_physicalNetworkDao", physicalNetworkDao);
-        Whitebox.setInternalState(guru, "_dcDao", dcDao);
-        Whitebox.setInternalState(guru, "_networkModel", networkModel);
-        Whitebox.setInternalState(guru, "_nicDao", nicDao);
+        ReflectionTestUtils.setField(guru, "_physicalNetworkDao", physicalNetworkDao);
+        ReflectionTestUtils.setField(guru, "_dcDao", dcDao);
+        ReflectionTestUtils.setField(guru, "_networkModel", networkModel);
+        ReflectionTestUtils.setField(guru, "_nicDao", nicDao);
         guru.networkOfferingServiceMapDao = ntwkOfferingSrvcDao;
         guru.tungstenFabricUtils = tungstenFabricUtils;
         guru.tungstenService = tungstenService;
@@ -180,10 +180,8 @@
 
         when(dc.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced);
         when(dc.getGuestNetworkCidr()).thenReturn("10.1.1.1/24");
-        when(dc.getId()).thenReturn(1L);
         when(dcDao.findById(anyLong())).thenReturn(dc);
 
-        when(physicalNetwork.getId()).thenReturn(1L);
         when(physicalNetwork.getIsolationMethods()).thenReturn(List.of("TF"));
         when(physicalNetworkDao.findById(anyLong())).thenReturn(physicalNetwork);
 
@@ -198,6 +196,11 @@
         when(plan.getPhysicalNetworkId()).thenReturn(1L);
     }
 
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
+    }
+
     @Test
     public void testIsMyIsolationMethod() {
         assertTrue(guru.isMyIsolationMethod(physicalNetwork));
@@ -401,13 +404,7 @@
         final VMInstanceVO vmInstanceVO = mock(VMInstanceVO.class);
         final HostVO host = mock(HostVO.class);
 
-        when(vm.getType()).thenReturn(VirtualMachine.Type.User);
         when(hostDao.findById(anyLong())).thenReturn(host);
-        when(ipAddressDao.findByAssociatedVmId(anyLong())).thenReturn(ipAddressVO);
-        when(networkModel.getSystemNetworkByZoneAndTrafficType(anyLong(), any())).thenReturn(new NetworkVO());
-        when(
-            tungstenFabricUtils.sendTungstenCommand(any(ReleaseTungstenFloatingIpCommand.class), anyLong())).thenReturn(
-            new TungstenAnswer(new TungstenCommand(), true, ""));
         when(
             tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenVRouterPortCommand.class), anyLong())).thenReturn(
             new TungstenAnswer(new TungstenCommand(), true, ""));
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenIntrospectApiTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenIntrospectApiTest.java
index b893a7d..3eaa1a8 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenIntrospectApiTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenIntrospectApiTest.java
@@ -18,27 +18,34 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.powermock.api.mockito.PowerMockito.mock;
-import static org.powermock.api.mockito.PowerMockito.mockStatic;
-import static org.powermock.api.mockito.PowerMockito.when;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
 
 import org.apache.cloudstack.network.tungsten.vrouter.IntrospectApiConnector;
 import org.apache.cloudstack.network.tungsten.vrouter.IntrospectApiConnectorFactory;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.MockedStatic;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(IntrospectApiConnectorFactory.class)
+@RunWith(MockitoJUnitRunner.class)
 public class TungstenIntrospectApiTest {
+    MockedStatic<IntrospectApiConnectorFactory> introspectApiConnectorFactoryMocked;
+
     @Before
     public void setup() {
-        mockStatic(IntrospectApiConnectorFactory.class);
+        introspectApiConnectorFactoryMocked = mockStatic(IntrospectApiConnectorFactory.class);
+    }
+
+    @After
+    public void tearDown() {
+        introspectApiConnectorFactoryMocked.close();
     }
 
     @Test
@@ -48,7 +55,7 @@
         NodeList nodeList = mock(NodeList.class);
         Node node = mock(Node.class);
 
-        when(IntrospectApiConnectorFactory.getInstance(anyString(), anyString())).thenReturn(introspectApiConnector);
+        introspectApiConnectorFactoryMocked.when(() -> IntrospectApiConnectorFactory.getInstance(anyString(), anyString())).thenReturn(introspectApiConnector);
         when(introspectApiConnector.getSnhItfReq(anyString())).thenReturn(document);
         when(document.getElementsByTagName(anyString())).thenReturn(nodeList);
         when(nodeList.getLength()).thenReturn(1);
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderServiceTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderServiceTest.java
index 0a62a22..6654718 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderServiceTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderServiceTest.java
@@ -38,15 +38,19 @@
 import org.apache.cloudstack.api.BaseResponse;
 import org.apache.cloudstack.framework.messagebus.MessageBus;
 import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenFabricProviderCmd;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.Arrays;
 import java.util.List;
 
+@RunWith(MockitoJUnitRunner.class)
 public class TungstenProviderServiceTest {
 
     @Mock
@@ -70,9 +74,11 @@
 
     TungstenProviderServiceImpl tungstenProviderService;
 
+    AutoCloseable closeable;
+
     @Before
     public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         tungstenProviderService = new TungstenProviderServiceImpl();
         tungstenProviderService.zoneDao = dcDao;
         tungstenProviderService.resourceMgr = resourceMgr;
@@ -86,8 +92,11 @@
         when(zone.getName()).thenReturn("ZoneName");
         when(resourceMgr.addHost(anyLong(), any(), any(), anyMap())).thenReturn(host);
         when(host.getId()).thenReturn(1L);
-        when(domainDao.listAll()).thenReturn(null);
-        when(projectDao.listAll()).thenReturn(null);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImplTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImplTest.java
index 6b199e2..736d032 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImplTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImplTest.java
@@ -27,8 +27,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-import static org.powermock.api.mockito.PowerMockito.mockStatic;
-import static org.powermock.api.mockito.PowerMockito.whenNew;
 
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
@@ -193,7 +191,6 @@
 import org.apache.cloudstack.network.tungsten.agent.api.RemoveTungstenSecondaryIpAddressCommand;
 import org.apache.cloudstack.network.tungsten.agent.api.RemoveTungstenSecurityGroupRuleCommand;
 import org.apache.cloudstack.network.tungsten.agent.api.RemoveTungstenTagCommand;
-import org.apache.cloudstack.network.tungsten.agent.api.RemoveTungstenVmFromSecurityGroupCommand;
 import org.apache.cloudstack.network.tungsten.agent.api.SetupTungstenVRouterCommand;
 import org.apache.cloudstack.network.tungsten.agent.api.TungstenAnswer;
 import org.apache.cloudstack.network.tungsten.agent.api.UpdateLoadBalancerServiceInstanceCommand;
@@ -205,21 +202,22 @@
 import org.apache.cloudstack.network.tungsten.model.TungstenNetworkPolicy;
 import org.apache.cloudstack.network.tungsten.model.TungstenRule;
 import org.apache.cloudstack.network.tungsten.model.TungstenTag;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.Arrays;
 import java.util.List;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({Transaction.class, TungstenServiceImpl.class})
+@RunWith(MockitoJUnitRunner.class)
 public class TungstenServiceImplTest {
     @Mock
     MessageBus messageBus;
@@ -278,9 +276,11 @@
 
     TungstenServiceImpl tungstenService;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         tungstenService = new TungstenServiceImpl();
         tungstenService.projectDao = projectDao;
         tungstenService.tungstenProviderDao = tungstenProviderDao;
@@ -311,6 +311,11 @@
         tungstenService.messageBus = messageBus;
     }
 
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
+    }
+
     @Test
     public void createTungstenFloatingIpTest() throws Exception {
         IPAddressVO ipAddressVO = mock(IPAddressVO.class);
@@ -323,7 +328,7 @@
         when(createTungstenFloatingIpAnswer.getResult()).thenReturn(true);
         when(ipAddressVO.getAddress()).thenReturn(ip);
 
-        assertTrue(Whitebox.invokeMethod(tungstenService, "createTungstenFloatingIp", 1L, ipAddressVO));
+        assertTrue(ReflectionTestUtils.invokeMethod(tungstenService, "createTungstenFloatingIp", 1L, ipAddressVO));
     }
 
     @Test
@@ -336,7 +341,7 @@
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenFloatingIpCommand.class), anyLong())).thenReturn(deleteTungstenFloatingIpAnswer);
         when(deleteTungstenFloatingIpAnswer.getResult()).thenReturn(true);
 
-        assertTrue(Whitebox.invokeMethod(tungstenService, "deleteTungstenFloatingIp", 1L, ipAddressVO));
+        assertTrue(ReflectionTestUtils.invokeMethod(tungstenService, "deleteTungstenFloatingIp", 1L, ipAddressVO));
     }
 
     @Test
@@ -349,7 +354,7 @@
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenDomainCommand.class), anyLong())).thenReturn(deleteTungstenDomainAnswer);
         when(deleteTungstenDomainAnswer.getResult()).thenReturn(true);
 
-        assertTrue(Whitebox.invokeMethod(tungstenService, "deleteTungstenDomain", domainVO));
+        assertTrue(ReflectionTestUtils.invokeMethod(tungstenService, "deleteTungstenDomain", domainVO));
     }
 
     @Test
@@ -362,7 +367,7 @@
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenProjectCommand.class), anyLong())).thenReturn(deleteTungstenProjectAnswer);
         when(deleteTungstenProjectAnswer.getResult()).thenReturn(true);
 
-        assertTrue(Whitebox.invokeMethod(tungstenService, "deleteTungstenProject", projectVO));
+        assertTrue(ReflectionTestUtils.invokeMethod(tungstenService, "deleteTungstenProject", projectVO));
     }
 
     @Test
@@ -451,12 +456,10 @@
 
         when(networkModel.getSystemNetworkByZoneAndTrafficType(anyLong(),
             eq(Networks.TrafficType.Management))).thenReturn(managementNetwork);
-        when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenNetworkPolicyCommand.class), anyLong())).thenReturn(deleteTungstenManagementPolicyAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(GetTungstenFabricNetworkCommand.class), anyLong())).thenReturn(getTungstenFabricNetworkAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenNetworkPolicyCommand.class), anyLong())).thenReturn(deleteTungstenFabricPolicyAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(DeleteTungstenNetworkCommand.class), anyLong())).thenReturn(deleteTungstenNetworkAnswer);
         when(getTungstenFabricNetworkAnswer.getApiObjectBase()).thenReturn(fabricVirtualNetwork);
-        when(deleteTungstenManagementPolicyAnswer.getResult()).thenReturn(true);
         when(getTungstenFabricNetworkAnswer.getResult()).thenReturn(true);
         when(deleteTungstenFabricPolicyAnswer.getResult()).thenReturn(true);
         when(deleteTungstenNetworkAnswer.getResult()).thenReturn(true);
@@ -472,7 +475,6 @@
         TungstenAnswer getTungstenNetworkDnsAnswer = mock(TungstenAnswer.class);
         DataCenterIpAddressVO dataCenterIpAddressVO = mock(DataCenterIpAddressVO.class);
 
-        when(hostPodVO.getDescription()).thenReturn("192.168.100.100-192.168.100.200");
         when(networkModel.getSystemNetworkByZoneAndTrafficType(anyLong(),
             eq(Networks.TrafficType.Management))).thenReturn(managementNetwork);
         when(tungstenFabricUtils.sendTungstenCommand(any(RemoveTungstenNetworkSubnetCommand.class), anyLong())).thenReturn(removeTungstenNetworkSubnetAnswer);
@@ -543,7 +545,6 @@
         when(applyTungstenPolicyAnswer.getResult()).thenReturn(true);
         when(publicNetwork.getTrafficType()).thenReturn(Networks.TrafficType.Public);
         when(createTungstenPolicyAnswer.getApiObjectBase()).thenReturn(networkPolicy);
-        when(ipAddressDao.findByIpAndDcId(anyLong(), anyString())).thenReturn(ipAddressVO);
         when(ipAddressDao.mark(anyLong(), any(Ip.class))).thenReturn(true);
 
         assertTrue(tungstenService.addPublicNetworkSubnet(vlanVO));
@@ -729,19 +730,19 @@
         TungstenSecurityGroupRuleVO tungstenSecurityGroupRuleVO = mock(TungstenSecurityGroupRuleVO.class);
         TungstenAnswer createTungstenSecurityGroupAnswer = mock(TungstenAnswer.class);
         TungstenAnswer addTungstenSecurityGroupRuleAnswer = mock(TungstenAnswer.class);
-        mockStatic(Transaction.class);
 
         when(projectDao.findByProjectAccountId(anyLong())).thenReturn(projectVO);
         when(tungstenProviderDao.findAll()).thenReturn(List.of(tungstenProviderVO));
         when(domainDao.findById(anyLong())).thenReturn(domainVO);
-        when(projectDao.findByUuid(anyString())).thenReturn(projectVO);
         when(tungstenFabricUtils.sendTungstenCommand(any(CreateTungstenSecurityGroupCommand.class), anyLong())).thenReturn(createTungstenSecurityGroupAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(AddTungstenSecurityGroupRuleCommand.class), anyLong())).thenReturn(addTungstenSecurityGroupRuleAnswer);
         when(createTungstenSecurityGroupAnswer.getResult()).thenReturn(true);
         when(addTungstenSecurityGroupRuleAnswer.getResult()).thenReturn(true);
-        PowerMockito.when(Transaction.execute(any(TransactionCallback.class))).thenReturn(List.of(tungstenSecurityGroupRuleVO));
 
-        assertTrue(tungstenService.createTungstenSecurityGroup(securityGroup));
+        try (MockedStatic<Transaction> transactionMocked = Mockito.mockStatic(Transaction.class)) {
+            transactionMocked.when(() -> Transaction.execute(any(TransactionCallback.class))).thenReturn(List.of(tungstenSecurityGroupRuleVO));
+            assertTrue(tungstenService.createTungstenSecurityGroup(securityGroup));
+        }
     }
 
     @Test
@@ -774,7 +775,6 @@
         when(tungstenFabricUtils.sendTungstenCommand(any(GetTungstenSecurityGroupCommand.class), anyLong())).thenReturn(getTungstenSecurityGroupAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(RemoveTungstenSecurityGroupRuleCommand.class), anyLong())).thenReturn(removeTungstenSecurityGroupRuleAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(AddTungstenSecurityGroupRuleCommand.class), anyLong())).thenReturn(addTungstenSecurityGroupRuleAnswer);
-        when(getTungstenSecurityGroupAnswer.getResult()).thenReturn(true);
         when(removeTungstenSecurityGroupRuleAnswer.getResult()).thenReturn(true);
         when(addTungstenSecurityGroupRuleAnswer.getResult()).thenReturn(true);
         when(getTungstenSecurityGroupAnswer.getApiObjectBase()).thenReturn(securityGroup);
@@ -807,7 +807,6 @@
         when(securityGroupDao.findById(anyLong())).thenReturn(securityGroupVO);
         when(tungstenFabricUtils.sendTungstenCommand(any(GetTungstenSecurityGroupCommand.class), anyLong())).thenReturn(getTungstenSecurityGroupAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(AddTungstenSecurityGroupRuleCommand.class), anyLong())).thenReturn(addTungstenSecurityGroupRuleAnswer);
-        when(getTungstenSecurityGroupAnswer.getResult()).thenReturn(true);
         when(addTungstenSecurityGroupRuleAnswer.getResult()).thenReturn(true);
         when(getTungstenSecurityGroupAnswer.getApiObjectBase()).thenReturn(securityGroup);
         when(securityRule.getRuleType()).thenReturn(SecurityRule.SecurityRuleType.IngressRule);
@@ -860,7 +859,6 @@
         when(tungstenProviderDao.findAll()).thenReturn(List.of(tungstenProviderVO));
         when(securityGroupDao.findById(anyLong())).thenReturn(securityGroupVO);
         when(securityRule.getRuleType()).thenReturn(SecurityRule.SecurityRuleType.IngressRule);
-        when(securityRule.getType()).thenReturn("ingress");
         when(tungstenFabricUtils.sendTungstenCommand(any(RemoveTungstenSecurityGroupRuleCommand.class), anyLong())).thenReturn(removeTungstenSecurityGroupRuleAnswer);
         when(removeTungstenSecurityGroupRuleAnswer.getResult()).thenReturn(true);
         when(securityRule.getAllowedNetworkId()).thenReturn(null);
@@ -945,7 +943,6 @@
 
     @Test
     public void addTungstenPolicyRuleTest() throws Exception {
-        AddTungstenPolicyRuleCommand addTungstenPolicyRuleCommand = mock(AddTungstenPolicyRuleCommand.class);
         TungstenAnswer addTungstenPolicyRuleAnswer = mock(TungstenAnswer.class);
         NetworkPolicy networkPolicy = mock(NetworkPolicy.class);
         PolicyEntriesType policyEntriesType = mock(PolicyEntriesType.class);
@@ -962,8 +959,7 @@
         when(addTungstenPolicyRuleAnswer.getApiObjectBase()).thenReturn(networkPolicy);
         when(networkPolicy.getEntries()).thenReturn(policyEntriesType);
         when(policyEntriesType.getPolicyRule()).thenReturn(List.of(policyRuleType));
-        whenNew(AddTungstenPolicyRuleCommand.class).withAnyArguments().thenReturn(addTungstenPolicyRuleCommand);
-        PowerMockito.when(addTungstenPolicyRuleCommand, "getUuid").thenReturn("8b4637b6-5629-46de-8fb2-d0b0502bfa85");
+
         when(policyRuleType.getRuleUuid()).thenReturn("8b4637b6-5629-46de-8fb2-d0b0502bfa85");
         when(policyRuleType.getActionList()).thenReturn(actionListType);
         when(actionListType.getSimpleAction()).thenReturn("pass");
@@ -973,9 +969,15 @@
         when(policyRuleType.getDstAddresses()).thenReturn(List.of(addressType));
         when(policyRuleType.getDstPorts()).thenReturn(List.of(portType));
 
-        assertNotNull(tungstenService.addTungstenPolicyRule(1L, "948f421c-edde-4518-a391-09299cc25dc2", "pass",
-            "<>", "tcp", "network1", "192.168.100.100", 32, 80, 80,
-            "network2", "192.168.200.200", 32, 80, 80));
+        try (MockedConstruction<AddTungstenPolicyRuleCommand> ignored =
+                     Mockito.mockConstruction(AddTungstenPolicyRuleCommand.class, (mock, context) -> {
+                         when(mock.getUuid()).thenReturn("8b4637b6-5629-46de-8fb2-d0b0502bfa85");
+                     })) {
+
+            assertNotNull(tungstenService.addTungstenPolicyRule(1L, "948f421c-edde-4518-a391-09299cc25dc2", "pass",
+                    "<>", "tcp", "network1", "192.168.100.100", 32, 80, 80,
+                    "network2", "192.168.200.200", 32, 80, 80));
+        }
     }
 
     @Test
@@ -1189,7 +1191,6 @@
         doReturn(List.of(virtualMachine)).when(tungstenTag).getVirtualMachineList();
         doReturn(List.of(virtualMachineInterface)).when(tungstenTag).getVirtualMachineInterfaceList();
         doReturn(List.of(networkPolicy)).when(tungstenTag).getNetworkPolicyList();
-        doReturn(List.of(applicationPolicySet)).when(tungstenTag).getApplicationPolicySetList();
 
         assertNotNull(tungstenService.listTungstenTags(1L, "948f421c-edde-4518-a391-09299cc25dc2"
         , "8b4637b6-5629-46de-8fb2-d0b0502bfa85", "8d097a79-a38d-4db4-8a41-16f15d9c5afa", "a329662e-1805-4a89-9b05-2b818ea35978",
@@ -1616,10 +1617,6 @@
         when(vlan.getIp6Cidr()).thenReturn("fd00::1/64");
         when(vlan.getIp6Range()).thenReturn("fd00::100-fd00::200");
         when(getTungstenNetworkDnsAnswer.getDetails()).thenReturn("192.168.1.150");
-        when(network.getTrafficType()).thenReturn(Networks.TrafficType.Guest);
-        when(network.getGuestType()).thenReturn(Network.GuestType.Shared);
-        when(ipAddressDao.findByIpAndDcId(anyLong(), anyString())).thenReturn(ipAddressVO);
-        when(ipAddressDao.mark(anyLong(), any(Ip.class))).thenReturn(true);
         when(createTungstenSharedNetworkAnswer.getApiObjectBase()).thenReturn(apiObjectBase);
         when(apiObjectBase.getQualifiedName()).thenReturn(List.of("network"));
         when(tungstenProviderVO.getGateway()).thenReturn("192.168.100.1");
@@ -1648,7 +1645,6 @@
         when(tungstenFabricUtils.sendTungstenCommand(any(GetTungstenSecurityGroupCommand.class), anyLong())).thenReturn(getTungstenSecurityGroupAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(AddTungstenVmToSecurityGroupCommand.class), anyLong())).thenReturn(addTungstenVmToSecurityGroupAnswer);
         when(tungstenFabricUtils.sendTungstenCommand(any(AddTungstenSecurityGroupRuleCommand.class), anyLong())).thenReturn(addTungstenSecurityGroupRuleAnswer);
-        when(getTungstenSecurityGroupAnswer.getResult()).thenReturn(true);
         when(addTungstenVmToSecurityGroupAnswer.getResult()).thenReturn(true);
         when(addTungstenSecurityGroupRuleAnswer.getResult()).thenReturn(true);
         when(getTungstenSecurityGroupAnswer.getApiObjectBase()).thenReturn(securityGroup);
@@ -1678,22 +1674,6 @@
 
         when(dataCenterDao.findById(anyLong())).thenReturn(dataCenterVO);
         when(dataCenterVO.isSecurityGroupEnabled()).thenReturn(true);
-        when(securityGroupManager.getSecurityGroupsForVm(anyLong())).thenReturn(List.of(securityGroupVO));
-        when(tungstenFabricUtils.sendTungstenCommand(any(RemoveTungstenVmFromSecurityGroupCommand.class), anyLong())).thenReturn(removeTungstenVmFromSecurityGroupAnswer);
-        when(tungstenFabricUtils.sendTungstenCommand(any(RemoveTungstenSecurityGroupRuleCommand.class), anyLong())).thenReturn(removeTungstenSecurityGroupRuleAnswer);
-        when(removeTungstenVmFromSecurityGroupAnswer.getResult()).thenReturn(true);
-        when(removeTungstenSecurityGroupRuleAnswer.getResult()).thenReturn(true);
-        when(nicDao.findDefaultNicForVM(anyLong())).thenReturn(nicVO);
-        when(nicVO.getBroadcastUri()).thenReturn(Networks.BroadcastDomainType.TUNGSTEN.toUri("tf"));
-        when(securityGroupRuleDao.listByAllowedSecurityGroupId(anyLong())).thenReturn(List.of(securityGroupRuleVO));
-        when(nicVO.getIPv4Address()).thenReturn("192.168.100.100");
-        when(nicVO.getIPv6Address()).thenReturn("fd00::1");
-        when(nicVO.getSecondaryIp()).thenReturn(true);
-        when(nicSecIpDao.getSecondaryIpAddressesForNic(anyLong())).thenReturn(List.of("192.168.100.200"));
-        when(securityGroupRuleVO.getProtocol()).thenReturn(NetUtils.ALL_PROTO);
-        when(tungstenSecurityGroupRuleDao.expunge(anyLong())).thenReturn(true);
-        when(tungstenSecurityGroupRuleDao.listByRuleTarget(anyString())).thenReturn(List.of(tungstenSecurityGroupRuleVO));
-        when(securityGroupDao.findById(anyLong())).thenReturn(securityGroupVO);
 
         assertTrue(tungstenService.removeTungstenVmSecurityGroup(vmInstanceVO));
     }
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenVRouterApiTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenVRouterApiTest.java
index e717fbd..094ad96 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenVRouterApiTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/service/TungstenVRouterApiTest.java
@@ -20,27 +20,34 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.powermock.api.mockito.PowerMockito.mock;
-import static org.powermock.api.mockito.PowerMockito.mockStatic;
-import static org.powermock.api.mockito.PowerMockito.when;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import org.apache.cloudstack.network.tungsten.vrouter.Port;
 import org.apache.cloudstack.network.tungsten.vrouter.VRouterApiConnector;
 import org.apache.cloudstack.network.tungsten.vrouter.VRouterApiConnectorFactory;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.io.IOException;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(VRouterApiConnectorFactory.class)
+@RunWith(MockitoJUnitRunner.class)
 public class TungstenVRouterApiTest {
+    MockedStatic<VRouterApiConnectorFactory> vRouterApiConnectorFactoryMocked;
+
     @Before
     public void setup() {
-        mockStatic(VRouterApiConnectorFactory.class);
+        vRouterApiConnectorFactoryMocked = Mockito.mockStatic(VRouterApiConnectorFactory.class);
+    }
+
+    @After
+    public void tearDown() {
+        vRouterApiConnectorFactoryMocked.close();
     }
 
     @Test
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/vrouter/IntrospectApiConnectorImplTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/vrouter/IntrospectApiConnectorImplTest.java
index cf1cd68..85625ac 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/vrouter/IntrospectApiConnectorImplTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/vrouter/IntrospectApiConnectorImplTest.java
@@ -27,12 +27,13 @@
 import org.apache.http.client.methods.HttpUriRequest;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.w3c.dom.Document;
 import org.xml.sax.SAXException;
 
@@ -43,17 +44,26 @@
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({HttpClients.class, DocumentBuilderFactory.class})
+@RunWith(MockitoJUnitRunner.class)
 public class IntrospectApiConnectorImplTest {
     IntrospectApiConnector introspectApiConnector;
 
+    MockedStatic<HttpClients> httpClientsMocked;
+
+    MockedStatic<DocumentBuilderFactory> documentBuilderFactoryMocked;
+
     @Before
     public void setup() {
         VRouter vRouter = mock(VRouter.class);
         introspectApiConnector = new IntrospectApiConnectorImpl(vRouter);
-        PowerMockito.mockStatic(HttpClients.class);
-        PowerMockito.mockStatic(DocumentBuilderFactory.class);
+        httpClientsMocked =  Mockito.mockStatic(HttpClients.class);
+        documentBuilderFactoryMocked = Mockito.mockStatic(DocumentBuilderFactory.class);
+    }
+
+    @After
+    public void tearDown() {
+        httpClientsMocked.close();
+        documentBuilderFactoryMocked.close();
     }
 
     @Test
@@ -66,11 +76,11 @@
         DocumentBuilderFactory documentBuilderFactory = mock(DocumentBuilderFactory.class);
         DocumentBuilder documentBuilder = mock(DocumentBuilder.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(closeableHttpResponse);
         when(closeableHttpResponse.getEntity()).thenReturn(httpEntity);
         when(httpEntity.getContent()).thenReturn(inputStream);
-        when(DocumentBuilderFactory.newInstance()).thenReturn(documentBuilderFactory);
+        documentBuilderFactoryMocked.when(DocumentBuilderFactory::newInstance).thenReturn(documentBuilderFactory);
         when(documentBuilderFactory.newDocumentBuilder()).thenReturn(documentBuilder);
         when(documentBuilder.parse(any(InputStream.class))).thenReturn(document);
 
@@ -81,7 +91,7 @@
     public void getSnhItfReqWithIOExceptionTest() throws Exception {
         CloseableHttpClient httpClient = mock(CloseableHttpClient.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenThrow(IOException.class);
 
         assertNull(introspectApiConnector.getSnhItfReq("948f421c-edde-4518-a391-09299cc25dc2"));
@@ -95,11 +105,9 @@
         InputStream inputStream = mock(InputStream.class);
         DocumentBuilderFactory documentBuilderFactory = mock(DocumentBuilderFactory.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(closeableHttpResponse);
-        when(closeableHttpResponse.getEntity()).thenReturn(httpEntity);
-        when(httpEntity.getContent()).thenReturn(inputStream);
-        when(DocumentBuilderFactory.newInstance()).thenReturn(documentBuilderFactory);
+        documentBuilderFactoryMocked.when(DocumentBuilderFactory::newInstance).thenReturn(documentBuilderFactory);
         when(documentBuilderFactory.newDocumentBuilder()).thenThrow(ParserConfigurationException.class);
 
         assertNull(introspectApiConnector.getSnhItfReq("948f421c-edde-4518-a391-09299cc25dc2"));
@@ -114,11 +122,11 @@
         DocumentBuilderFactory documentBuilderFactory = mock(DocumentBuilderFactory.class);
         DocumentBuilder documentBuilder = mock(DocumentBuilder.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(closeableHttpResponse);
         when(closeableHttpResponse.getEntity()).thenReturn(httpEntity);
         when(httpEntity.getContent()).thenReturn(inputStream);
-        when(DocumentBuilderFactory.newInstance()).thenReturn(documentBuilderFactory);
+        documentBuilderFactoryMocked.when(DocumentBuilderFactory::newInstance).thenReturn(documentBuilderFactory);
         when(documentBuilderFactory.newDocumentBuilder()).thenReturn(documentBuilder);
         when(documentBuilder.parse(any(InputStream.class))).thenThrow(SAXException.class);
 
diff --git a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnectorImplTest.java b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnectorImplTest.java
index 11a2d9c..7006912 100644
--- a/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnectorImplTest.java
+++ b/plugins/network-elements/tungsten/src/test/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnectorImplTest.java
@@ -28,27 +28,37 @@
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.util.EntityUtils;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.io.IOException;
 import java.util.Arrays;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({HttpClients.class, EntityUtils.class})
+@RunWith(MockitoJUnitRunner.class)
 public class VRouterApiConnectorImplTest {
     VRouterApiConnector vRouterApiConnector;
 
+    MockedStatic<EntityUtils> entityUtilsMocked;
+
+    MockedStatic<HttpClients> httpClientsMocked;
+
     @Before
     public void setup() {
         VRouter vRouter = mock(VRouter.class);
         vRouterApiConnector = new VRouterApiConnectorImpl(vRouter);
-        PowerMockito.mockStatic(HttpClients.class);
-        PowerMockito.mockStatic(EntityUtils.class);
+        httpClientsMocked = Mockito.mockStatic(HttpClients.class);
+        entityUtilsMocked = Mockito.mockStatic(EntityUtils.class);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        httpClientsMocked.close();
+        entityUtilsMocked.close();
     }
 
     @Test
@@ -58,10 +68,10 @@
         CloseableHttpResponse closeableHttpResponse = mock(CloseableHttpResponse.class);
         HttpEntity httpEntity = mock(HttpEntity.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(closeableHttpResponse);
         when(closeableHttpResponse.getEntity()).thenReturn(httpEntity);
-        when(EntityUtils.toString(any(HttpEntity.class))).thenReturn("{}");
+        entityUtilsMocked.when(()-> EntityUtils.toString(any(HttpEntity.class))).thenReturn("{}");
 
         assertTrue(vRouterApiConnector.addPort(port));
     }
@@ -71,7 +81,7 @@
         Port port = mock(Port.class);
         CloseableHttpClient httpClient = mock(CloseableHttpClient.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenThrow(IOException.class);
 
         assertFalse(vRouterApiConnector.addPort(port));
@@ -84,10 +94,10 @@
         CloseableHttpResponse closeableHttpResponse = mock(CloseableHttpResponse.class);
         HttpEntity httpEntity = mock(HttpEntity.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(closeableHttpResponse);
         when(closeableHttpResponse.getEntity()).thenReturn(httpEntity);
-        when(EntityUtils.toString(any(HttpEntity.class))).thenReturn("{error:404}");
+        entityUtilsMocked.when(()-> EntityUtils.toString(any(HttpEntity.class))).thenReturn("{error:404}");
 
         assertFalse(vRouterApiConnector.addPort(port));
     }
@@ -98,10 +108,10 @@
         CloseableHttpResponse closeableHttpResponse = mock(CloseableHttpResponse.class);
         HttpEntity httpEntity = mock(HttpEntity.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(closeableHttpResponse);
         when(closeableHttpResponse.getEntity()).thenReturn(httpEntity);
-        when(EntityUtils.toString(any(HttpEntity.class))).thenReturn("{}");
+        entityUtilsMocked.when(()-> EntityUtils.toString(any(HttpEntity.class))).thenReturn("{}");
 
         assertTrue(vRouterApiConnector.deletePort("948f421c-edde-4518-a391-09299cc25dc2"));
     }
@@ -110,7 +120,7 @@
     public void deletePortWithExceptionTest() throws Exception {
         CloseableHttpClient httpClient = mock(CloseableHttpClient.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenThrow(IOException.class);
 
         assertFalse(vRouterApiConnector.deletePort("948f421c-edde-4518-a391-09299cc25dc2"));
@@ -122,10 +132,10 @@
         CloseableHttpResponse closeableHttpResponse = mock(CloseableHttpResponse.class);
         HttpEntity httpEntity = mock(HttpEntity.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(closeableHttpResponse);
         when(closeableHttpResponse.getEntity()).thenReturn(httpEntity);
-        when(EntityUtils.toString(any(HttpEntity.class))).thenReturn("{}");
+        entityUtilsMocked.when(()-> EntityUtils.toString(any(HttpEntity.class))).thenReturn("{}");
 
         assertTrue(vRouterApiConnector.enablePort("948f421c-edde-4518-a391-09299cc25dc2"));
     }
@@ -134,7 +144,7 @@
     public void enablePortWithExceptionTest() throws Exception {
         CloseableHttpClient httpClient = mock(CloseableHttpClient.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenThrow(IOException.class);
 
         assertFalse(vRouterApiConnector.enablePort("948f421c-edde-4518-a391-09299cc25dc2"));
@@ -146,10 +156,10 @@
         CloseableHttpResponse closeableHttpResponse = mock(CloseableHttpResponse.class);
         HttpEntity httpEntity = mock(HttpEntity.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(closeableHttpResponse);
         when(closeableHttpResponse.getEntity()).thenReturn(httpEntity);
-        when(EntityUtils.toString(any(HttpEntity.class))).thenReturn("{}");
+        entityUtilsMocked.when(()-> EntityUtils.toString(any(HttpEntity.class))).thenReturn("{}");
 
         assertTrue(vRouterApiConnector.disablePort("948f421c-edde-4518-a391-09299cc25dc2"));
     }
@@ -158,7 +168,7 @@
     public void disablePortWithExceptionTest() throws Exception {
         CloseableHttpClient httpClient = mock(CloseableHttpClient.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenThrow(IOException.class);
 
         assertFalse(vRouterApiConnector.disablePort("948f421c-edde-4518-a391-09299cc25dc2"));
@@ -172,10 +182,10 @@
         CloseableHttpResponse closeableHttpResponse = mock(CloseableHttpResponse.class);
         HttpEntity httpEntity = mock(HttpEntity.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(closeableHttpResponse);
         when(closeableHttpResponse.getEntity()).thenReturn(httpEntity);
-        when(EntityUtils.toString(any(HttpEntity.class))).thenReturn("{}");
+        entityUtilsMocked.when(()-> EntityUtils.toString(any(HttpEntity.class))).thenReturn("{}");
 
         assertTrue(vRouterApiConnector.addGateway(Arrays.asList(gateway1, gateway2)));
     }
@@ -186,7 +196,7 @@
         Gateway gateway2 = mock(Gateway.class);
         CloseableHttpClient httpClient = mock(CloseableHttpClient.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenThrow(IOException.class);
 
         assertFalse(vRouterApiConnector.addGateway(Arrays.asList(gateway1, gateway2)));
@@ -200,10 +210,10 @@
         CloseableHttpResponse closeableHttpResponse = mock(CloseableHttpResponse.class);
         HttpEntity httpEntity = mock(HttpEntity.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(closeableHttpResponse);
         when(closeableHttpResponse.getEntity()).thenReturn(httpEntity);
-        when(EntityUtils.toString(any(HttpEntity.class))).thenReturn("{}");
+        entityUtilsMocked.when(()-> EntityUtils.toString(any(HttpEntity.class))).thenReturn("{}");
 
         assertTrue(vRouterApiConnector.deleteGateway(Arrays.asList(gateway1, gateway2)));
     }
@@ -214,7 +224,7 @@
         Gateway gateway2 = mock(Gateway.class);
         CloseableHttpClient httpClient = mock(CloseableHttpClient.class);
 
-        when(HttpClients.createDefault()).thenReturn(httpClient);
+        httpClientsMocked.when(HttpClients::createDefault).thenReturn(httpClient);
         when(httpClient.execute(any(HttpUriRequest.class))).thenThrow(IOException.class);
 
         assertFalse(vRouterApiConnector.deleteGateway(Arrays.asList(gateway1, gateway2)));
diff --git a/plugins/network-elements/tungsten/src/test/resources/log4j.properties b/plugins/network-elements/tungsten/src/test/resources/log4j.properties
index 8c012b1..27276fc 100644
--- a/plugins/network-elements/tungsten/src/test/resources/log4j.properties
+++ b/plugins/network-elements/tungsten/src/test/resources/log4j.properties
@@ -32,4 +32,3 @@
 #log4j.category.com.cloud.utils.db.Transaction=ALL
 log4j.category.org.apache.cloudstack.network.contrail=ALL
 log4j.category.com.cloud.network=ALL
-
diff --git a/plugins/network-elements/tungsten/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/plugins/network-elements/tungsten/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d4
--- /dev/null
+++ b/plugins/network-elements/tungsten/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/plugins/network-elements/vxlan/pom.xml b/plugins/network-elements/vxlan/pom.xml
index 25e75da..a208ec2 100644
--- a/plugins/network-elements/vxlan/pom.xml
+++ b/plugins/network-elements/vxlan/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/network-elements/vxlan/src/main/resources/META-INF/cloudstack/vxlan/module.properties b/plugins/network-elements/vxlan/src/main/resources/META-INF/cloudstack/vxlan/module.properties
index 4c2c7f7..04457d8 100644
--- a/plugins/network-elements/vxlan/src/main/resources/META-INF/cloudstack/vxlan/module.properties
+++ b/plugins/network-elements/vxlan/src/main/resources/META-INF/cloudstack/vxlan/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=vxlan
-parent=network
\ No newline at end of file
+parent=network
diff --git a/plugins/outofbandmanagement-drivers/ipmitool/pom.xml b/plugins/outofbandmanagement-drivers/ipmitool/pom.xml
index 4ddc980..faf3f54 100644
--- a/plugins/outofbandmanagement-drivers/ipmitool/pom.xml
+++ b/plugins/outofbandmanagement-drivers/ipmitool/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/outofbandmanagement-drivers/nested-cloudstack/pom.xml b/plugins/outofbandmanagement-drivers/nested-cloudstack/pom.xml
index d8e4941..826d93d 100644
--- a/plugins/outofbandmanagement-drivers/nested-cloudstack/pom.xml
+++ b/plugins/outofbandmanagement-drivers/nested-cloudstack/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/outofbandmanagement-drivers/redfish/pom.xml b/plugins/outofbandmanagement-drivers/redfish/pom.xml
index 88dcdec..fd2bf0b 100644
--- a/plugins/outofbandmanagement-drivers/redfish/pom.xml
+++ b/plugins/outofbandmanagement-drivers/redfish/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/pom.xml b/plugins/pom.xml
index 6eea563..d0661c0 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
     </parent>
     <build>
         <plugins>
@@ -115,6 +115,8 @@
         <module>outofbandmanagement-drivers/nested-cloudstack</module>
         <module>outofbandmanagement-drivers/redfish</module>
 
+        <module>shutdown</module>
+
         <module>storage/image/default</module>
         <module>storage/image/s3</module>
         <module>storage/image/sample</module>
diff --git a/plugins/shutdown/pom.xml b/plugins/shutdown/pom.xml
new file mode 100644
index 0000000..0f34cc0
--- /dev/null
+++ b/plugins/shutdown/pom.xml
@@ -0,0 +1,44 @@
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>cloud-plugin-shutdown</artifactId>
+    <name>Apache CloudStack Plugin - Safe Shutdown</name>
+    <parent>
+        <groupId>org.apache.cloudstack</groupId>
+        <artifactId>cloudstack-plugins</artifactId>
+        <version>4.19.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.cloudstack</groupId>
+            <artifactId>cloud-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cloudstack</groupId>
+            <artifactId>cloud-utils</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/BaseShutdownActionCmd.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/BaseShutdownActionCmd.java
new file mode 100644
index 0000000..d7f4953
--- /dev/null
+++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/BaseShutdownActionCmd.java
@@ -0,0 +1,49 @@
+// 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.command;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+
+
+import org.apache.cloudstack.api.response.ManagementServerResponse;
+import org.apache.cloudstack.shutdown.ShutdownManager;
+
+public abstract class BaseShutdownActionCmd extends BaseCmd {
+
+    @Inject
+    protected ShutdownManager shutdownManager;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name = ApiConstants.MANAGEMENT_SERVER_ID, type = CommandType.UUID, entityType = ManagementServerResponse.class, description = "the uuid of the management server", required = true)
+    private Long managementServerId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getManagementServerId() {
+        return managementServerId;
+    }
+}
diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/CancelShutdownCmd.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/CancelShutdownCmd.java
new file mode 100644
index 0000000..fe6204f
--- /dev/null
+++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/CancelShutdownCmd.java
@@ -0,0 +1,62 @@
+// 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.command;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.log4j.Logger;
+
+import com.cloud.user.Account;
+
+import org.apache.cloudstack.api.response.ReadyForShutdownResponse;
+import org.apache.cloudstack.acl.RoleType;
+
+@APICommand(name = CancelShutdownCmd.APINAME,
+            description = "Cancels a triggered shutdown",
+            since = "4.19.0",
+            responseObject = ReadyForShutdownResponse.class,
+            requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+            authorized = {RoleType.Admin})
+
+public class CancelShutdownCmd extends BaseShutdownActionCmd {
+
+    public static final Logger LOG = Logger.getLogger(CancelShutdownCmd.class);
+    public static final String APINAME = "cancelShutdown";
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() {
+        final ReadyForShutdownResponse response = shutdownManager.cancelShutdown(this);
+        response.setResponseName(getCommandName());
+        response.setObjectName("cancelshutdown");
+        setResponseObject(response);
+    }
+}
diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/PrepareForShutdownCmd.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/PrepareForShutdownCmd.java
new file mode 100644
index 0000000..01ea179
--- /dev/null
+++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/PrepareForShutdownCmd.java
@@ -0,0 +1,61 @@
+// 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.command;
+
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.log4j.Logger;
+
+import com.cloud.user.Account;
+
+import org.apache.cloudstack.api.response.ReadyForShutdownResponse;
+import org.apache.cloudstack.acl.RoleType;
+
+@APICommand(name = PrepareForShutdownCmd.APINAME,
+            description = "Prepares CloudStack for a safe manual shutdown by preventing new jobs from being accepted",
+            since = "4.19.0",
+            responseObject = ReadyForShutdownResponse.class,
+            requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+            authorized = {RoleType.Admin})
+public class PrepareForShutdownCmd extends BaseShutdownActionCmd {
+    public static final Logger LOG = Logger.getLogger(PrepareForShutdownCmd.class);
+    public static final String APINAME = "prepareForShutdown";
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() {
+        final ReadyForShutdownResponse response = shutdownManager.prepareForShutdown(this);
+        response.setResponseName(getCommandName());
+        response.setObjectName("prepareforshutdown");
+        setResponseObject(response);
+    }
+}
diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/ReadyForShutdownCmd.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/ReadyForShutdownCmd.java
new file mode 100644
index 0000000..d7ab6a2
--- /dev/null
+++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/ReadyForShutdownCmd.java
@@ -0,0 +1,80 @@
+// 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.command;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.ManagementServerResponse;
+import org.apache.cloudstack.api.response.ReadyForShutdownResponse;
+import org.apache.cloudstack.shutdown.ShutdownManager;
+import org.apache.log4j.Logger;
+import com.cloud.user.Account;
+
+@APICommand(name = ReadyForShutdownCmd.APINAME,
+            description = "Returs the status of CloudStack, whether a shutdown has been triggered and if ready to shutdown",
+            since = "4.19.0",
+            responseObject = ReadyForShutdownResponse.class,
+            requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class ReadyForShutdownCmd extends BaseCmd {
+    public static final Logger LOG = Logger.getLogger(ReadyForShutdownCmd.class);
+    public static final String APINAME = "readyForShutdown";
+
+    @Inject
+    private ShutdownManager shutdownManager;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name = ApiConstants.MANAGEMENT_SERVER_ID, type = CommandType.UUID, entityType = ManagementServerResponse.class, description = "the uuid of the management server")
+    private Long managementServerId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getManagementServerId() {
+        return managementServerId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() {
+        final ReadyForShutdownResponse response = shutdownManager.readyForShutdown(this);
+        response.setResponseName(getCommandName());
+        response.setObjectName("readyforshutdown");
+        setResponseObject(response);
+    }
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+}
diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/TriggerShutdownCmd.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/TriggerShutdownCmd.java
new file mode 100644
index 0000000..3abde0b
--- /dev/null
+++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/command/TriggerShutdownCmd.java
@@ -0,0 +1,64 @@
+// 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.command;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.log4j.Logger;
+
+import com.cloud.user.Account;
+
+import org.apache.cloudstack.api.response.ReadyForShutdownResponse;
+import org.apache.cloudstack.acl.RoleType;
+
+@APICommand(name = TriggerShutdownCmd.APINAME,
+            description = "Triggers an automatic safe shutdown of CloudStack by not accepting new jobs and shutting down when all pending jobbs have been completed. Triggers an immediate shutdown if forced",
+            since = "4.19.0",
+            responseObject = ReadyForShutdownResponse.class,
+            requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+            authorized = {RoleType.Admin})
+public class TriggerShutdownCmd extends BaseShutdownActionCmd {
+    public static final Logger LOG = Logger.getLogger(TriggerShutdownCmd.class);
+    public static final String APINAME = "triggerShutdown";
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() {
+        final ReadyForShutdownResponse response = shutdownManager.triggerShutdown(this);
+        response.setResponseName(getCommandName());
+        response.setObjectName("triggershutdown");
+        setResponseObject(response);
+    }
+}
diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/api/response/ReadyForShutdownResponse.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/response/ReadyForShutdownResponse.java
new file mode 100644
index 0000000..d1b2353
--- /dev/null
+++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/response/ReadyForShutdownResponse.java
@@ -0,0 +1,81 @@
+// 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.response;
+
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+
+public class ReadyForShutdownResponse extends BaseResponse {
+    @SerializedName(ApiConstants.READY_FOR_SHUTDOWN)
+    @Param(description = "Indicates whether CloudStack is ready to shutdown")
+    private Boolean readyForShutdown;
+
+    @SerializedName(ApiConstants.SHUTDOWN_TRIGGERED)
+    @Param(description = "Indicates whether a shutdown has been triggered")
+    private Boolean shutdownTriggered;
+
+    @SerializedName(ApiConstants.PENDING_JOBS_COUNT)
+    @Param(description = "The number of jobs in progress")
+    private Long pendingJobsCount;
+
+    @SerializedName(ApiConstants.MANAGEMENT_SERVER_ID)
+    @Param(description = "The id of the management server")
+    private Long msId;
+
+    public ReadyForShutdownResponse(Long msId, Boolean shutdownTriggered, Boolean readyForShutdown, long pendingJobsCount) {
+        this.msId = msId;
+        this.shutdownTriggered = shutdownTriggered;
+        this.readyForShutdown = readyForShutdown;
+        this.pendingJobsCount = pendingJobsCount;
+    }
+
+    public Boolean getShutdownTriggered() {
+        return this.shutdownTriggered;
+    }
+
+    public void setShutdownTriggered(Boolean shutdownTriggered) {
+        this.shutdownTriggered = shutdownTriggered;
+    }
+
+    public Boolean getReadyForShutdown() {
+        return this.readyForShutdown;
+    }
+
+    public void setReadyForShutdown(Boolean readyForShutdown) {
+        this.readyForShutdown = readyForShutdown;
+    }
+
+    public Long getPendingJobsCount() {
+        return this.pendingJobsCount;
+    }
+
+    public void setPendingJobsCount(Long pendingJobsCount) {
+        this.pendingJobsCount = pendingJobsCount;
+    }
+
+    public Long getMsId() {
+        return msId;
+    }
+
+    public void setMsId(Long msId) {
+        this.msId = msId;
+    }
+}
diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/ShutdownManager.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/ShutdownManager.java
new file mode 100644
index 0000000..22f43cb
--- /dev/null
+++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/ShutdownManager.java
@@ -0,0 +1,60 @@
+// 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.shutdown;
+
+import org.apache.cloudstack.api.command.CancelShutdownCmd;
+import org.apache.cloudstack.api.command.PrepareForShutdownCmd;
+import org.apache.cloudstack.api.command.ReadyForShutdownCmd;
+import org.apache.cloudstack.api.command.TriggerShutdownCmd;
+import org.apache.cloudstack.api.response.ReadyForShutdownResponse;
+
+public interface ShutdownManager {
+    // Returns the number of pending jobs for the given Management server msids.
+    // NOTE: This is the msid and NOT the id
+    long countPendingJobs(Long... msIds);
+
+    // Indicates whether a shutdown has been triggered on the current management server
+    boolean isShutdownTriggered();
+
+    // Indicates whether the current management server is preparing to shutdown
+    boolean isPreparingForShutdown();
+
+    // Triggers a shutdown on the current management server by not accepting any more async jobs and shutting down when there are no pending jobs
+    void triggerShutdown();
+
+    // Prepares the current management server to shutdown by not accepting any more async jobs
+    void prepareForShutdown();
+
+    // Cancels the shutdown on the current management server
+    void cancelShutdown();
+
+    // Returns whether the given ms can be shut down
+    ReadyForShutdownResponse readyForShutdown(Long managementserverid);
+
+    // Returns whether the any of the ms can be shut down and if a shutdown has been triggered on any running ms
+    ReadyForShutdownResponse readyForShutdown(ReadyForShutdownCmd cmd);
+
+    // Prepares the specified management server to shutdown by not accepting any more async jobs
+    ReadyForShutdownResponse prepareForShutdown(PrepareForShutdownCmd cmd);
+
+    // Cancels the shutdown on the specified management server
+    ReadyForShutdownResponse cancelShutdown(CancelShutdownCmd cmd);
+
+    // Triggers a shutdown on the specified management server by not accepting any more async jobs and shutting down when there are no pending jobs
+    ReadyForShutdownResponse triggerShutdown(TriggerShutdownCmd cmd);
+}
diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/ShutdownManagerImpl.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/ShutdownManagerImpl.java
new file mode 100644
index 0000000..b8f5fb5
--- /dev/null
+++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/ShutdownManagerImpl.java
@@ -0,0 +1,265 @@
+// 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.shutdown;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.command.CancelShutdownCmd;
+import org.apache.cloudstack.api.command.PrepareForShutdownCmd;
+import org.apache.cloudstack.api.command.ReadyForShutdownCmd;
+import org.apache.cloudstack.api.command.TriggerShutdownCmd;
+import org.apache.cloudstack.api.response.ReadyForShutdownResponse;
+import org.apache.cloudstack.framework.jobs.AsyncJobManager;
+import org.apache.cloudstack.management.ManagementServerHost.State;
+import org.apache.cloudstack.shutdown.command.CancelShutdownManagementServerHostCommand;
+import org.apache.cloudstack.shutdown.command.PrepareForShutdownManagementServerHostCommand;
+import org.apache.cloudstack.shutdown.command.TriggerShutdownManagementServerHostCommand;
+import org.apache.cloudstack.utils.identity.ManagementServerNode;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Command;
+import com.cloud.cluster.ClusterManager;
+import com.cloud.cluster.ManagementServerHostVO;
+import com.cloud.cluster.dao.ManagementServerHostDao;
+import com.cloud.serializer.GsonHelper;
+import com.cloud.utils.component.ManagerBase;
+import com.cloud.utils.component.PluggableService;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.google.gson.Gson;
+
+public class ShutdownManagerImpl extends ManagerBase implements ShutdownManager, PluggableService{
+
+    private static Logger logger = Logger.getLogger(ShutdownManagerImpl.class);
+    Gson gson;
+
+    @Inject
+    private AsyncJobManager jobManager;
+    @Inject
+    private ManagementServerHostDao msHostDao;
+    @Inject
+    private ClusterManager clusterManager;
+
+    private boolean shutdownTriggered = false;
+    private boolean preparingForShutdown = false;
+
+    private Timer timer = new Timer();
+    private TimerTask shutdownTask;
+
+    protected ShutdownManagerImpl() {
+        super();
+        gson = GsonHelper.getGson();
+    }
+
+    @Override
+    public boolean isShutdownTriggered() {
+        return shutdownTriggered;
+    }
+
+    @Override
+    public boolean isPreparingForShutdown() {
+        return preparingForShutdown;
+    }
+
+    @Override
+    public long countPendingJobs(Long... msIds) {
+        return jobManager.countPendingNonPseudoJobs(msIds);
+    }
+
+    @Override
+    public void triggerShutdown() {
+        if (this.shutdownTriggered) {
+            throw new CloudRuntimeException("A shutdown has already been triggered");
+        }
+        this.shutdownTriggered = true;
+        prepareForShutdown(true);
+    }
+
+    private void prepareForShutdown(boolean postTrigger) {
+        // Ensure we don't throw an error if triggering a shutdown after just preparing for it
+        if (!postTrigger && this.preparingForShutdown) {
+            throw new CloudRuntimeException("A shutdown has already been triggered");
+        }
+        this.preparingForShutdown = true;
+        jobManager.disableAsyncJobs();
+        if (this.shutdownTask != null) {
+            this.shutdownTask.cancel();
+            this.shutdownTask = null;
+        }
+        this.shutdownTask = new ShutdownTask(this);
+        timer.scheduleAtFixedRate(shutdownTask, 0, 30L * 1000);
+    }
+
+    @Override
+    public void prepareForShutdown() {
+        prepareForShutdown(false);
+    }
+
+    @Override
+    public void cancelShutdown() {
+        if (!this.preparingForShutdown) {
+            throw new CloudRuntimeException("A shutdown has not been triggered");
+        }
+
+        this.preparingForShutdown = false;
+        this.shutdownTriggered = false;
+        jobManager.enableAsyncJobs();
+        if (shutdownTask != null) {
+            shutdownTask.cancel();
+        }
+        shutdownTask = null;
+    }
+
+    @Override
+    public ReadyForShutdownResponse readyForShutdown(Long managementserverid) {
+        Long[] msIds = null;
+        boolean shutdownTriggeredAnywhere = false;
+        State[] shutdownTriggeredStates = {State.ShuttingDown, State.PreparingToShutDown, State.ReadyToShutDown};
+        if (managementserverid == null) {
+            List<ManagementServerHostVO> msHosts = msHostDao.listBy(shutdownTriggeredStates);
+            if (msHosts != null && !msHosts.isEmpty()) {
+                msIds = new Long[msHosts.size()];
+                for (int i = 0; i < msHosts.size(); i++) {
+                    msIds[i] = msHosts.get(i).getMsid();
+                }
+                shutdownTriggeredAnywhere = !msHosts.isEmpty();
+            }
+        } else {
+            ManagementServerHostVO msHost = msHostDao.findById(managementserverid);
+            msIds = new Long[]{msHost.getMsid()};
+            shutdownTriggeredAnywhere = Arrays.asList(shutdownTriggeredStates).contains(msHost.getState());
+        }
+        long pendingJobCount = countPendingJobs(msIds);
+        return new ReadyForShutdownResponse(managementserverid, shutdownTriggeredAnywhere, pendingJobCount == 0, pendingJobCount);
+    }
+
+    @Override
+    public ReadyForShutdownResponse readyForShutdown(ReadyForShutdownCmd cmd) {
+        return readyForShutdown(cmd.getManagementServerId());
+    }
+
+    @Override
+    public ReadyForShutdownResponse prepareForShutdown(PrepareForShutdownCmd cmd) {
+        ManagementServerHostVO msHost = msHostDao.findById(cmd.getManagementServerId());
+        final Command[] cmds = new Command[1];
+        cmds[0] = new PrepareForShutdownManagementServerHostCommand(msHost.getMsid());
+        String result = clusterManager.execute(String.valueOf(msHost.getMsid()), 0, gson.toJson(cmds), true);
+        logger.info("PrepareForShutdownCmd result : " + result);
+        if (!result.contains("Success")) {
+            throw new CloudRuntimeException(result);
+        }
+
+        msHost.setState(State.PreparingToShutDown);
+        msHostDao.persist(msHost);
+
+        return readyForShutdown(cmd.getManagementServerId());
+    }
+
+    @Override
+    public ReadyForShutdownResponse triggerShutdown(TriggerShutdownCmd cmd) {
+        ManagementServerHostVO msHost = msHostDao.findById(cmd.getManagementServerId());
+        final Command[] cmds = new Command[1];
+        cmds[0] = new TriggerShutdownManagementServerHostCommand(msHost.getMsid());
+        String result = clusterManager.execute(String.valueOf(msHost.getMsid()), 0, gson.toJson(cmds), true);
+        logger.info("TriggerShutdownCmd result : " + result);
+        if (!result.contains("Success")) {
+            throw new CloudRuntimeException(result);
+        }
+
+        msHost.setState(State.ShuttingDown);
+        msHostDao.persist(msHost);
+
+        return readyForShutdown(cmd.getManagementServerId());
+    }
+
+    @Override
+    public ReadyForShutdownResponse cancelShutdown(CancelShutdownCmd cmd) {
+        ManagementServerHostVO msHost = msHostDao.findById(cmd.getManagementServerId());
+        final Command[] cmds = new Command[1];
+        cmds[0] = new CancelShutdownManagementServerHostCommand(msHost.getMsid());
+        String result = clusterManager.execute(String.valueOf(msHost.getMsid()), 0, gson.toJson(cmds), true);
+        logger.info("CancelShutdownCmd result : " + result);
+        if (!result.contains("Success")) {
+            throw new CloudRuntimeException(result);
+        }
+
+        msHost.setState(State.Up);
+        msHostDao.persist(msHost);
+
+        return readyForShutdown(cmd.getManagementServerId());
+    }
+
+    @Override
+    public List<Class<?>> getCommands() {
+        final List<Class<?>> cmdList = new ArrayList<>();
+        cmdList.add(CancelShutdownCmd.class);
+        cmdList.add(PrepareForShutdownCmd.class);
+        cmdList.add(ReadyForShutdownCmd.class);
+        cmdList.add(TriggerShutdownCmd.class);
+        return cmdList;
+    }
+
+    private final class ShutdownTask extends TimerTask {
+
+        private ShutdownManager shutdownManager;
+
+        public ShutdownTask(ShutdownManager shutdownManager) {
+            this.shutdownManager = shutdownManager;
+        }
+
+        @Override
+        public void run() {
+            try {
+                Long totalPendingJobs = shutdownManager.countPendingJobs(ManagementServerNode.getManagementServerId());
+                String msg = String.format("Checking for triggered shutdown... shutdownTriggered [%b] AllowAsyncJobs [%b] PendingJobCount [%d]",
+                    shutdownManager.isShutdownTriggered(), shutdownManager.isPreparingForShutdown(), totalPendingJobs);
+                logger.info(msg);
+
+                // If the shutdown has been cancelled
+                if (!shutdownManager.isPreparingForShutdown()) {
+                    logger.info("Shutdown cancelled. Terminating the shutdown timer task");
+                    this.cancel();
+                    return;
+                }
+
+                // No more pending jobs. Good to terminate
+                if (totalPendingJobs == 0) {
+                    if (shutdownManager.isShutdownTriggered()) {
+                        logger.info("Shutting down now");
+                        System.exit(0);
+                    }
+                    if (shutdownManager.isPreparingForShutdown()) {
+                        logger.info("Ready to shutdown");
+                        ManagementServerHostVO msHost = msHostDao.findByMsid(ManagementServerNode.getManagementServerId());
+                        msHost.setState(State.ReadyToShutDown);
+                        msHostDao.persist(msHost);
+                    }
+                }
+
+                logger.info("Pending jobs. Trying again later");
+            } catch (final Exception e) {
+                logger.error("Error trying to run shutdown task", e);
+            }
+        }
+    }
+}
diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/command/BaseShutdownManagementServerHostCommand.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/command/BaseShutdownManagementServerHostCommand.java
new file mode 100644
index 0000000..8fe3331
--- /dev/null
+++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/command/BaseShutdownManagementServerHostCommand.java
@@ -0,0 +1,38 @@
+// 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.shutdown.command;
+
+import com.cloud.agent.api.Command;
+
+public class BaseShutdownManagementServerHostCommand extends Command {
+    long msId;
+
+    public BaseShutdownManagementServerHostCommand(long msId) {
+        this.msId = msId;
+    }
+
+    public long getMsId() {
+        return msId;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return false;
+    }
+}
diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/command/CancelShutdownManagementServerHostCommand.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/command/CancelShutdownManagementServerHostCommand.java
new file mode 100644
index 0000000..eef4444
--- /dev/null
+++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/command/CancelShutdownManagementServerHostCommand.java
@@ -0,0 +1,27 @@
+// 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.shutdown.command;
+
+public class CancelShutdownManagementServerHostCommand extends BaseShutdownManagementServerHostCommand {
+
+    public CancelShutdownManagementServerHostCommand(long msId) {
+        super(msId);
+    }
+
+}
diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/command/PrepareForShutdownManagementServerHostCommand.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/command/PrepareForShutdownManagementServerHostCommand.java
new file mode 100644
index 0000000..32a9201d
--- /dev/null
+++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/command/PrepareForShutdownManagementServerHostCommand.java
@@ -0,0 +1,26 @@
+// 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.shutdown.command;
+
+public class PrepareForShutdownManagementServerHostCommand extends BaseShutdownManagementServerHostCommand {
+
+    public PrepareForShutdownManagementServerHostCommand(long msId) {
+        super(msId);
+    }
+}
diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/command/TriggerShutdownManagementServerHostCommand.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/command/TriggerShutdownManagementServerHostCommand.java
new file mode 100644
index 0000000..e0d1879
--- /dev/null
+++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/command/TriggerShutdownManagementServerHostCommand.java
@@ -0,0 +1,26 @@
+// 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.shutdown.command;
+
+public class TriggerShutdownManagementServerHostCommand extends BaseShutdownManagementServerHostCommand {
+
+    public TriggerShutdownManagementServerHostCommand(long msId) {
+        super(msId);
+    }
+}
diff --git a/plugins/shutdown/src/main/resources/META-INF/cloudstack/shutdown/module.properties b/plugins/shutdown/src/main/resources/META-INF/cloudstack/shutdown/module.properties
new file mode 100644
index 0000000..fd85c30
--- /dev/null
+++ b/plugins/shutdown/src/main/resources/META-INF/cloudstack/shutdown/module.properties
@@ -0,0 +1,18 @@
+# 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.
+name=shutdown
+parent=api
diff --git a/plugins/shutdown/src/main/resources/META-INF/cloudstack/shutdown/spring-shutdown-context.xml b/plugins/shutdown/src/main/resources/META-INF/cloudstack/shutdown/spring-shutdown-context.xml
new file mode 100644
index 0000000..5318b3b
--- /dev/null
+++ b/plugins/shutdown/src/main/resources/META-INF/cloudstack/shutdown/spring-shutdown-context.xml
@@ -0,0 +1,29 @@
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd"
+>
+
+    <bean id="shutdownManager" class="org.apache.cloudstack.shutdown.ShutdownManagerImpl" >
+      <property name="name" value="shutdownManager" />
+    </bean>
+
+</beans>
diff --git a/plugins/shutdown/src/test/java/org/apache/cloudstack/shutdown/ShutdownManagerImplTest.java b/plugins/shutdown/src/test/java/org/apache/cloudstack/shutdown/ShutdownManagerImplTest.java
new file mode 100644
index 0000000..19ded78
--- /dev/null
+++ b/plugins/shutdown/src/test/java/org/apache/cloudstack/shutdown/ShutdownManagerImplTest.java
@@ -0,0 +1,78 @@
+// 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.shutdown;
+
+import org.apache.cloudstack.framework.jobs.AsyncJobManager;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+
+
+@RunWith(MockitoJUnitRunner.class)
+public class ShutdownManagerImplTest {
+
+    @Spy
+    @InjectMocks
+    ShutdownManagerImpl spy;
+
+    @Mock
+    AsyncJobManager jobManagerMock;
+
+    private long prepareCountPendingJobs() {
+        long expectedCount = 1L;
+        Mockito.doReturn(expectedCount).when(jobManagerMock).countPendingNonPseudoJobs(1L);
+        return expectedCount;
+    }
+
+    @Test
+    public void countPendingJobs() {
+        long expectedCount = prepareCountPendingJobs();
+        long count = spy.countPendingJobs(1L);
+        Assert.assertEquals(expectedCount, count);
+    }
+
+    @Test
+    public void cancelShutdown() {
+        Assert.assertThrows(CloudRuntimeException.class, () -> {
+            spy.cancelShutdown();
+        });
+    }
+
+    @Test
+    public void prepareForShutdown() {
+        Mockito.doNothing().when(jobManagerMock).disableAsyncJobs();
+        spy.prepareForShutdown();
+        Mockito.verify(jobManagerMock).disableAsyncJobs();
+
+        Assert.assertThrows(CloudRuntimeException.class, () -> {
+            spy.prepareForShutdown();
+        });
+
+
+        Mockito.doNothing().when(jobManagerMock).enableAsyncJobs();
+        spy.cancelShutdown();
+        Mockito.verify(jobManagerMock).enableAsyncJobs();
+    }
+}
diff --git a/plugins/storage-allocators/random/pom.xml b/plugins/storage-allocators/random/pom.xml
index e68b0cb..a745f47 100644
--- a/plugins/storage-allocators/random/pom.xml
+++ b/plugins/storage-allocators/random/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/storage/image/default/pom.xml b/plugins/storage/image/default/pom.xml
index bd75e1c..4f2b1ab 100644
--- a/plugins/storage/image/default/pom.xml
+++ b/plugins/storage/image/default/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
@@ -53,9 +53,6 @@
         <plugins>
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <skipTests>true</skipTests>
-                </configuration>
                 <executions>
                     <execution>
                         <phase>integration-test</phase>
diff --git a/plugins/storage/image/default/src/main/resources/META-INF/cloudstack/storage-image-default/module.properties b/plugins/storage/image/default/src/main/resources/META-INF/cloudstack/storage-image-default/module.properties
index 8381f6e..4bdbee2 100644
--- a/plugins/storage/image/default/src/main/resources/META-INF/cloudstack/storage-image-default/module.properties
+++ b/plugins/storage/image/default/src/main/resources/META-INF/cloudstack/storage-image-default/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=storage-image-default
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/plugins/storage/image/s3/pom.xml b/plugins/storage/image/s3/pom.xml
index dc01305..de4457f 100644
--- a/plugins/storage/image/s3/pom.xml
+++ b/plugins/storage/image/s3/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/storage/image/s3/src/main/resources/META-INF/cloudstack/storage-image-s3/module.properties b/plugins/storage/image/s3/src/main/resources/META-INF/cloudstack/storage-image-s3/module.properties
index da571e2..6efe32c 100644
--- a/plugins/storage/image/s3/src/main/resources/META-INF/cloudstack/storage-image-s3/module.properties
+++ b/plugins/storage/image/s3/src/main/resources/META-INF/cloudstack/storage-image-s3/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=storage-image-s3
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/plugins/storage/image/sample/pom.xml b/plugins/storage/image/sample/pom.xml
index db0f377..29bb514 100644
--- a/plugins/storage/image/sample/pom.xml
+++ b/plugins/storage/image/sample/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
@@ -53,9 +53,6 @@
         <plugins>
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <skipTests>true</skipTests>
-                </configuration>
                 <executions>
                     <execution>
                         <phase>integration-test</phase>
diff --git a/plugins/storage/image/swift/pom.xml b/plugins/storage/image/swift/pom.xml
index 473b6ab..5f2563b 100644
--- a/plugins/storage/image/swift/pom.xml
+++ b/plugins/storage/image/swift/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
@@ -53,9 +53,6 @@
         <plugins>
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <skipTests>true</skipTests>
-                </configuration>
                 <executions>
                     <execution>
                         <phase>integration-test</phase>
diff --git a/plugins/storage/image/swift/src/main/resources/META-INF/cloudstack/storage-image-swift/module.properties b/plugins/storage/image/swift/src/main/resources/META-INF/cloudstack/storage-image-swift/module.properties
index 1fa4be6..9cd56e7 100644
--- a/plugins/storage/image/swift/src/main/resources/META-INF/cloudstack/storage-image-swift/module.properties
+++ b/plugins/storage/image/swift/src/main/resources/META-INF/cloudstack/storage-image-swift/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=storage-image-swift
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/plugins/storage/volume/cloudbyte/pom.xml b/plugins/storage/volume/cloudbyte/pom.xml
index 2c9b0ba..2313bfd 100644
--- a/plugins/storage/volume/cloudbyte/pom.xml
+++ b/plugins/storage/volume/cloudbyte/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
@@ -57,9 +57,6 @@
         <plugins>
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <skipTests>true</skipTests>
-                </configuration>
                 <executions>
                     <execution>
                         <phase>integration-test</phase>
diff --git a/plugins/storage/volume/cloudbyte/src/main/resources/META-INF/cloudstack/storage-volume-cloudbyte/module.properties b/plugins/storage/volume/cloudbyte/src/main/resources/META-INF/cloudstack/storage-volume-cloudbyte/module.properties
index 92cd58f..c494608 100755
--- a/plugins/storage/volume/cloudbyte/src/main/resources/META-INF/cloudstack/storage-volume-cloudbyte/module.properties
+++ b/plugins/storage/volume/cloudbyte/src/main/resources/META-INF/cloudstack/storage-volume-cloudbyte/module.properties
@@ -18,4 +18,4 @@
 #
 
 name=storage-volume-cloudbyte
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/plugins/storage/volume/datera/pom.xml b/plugins/storage/volume/datera/pom.xml
index 5c734bb..e3a53e7 100644
--- a/plugins/storage/volume/datera/pom.xml
+++ b/plugins/storage/volume/datera/pom.xml
@@ -16,7 +16,7 @@
   <parent>
     <groupId>org.apache.cloudstack</groupId>
     <artifactId>cloudstack-plugins</artifactId>
-    <version>4.18.1.0-SNAPSHOT</version>
+    <version>4.19.0.0-SNAPSHOT</version>
     <relativePath>../../../pom.xml</relativePath>
   </parent>
   <dependencies>
@@ -49,9 +49,6 @@
     <plugins>
       <plugin>
         <artifactId>maven-surefire-plugin</artifactId>
-        <configuration>
-          <skipTests>true</skipTests>
-        </configuration>
         <executions>
           <execution>
             <phase>integration-test</phase>
diff --git a/plugins/storage/volume/default/pom.xml b/plugins/storage/volume/default/pom.xml
index 6572c09..66f9f6b 100644
--- a/plugins/storage/volume/default/pom.xml
+++ b/plugins/storage/volume/default/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
@@ -38,9 +38,6 @@
         <plugins>
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <skipTests>true</skipTests>
-                </configuration>
                 <executions>
                     <execution>
                         <phase>integration-test</phase>
diff --git a/plugins/storage/volume/default/src/main/resources/META-INF/cloudstack/storage-volume-default/module.properties b/plugins/storage/volume/default/src/main/resources/META-INF/cloudstack/storage-volume-default/module.properties
index 6136988..e596415 100644
--- a/plugins/storage/volume/default/src/main/resources/META-INF/cloudstack/storage-volume-default/module.properties
+++ b/plugins/storage/volume/default/src/main/resources/META-INF/cloudstack/storage-volume-default/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=storage-volume-default
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/plugins/storage/volume/default/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImplTest.java b/plugins/storage/volume/default/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImplTest.java
index ffdc514..dbd13d8 100644
--- a/plugins/storage/volume/default/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImplTest.java
+++ b/plugins/storage/volume/default/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImplTest.java
@@ -23,6 +23,7 @@
 import com.cloud.agent.api.ModifyStoragePoolAnswer;
 import com.cloud.agent.api.ModifyStoragePoolCommand;
 import com.cloud.agent.api.StoragePoolInfo;
+import com.cloud.exception.StorageConflictException;
 import com.cloud.host.Host;
 import com.cloud.host.HostVO;
 import com.cloud.host.Status;
@@ -32,7 +33,6 @@
 import com.cloud.storage.Storage;
 import com.cloud.storage.StorageManager;
 import com.cloud.storage.StorageManagerImpl;
-import com.cloud.storage.StoragePoolHostVO;
 import com.cloud.storage.dao.StoragePoolHostDao;
 import junit.framework.TestCase;
 import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
@@ -45,8 +45,9 @@
 import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
-import org.apache.cloudstack.storage.datastore.provider.DefaultHostListener;
 import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
+import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -54,8 +55,8 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
 import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -64,8 +65,6 @@
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 /**
@@ -77,7 +76,6 @@
     @InjectMocks
     PrimaryDataStoreLifeCycle _cloudStackPrimaryDataStoreLifeCycle = new CloudStackPrimaryDataStoreLifeCycleImpl();
 
-    @Spy
     @InjectMocks
     StorageManager storageMgr = new StorageManagerImpl();
 
@@ -93,9 +91,8 @@
     @Mock
     DataStoreProviderManager _dataStoreProviderMgr;
 
-    @Spy
-    @InjectMocks
-    HypervisorHostListener hostListener = new DefaultHostListener();
+    @Mock
+    HypervisorHostListener hostListener;
 
     @Mock
     StoragePoolHostDao storagePoolHostDao;
@@ -121,10 +118,16 @@
     @Mock
     PrimaryDataStoreHelper primaryDataStoreHelper;
 
-    @Before
-    public void initMocks() {
+    AutoCloseable closeable;
 
-        MockitoAnnotations.initMocks(this);
+    @Before
+    public void initMocks() throws StorageConflictException {
+        closeable = MockitoAnnotations.openMocks(this);
+
+        ReflectionTestUtils.setField(storageMgr, "_storagePoolDao", primaryStoreDao);
+        ReflectionTestUtils.setField(storageMgr, "_dataStoreProviderMgr", _dataStoreProviderMgr);
+        ReflectionTestUtils.setField(storageMgr, "_dataStoreMgr", _dataStoreMgr);
+        ReflectionTestUtils.setField(_cloudStackPrimaryDataStoreLifeCycle, "storageMgr", storageMgr);
 
         List<HostVO> hostList = new ArrayList<HostVO>();
         HostVO host1 = new HostVO(1L, "aa01", Host.Type.Routing, "192.168.1.1", "255.255.255.0", null, null, null, null, null, null, null, null, null, null,
@@ -141,30 +144,31 @@
         when(store.getPoolType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
         when(store.isShared()).thenReturn(true);
         when(store.getName()).thenReturn("newPool");
+        when(store.getStorageProviderName()).thenReturn("default");
+
 
         when(_dataStoreProviderMgr.getDataStoreProvider(anyString())).thenReturn(dataStoreProvider);
         when(dataStoreProvider.getName()).thenReturn("default");
-        ((StorageManagerImpl)storageMgr).registerHostListener("default", hostListener);
+
+        when(hostListener.hostConnect(Mockito.anyLong(), Mockito.anyLong())).thenReturn(true);
+        storageMgr.registerHostListener("default", hostListener);
+
 
         when(_resourceMgr.listAllUpHosts(eq(Host.Type.Routing), anyLong(), anyLong(), anyLong())).thenReturn(hostList);
         when(agentMgr.easySend(anyLong(), Mockito.any(ModifyStoragePoolCommand.class))).thenReturn(answer);
         when(answer.getResult()).thenReturn(true);
-        when(answer.getPoolInfo()).thenReturn(info);
 
-        when(info.getLocalPath()).thenReturn("/mnt/1");
-        when(info.getCapacityBytes()).thenReturn(0L);
-        when(info.getAvailableBytes()).thenReturn(0L);
-
-        when(storagePoolHostDao.findByPoolHost(anyLong(), anyLong())).thenReturn(null);
         when(primaryStoreDao.findById(anyLong())).thenReturn(storagePool);
-        when(primaryStoreDao.update(anyLong(), Mockito.any(StoragePoolVO.class))).thenReturn(true);
         when(primaryDataStoreHelper.attachCluster(Mockito.any(DataStore.class))).thenReturn(null);
     }
 
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
+    }
+
     @Test
     public void testAttachCluster() throws Exception {
-        _cloudStackPrimaryDataStoreLifeCycle.attachCluster(store, new ClusterScope(1L, 1L, 1L));
-        verify(storagePoolHostDao,times(2)).persist(Mockito.any(StoragePoolHostVO.class));
-
+        Assert.assertTrue(_cloudStackPrimaryDataStoreLifeCycle.attachCluster(store, new ClusterScope(1L, 1L, 1L)));
     }
 }
diff --git a/plugins/storage/volume/linstor/pom.xml b/plugins/storage/volume/linstor/pom.xml
index 3efda9d..69de4ff 100644
--- a/plugins/storage/volume/linstor/pom.xml
+++ b/plugins/storage/volume/linstor/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
@@ -48,9 +48,6 @@
         <plugins>
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <skipTests>true</skipTests>
-                </configuration>
                 <executions>
                     <execution>
                         <phase>integration-test</phase>
diff --git a/plugins/storage/volume/nexenta/pom.xml b/plugins/storage/volume/nexenta/pom.xml
index e6ff46f..33c0ffe 100644
--- a/plugins/storage/volume/nexenta/pom.xml
+++ b/plugins/storage/volume/nexenta/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
@@ -38,9 +38,6 @@
         <plugins>
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <skipTests>true</skipTests>
-                </configuration>
                 <executions>
                     <execution>
                         <phase>integration-test</phase>
diff --git a/plugins/storage/volume/nexenta/src/main/resources/META-INF.cloudstack.storage-volume-solidfire/module.properties b/plugins/storage/volume/nexenta/src/main/resources/META-INF.cloudstack.storage-volume-solidfire/module.properties
index c203600..fe95f28 100644
--- a/plugins/storage/volume/nexenta/src/main/resources/META-INF.cloudstack.storage-volume-solidfire/module.properties
+++ b/plugins/storage/volume/nexenta/src/main/resources/META-INF.cloudstack.storage-volume-solidfire/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=storage-volume-nexenta
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/plugins/storage/volume/nexenta/src/main/resources/META-INF.cloudstack.storage-volume-solidfire/spring-storage-volume-nexenta-context.xml b/plugins/storage/volume/nexenta/src/main/resources/META-INF.cloudstack.storage-volume-solidfire/spring-storage-volume-nexenta-context.xml
index 52032e1..c1dae74 100644
--- a/plugins/storage/volume/nexenta/src/main/resources/META-INF.cloudstack.storage-volume-solidfire/spring-storage-volume-nexenta-context.xml
+++ b/plugins/storage/volume/nexenta/src/main/resources/META-INF.cloudstack.storage-volume-solidfire/spring-storage-volume-nexenta-context.xml
@@ -29,4 +29,4 @@
   <bean id="nexentaStorDataStoreProvider"
         class="org.apache.cloudstack.storage.datastore.provider.NexentaPrimaryDataStoreProvider" />
 
-</beans>
\ No newline at end of file
+</beans>
diff --git a/plugins/storage/volume/nexenta/src/test/java/org/apache/cloudstack/storage/datastore/util/NexentaStorApplianceTest.java b/plugins/storage/volume/nexenta/src/test/java/org/apache/cloudstack/storage/datastore/util/NexentaStorApplianceTest.java
index 6dc59eb..749c04b 100644
--- a/plugins/storage/volume/nexenta/src/test/java/org/apache/cloudstack/storage/datastore/util/NexentaStorApplianceTest.java
+++ b/plugins/storage/volume/nexenta/src/test/java/org/apache/cloudstack/storage/datastore/util/NexentaStorApplianceTest.java
@@ -119,7 +119,6 @@
         when(client.execute(ListOfStringsNmsResponse.class, "stmf", "list_targetgroups")).thenReturn(null);
         assertFalse(appliance.isIscsiTargetGroupExists(targetGroup));
 
-        when(client.execute(ListOfIscsiTargetsNmsResponse.class, "stmf", "list_targetgroups")).thenReturn(new ListOfIscsiTargetsNmsResponse());
         assertFalse(appliance.isIscsiTargetGroupExists(targetGroup));
 
         LinkedList<String> result = new LinkedList<String>();
diff --git a/plugins/storage/volume/sample/pom.xml b/plugins/storage/volume/sample/pom.xml
index 79013c8..bb96b60 100644
--- a/plugins/storage/volume/sample/pom.xml
+++ b/plugins/storage/volume/sample/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
@@ -38,9 +38,6 @@
         <plugins>
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <skipTests>true</skipTests>
-                </configuration>
                 <executions>
                     <execution>
                         <phase>integration-test</phase>
diff --git a/plugins/storage/volume/scaleio/pom.xml b/plugins/storage/volume/scaleio/pom.xml
index cff8048..390d11b 100644
--- a/plugins/storage/volume/scaleio/pom.xml
+++ b/plugins/storage/volume/scaleio/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
@@ -44,9 +44,6 @@
         <plugins>
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <skipTests>true</skipTests>
-                </configuration>
                 <executions>
                     <execution>
                         <phase>integration-test</phase>
diff --git a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImplTest.java b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImplTest.java
index 577b918..cf624c2 100644
--- a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImplTest.java
+++ b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImplTest.java
@@ -48,7 +48,7 @@
 
 @RunWith(MockitoJUnitRunner.class)
 public class ScaleIOGatewayClientImplTest {
-    private final int port = 443;
+    private final int port = 8443;
     private final int timeout = 30;
     private final int maxConnections = 50;
     private final String username = "admin";
@@ -70,7 +70,7 @@
                         .withHeader("content-type", "application/json;charset=UTF-8")
                         .withBody(sessionKey)));
 
-        client = new ScaleIOGatewayClientImpl("https://localhost/api", username, password, false, timeout, maxConnections);
+        client = new ScaleIOGatewayClientImpl(String.format("https://localhost:%d/api", port), username, password, false, timeout, maxConnections);
 
         wireMockRule.stubFor(post("/api/types/Volume/instances")
                 .willReturn(aResponse()
diff --git a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriverTest.java b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriverTest.java
index d147582..1852ec1 100644
--- a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriverTest.java
+++ b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriverTest.java
@@ -49,28 +49,29 @@
 import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.storage.to.VolumeObjectTO;
+import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.Optional;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.when;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(RemoteHostEndPoint.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ScaleIOPrimaryDataStoreDriverTest {
 
     @Spy
@@ -93,6 +94,18 @@
     @Mock
     ConfigurationDao configDao;
 
+    static MockedStatic<RemoteHostEndPoint> remoteHostEndPointMock;
+
+    @BeforeClass
+    public static void init() {
+        remoteHostEndPointMock = mockStatic(RemoteHostEndPoint.class);
+    }
+
+    @AfterClass
+    public static void close() {
+        remoteHostEndPointMock.close();
+    }
+
     @Before
     public void initMocks() {
         MockitoAnnotations.initMocks(this);
@@ -180,9 +193,8 @@
         VolumeObjectTO destVolTO = Mockito.mock(VolumeObjectTO.class);
         when(destData.getTO()).thenReturn(destVolTO);
         Host host = prepareEndpointForVolumeOperation(srcData);
-        PowerMockito.mockStatic(RemoteHostEndPoint.class);
         RemoteHostEndPoint ep = Mockito.mock(RemoteHostEndPoint.class);
-        when(RemoteHostEndPoint.getHypervisorHostEndPoint(host)).thenReturn(ep);
+        remoteHostEndPointMock.when(() -> RemoteHostEndPoint.getHypervisorHostEndPoint(host)).thenReturn(ep);
 
         DataTO dataTO = Mockito.mock(DataTO.class);
         CreateObjectAnswer createAnswer = new CreateObjectAnswer(dataTO);
@@ -225,9 +237,8 @@
         VolumeObjectTO destVolTO = Mockito.mock(VolumeObjectTO.class);
         when(destData.getTO()).thenReturn(destVolTO);
         Host host = prepareEndpointForVolumeOperation(srcData);
-        PowerMockito.mockStatic(RemoteHostEndPoint.class);
         RemoteHostEndPoint ep = Mockito.mock(RemoteHostEndPoint.class);
-        when(RemoteHostEndPoint.getHypervisorHostEndPoint(host)).thenReturn(ep);
+        remoteHostEndPointMock.when(() -> RemoteHostEndPoint.getHypervisorHostEndPoint(host)).thenReturn(ep);
 
         DataTO dataTO = Mockito.mock(DataTO.class);
         CreateObjectAnswer createAnswer = new CreateObjectAnswer(dataTO);
@@ -493,9 +504,8 @@
         Host destHost = Mockito.mock(Host.class);
 
         doReturn(false).when(scaleIOPrimaryDataStoreDriver).anyVolumeRequiresEncryption(srcData, destData);
-        PowerMockito.mockStatic(RemoteHostEndPoint.class);
         RemoteHostEndPoint ep = Mockito.mock(RemoteHostEndPoint.class);
-        when(RemoteHostEndPoint.getHypervisorHostEndPoint(destHost)).thenReturn(ep);
+        remoteHostEndPointMock.when(() -> RemoteHostEndPoint.getHypervisorHostEndPoint(destHost)).thenReturn(ep);
         Answer answer = Mockito.mock(Answer.class);
         when(ep.sendMessage(any())).thenReturn(answer);
 
@@ -517,8 +527,7 @@
         Host destHost = Mockito.mock(Host.class);
 
         doReturn(false).when(scaleIOPrimaryDataStoreDriver).anyVolumeRequiresEncryption(srcData, destData);
-        PowerMockito.mockStatic(RemoteHostEndPoint.class);
-        when(RemoteHostEndPoint.getHypervisorHostEndPoint(destHost)).thenReturn(null);
+        remoteHostEndPointMock.when(() -> RemoteHostEndPoint.getHypervisorHostEndPoint(destHost)).thenReturn(null);
 
         Answer answer = scaleIOPrimaryDataStoreDriver.copyOfflineVolume(srcData, destData, destHost);
 
diff --git a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycleTest.java b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycleTest.java
index 6cc7b87..4a6e73a 100644
--- a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycleTest.java
+++ b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycleTest.java
@@ -24,8 +24,7 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
 
@@ -40,13 +39,11 @@
 import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
 import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
-import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClient;
 import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClientConnectionPool;
 import org.apache.cloudstack.storage.datastore.client.ScaleIOGatewayClientImpl;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
-import org.apache.cloudstack.storage.datastore.provider.ScaleIOHostListener;
 import org.apache.cloudstack.storage.datastore.util.ScaleIOUtil;
 import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
 import org.junit.Before;
@@ -54,19 +51,13 @@
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
-import org.mockito.Spy;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
-import com.cloud.agent.AgentManager;
-import com.cloud.agent.api.ModifyStoragePoolAnswer;
-import com.cloud.agent.api.ModifyStoragePoolCommand;
 import com.cloud.host.Host;
 import com.cloud.host.HostVO;
 import com.cloud.host.Status;
-import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor;
 import com.cloud.resource.ResourceManager;
 import com.cloud.resource.ResourceState;
@@ -80,9 +71,9 @@
 import com.cloud.storage.dao.StoragePoolHostDao;
 import com.cloud.template.TemplateManager;
 import com.cloud.utils.exception.CloudRuntimeException;
+import org.springframework.test.util.ReflectionTestUtils;
 
-@PrepareForTest(ScaleIOGatewayClient.class)
-@RunWith(PowerMockRunner.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ScaleIOPrimaryDataStoreLifeCycleTest {
 
     @Mock
@@ -96,8 +87,6 @@
     @Mock
     private StoragePoolAutomation storagePoolAutomation;
     @Mock
-    private HostDao hostDao;
-    @Mock
     private StoragePoolHostDao storagePoolHostDao;
     @Mock
     private DataStoreProviderManager dataStoreProviderMgr;
@@ -109,18 +98,12 @@
     private PrimaryDataStore store;
     @Mock
     private TemplateManager templateMgr;
-    @Mock
-    private AgentManager agentMgr;
-    @Mock
-    ModifyStoragePoolAnswer answer;
 
-    @Spy
     @InjectMocks
     private StorageManager storageMgr = new StorageManagerImpl();
 
-    @Spy
-    @InjectMocks
-    private HypervisorHostListener hostListener = new ScaleIOHostListener();
+    @Mock
+    private HypervisorHostListener hostListener;
 
     @InjectMocks
     private ScaleIOPrimaryDataStoreLifeCycle scaleIOPrimaryDataStoreLifeCycleTest;
@@ -128,6 +111,7 @@
     @Before
     public void setUp() {
         initMocks(this);
+        ReflectionTestUtils.setField(scaleIOPrimaryDataStoreLifeCycleTest, "storageMgr", storageMgr);
     }
 
     @Test
@@ -135,9 +119,11 @@
         final DataStore dataStore = mock(DataStore.class);
         when(dataStore.getId()).thenReturn(1L);
 
-        PowerMockito.mockStatic(ScaleIOGatewayClient.class);
+        MockedStatic<ScaleIOGatewayClientConnectionPool> scaleIOGatewayClientConnectionPoolMocked = mockStatic(ScaleIOGatewayClientConnectionPool.class);
         ScaleIOGatewayClientImpl client = mock(ScaleIOGatewayClientImpl.class);
-        when(ScaleIOGatewayClientConnectionPool.getInstance().getClient(1L, storagePoolDetailsDao)).thenReturn(client);
+        ScaleIOGatewayClientConnectionPool pool = mock(ScaleIOGatewayClientConnectionPool.class);
+        scaleIOGatewayClientConnectionPoolMocked.when(() -> ScaleIOGatewayClientConnectionPool.getInstance()).thenReturn(pool);
+        when(pool.getClient(1L, storagePoolDetailsDao)).thenReturn(client);
 
         when(client.haveConnectedSdcs()).thenReturn(true);
 
@@ -157,28 +143,19 @@
 
         when(dataStoreMgr.getDataStore(anyLong(), eq(DataStoreRole.Primary))).thenReturn(store);
         when(store.getId()).thenReturn(1L);
-        when(store.getPoolType()).thenReturn(Storage.StoragePoolType.PowerFlex);
         when(store.isShared()).thenReturn(true);
         when(store.getName()).thenReturn("ScaleIOPool");
         when(store.getStorageProviderName()).thenReturn(ScaleIOUtil.PROVIDER_NAME);
 
         when(dataStoreProviderMgr.getDataStoreProvider(ScaleIOUtil.PROVIDER_NAME)).thenReturn(dataStoreProvider);
         when(dataStoreProvider.getName()).thenReturn(ScaleIOUtil.PROVIDER_NAME);
+        when(hostListener.hostConnect(Mockito.anyLong(), Mockito.anyLong())).thenReturn(true);
         storageMgr.registerHostListener(ScaleIOUtil.PROVIDER_NAME, hostListener);
 
-        when(agentMgr.easySend(anyLong(), Mockito.any(ModifyStoragePoolCommand.class))).thenReturn(answer);
-        when(answer.getResult()).thenReturn(true);
-
-        when(storagePoolHostDao.findByPoolHost(anyLong(), anyLong())).thenReturn(null);
-
-        when(hostDao.findById(1L)).thenReturn(host1);
-        when(hostDao.findById(2L)).thenReturn(host2);
-
         when(dataStoreHelper.attachZone(Mockito.any(DataStore.class))).thenReturn(null);
 
-        scaleIOPrimaryDataStoreLifeCycleTest.attachZone(dataStore, scope, Hypervisor.HypervisorType.KVM);
-        verify(storageMgr,times(2)).connectHostToSharedPool(Mockito.any(Long.class), Mockito.any(Long.class));
-        verify(storagePoolHostDao,times(2)).persist(Mockito.any(StoragePoolHostVO.class));
+        boolean result = scaleIOPrimaryDataStoreLifeCycleTest.attachZone(dataStore, scope, Hypervisor.HypervisorType.KVM);
+        assertThat(result).isTrue();
     }
 
     @Test(expected = CloudRuntimeException.class)
@@ -224,7 +201,6 @@
     public void testDeleteDataStoreWithStoragePoolNull() {
         final PrimaryDataStore store = mock(PrimaryDataStore.class);
         when(primaryDataStoreDao.findById(anyLong())).thenReturn(null);
-        when(dataStoreHelper.deletePrimaryDataStore(any(DataStore.class))).thenReturn(true);
         final boolean result = scaleIOPrimaryDataStoreLifeCycleTest.deleteDataStore(store);
         assertThat(result).isFalse();
     }
@@ -233,6 +209,7 @@
     public void testDeleteDataStore() {
         final PrimaryDataStore store = mock(PrimaryDataStore.class);
         final StoragePoolVO storagePoolVO = mock(StoragePoolVO.class);
+        when(store.getId()).thenReturn(1L);
         when(primaryDataStoreDao.findById(anyLong())).thenReturn(storagePoolVO);
         List<VMTemplateStoragePoolVO> unusedTemplates = new ArrayList<>();
         when(templateMgr.getUnusedTemplatesInPool(storagePoolVO)).thenReturn(unusedTemplates);
diff --git a/plugins/storage/volume/scaleio/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/plugins/storage/volume/scaleio/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d4
--- /dev/null
+++ b/plugins/storage/volume/scaleio/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/plugins/storage/volume/solidfire/pom.xml b/plugins/storage/volume/solidfire/pom.xml
index 1d1db53..1c54522 100644
--- a/plugins/storage/volume/solidfire/pom.xml
+++ b/plugins/storage/volume/solidfire/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/storage/volume/solidfire/src/main/resources/META-INF/cloudstack/storage-volume-solidfire/module.properties b/plugins/storage/volume/solidfire/src/main/resources/META-INF/cloudstack/storage-volume-solidfire/module.properties
index 335a9d2..72b2e03 100644
--- a/plugins/storage/volume/solidfire/src/main/resources/META-INF/cloudstack/storage-volume-solidfire/module.properties
+++ b/plugins/storage/volume/solidfire/src/main/resources/META-INF/cloudstack/storage-volume-solidfire/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=storage-volume-solidfire
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/plugins/storage/volume/storpool/pom.xml b/plugins/storage/volume/storpool/pom.xml
index ee4c5cf..0914a4d 100644
--- a/plugins/storage/volume/storpool/pom.xml
+++ b/plugins/storage/volume/storpool/pom.xml
@@ -17,7 +17,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <dependencies>
@@ -71,9 +71,6 @@
         <plugins>
             <plugin>
                 <artifactId>maven-surefire-plugin</artifactId>
-                <configuration>
-                    <skipTests>true</skipTests>
-                </configuration>
                 <executions>
                     <execution>
                         <phase>integration-test</phase>
diff --git a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolUtil.java b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolUtil.java
index a7ff626..3a428ef 100644
--- a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolUtil.java
+++ b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/util/StorPoolUtil.java
@@ -54,6 +54,8 @@
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.sql.Timestamp;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -67,7 +69,10 @@
 public class StorPoolUtil {
     private static final Logger log = Logger.getLogger(StorPoolUtil.class);
 
-    private static final File spLogFile = new File("/var/log/cloudstack/management/storpool-plugin.log");
+    private static final File spLogFile = new File(
+            Files.exists(Paths.get("/var/log/cloudstack/management/")) ?
+                    "/var/log/cloudstack/management/storpool-plugin.log" :
+                    "/tmp/storpool-plugin.log");
     private static PrintWriter spLogPrinterWriter = spLogFileInitialize();
 
     private static PrintWriter spLogFileInitialize() {
diff --git a/plugins/storage/volume/storpool/src/test/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriverTest.java b/plugins/storage/volume/storpool/src/test/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriverTest.java
index 356cac9..b862695 100644
--- a/plugins/storage/volume/storpool/src/test/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriverTest.java
+++ b/plugins/storage/volume/storpool/src/test/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriverTest.java
@@ -47,18 +47,16 @@
 import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 import org.mockito.junit.MockitoJUnitRunner;
-import org.powermock.core.classloader.annotations.PrepareForTest;
 
 import java.util.UUID;
 
 import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
-import static org.powermock.api.mockito.PowerMockito.mock;
 
 
 @RunWith(MockitoJUnitRunner.class)
-@PrepareForTest(StorPoolUtil.class)
 public class StorPoolPrimaryDataStoreDriverTest {
 
     @Mock
diff --git a/plugins/user-authenticators/ldap/pom.xml b/plugins/user-authenticators/ldap/pom.xml
index deed063..6ccbfa8 100644
--- a/plugins/user-authenticators/ldap/pom.xml
+++ b/plugins/user-authenticators/ldap/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 
diff --git a/plugins/user-authenticators/ldap/src/main/resources/META-INF/cloudstack/ldap/module.properties b/plugins/user-authenticators/ldap/src/main/resources/META-INF/cloudstack/ldap/module.properties
index 4659ab5..7194ac4 100644
--- a/plugins/user-authenticators/ldap/src/main/resources/META-INF/cloudstack/ldap/module.properties
+++ b/plugins/user-authenticators/ldap/src/main/resources/META-INF/cloudstack/ldap/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=ldap
-parent=api
\ No newline at end of file
+parent=api
diff --git a/plugins/user-authenticators/ldap/src/test/groovy/org/apache/cloudstack/ldap/LdapUserSpec.groovy b/plugins/user-authenticators/ldap/src/test/groovy/org/apache/cloudstack/ldap/LdapUserSpec.groovy
index 36b37ca..769f623 100644
--- a/plugins/user-authenticators/ldap/src/test/groovy/org/apache/cloudstack/ldap/LdapUserSpec.groovy
+++ b/plugins/user-authenticators/ldap/src/test/groovy/org/apache/cloudstack/ldap/LdapUserSpec.groovy
@@ -107,4 +107,4 @@
 	where: "The username is set to "
 	domain << ["", null, "engineering"]
     }
-}
\ No newline at end of file
+}
diff --git a/plugins/user-authenticators/ldap/src/test/groovy/org/apache/cloudstack/ldap/NoLdapUserMatchingQueryExceptionSpec.groovy b/plugins/user-authenticators/ldap/src/test/groovy/org/apache/cloudstack/ldap/NoLdapUserMatchingQueryExceptionSpec.groovy
index 4c0cc4b..93c91e3 100644
--- a/plugins/user-authenticators/ldap/src/test/groovy/org/apache/cloudstack/ldap/NoLdapUserMatchingQueryExceptionSpec.groovy
+++ b/plugins/user-authenticators/ldap/src/test/groovy/org/apache/cloudstack/ldap/NoLdapUserMatchingQueryExceptionSpec.groovy
@@ -27,4 +27,4 @@
         where: "The username is set to "
         query << ["", null, "murp*"]
     }
-}
\ No newline at end of file
+}
diff --git a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapCreateAccountCmdTest.java b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapCreateAccountCmdTest.java
index 6bc81b7..b96a007 100644
--- a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapCreateAccountCmdTest.java
+++ b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapCreateAccountCmdTest.java
@@ -32,8 +32,8 @@
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.ArgumentMatchers.nullable;
-import static org.powermock.api.mockito.PowerMockito.spy;
-import static org.powermock.api.mockito.PowerMockito.when;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
 public class LdapCreateAccountCmdTest implements LdapConfigurationChanger {
diff --git a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapImportUsersCmdTest.java b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapImportUsersCmdTest.java
index 55310f9..594c23f 100644
--- a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapImportUsersCmdTest.java
+++ b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapImportUsersCmdTest.java
@@ -40,8 +40,8 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
-import static org.powermock.api.mockito.PowerMockito.spy;
-import static org.powermock.api.mockito.PowerMockito.when;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
 public class LdapImportUsersCmdTest implements LdapConfigurationChanger {
diff --git a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapListUsersCmdTest.java b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapListUsersCmdTest.java
index 6203c53..11d99f5 100644
--- a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapListUsersCmdTest.java
+++ b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LdapListUsersCmdTest.java
@@ -31,14 +31,14 @@
 import org.apache.cloudstack.ldap.LdapUser;
 import org.apache.cloudstack.ldap.NoLdapUserMatchingQueryException;
 import org.apache.cloudstack.query.QueryService;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -50,16 +50,13 @@
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.powermock.api.mockito.PowerMockito.doReturn;
-import static org.powermock.api.mockito.PowerMockito.doThrow;
-import static org.powermock.api.mockito.PowerMockito.spy;
-import static org.powermock.api.mockito.PowerMockito.when;
+import static org.mockito.Mockito.when;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(CallContext.class)
-@PowerMockIgnore({"javax.xml.*", "org.w3c.dom.*", "org.apache.xerces.*", "org.xml.*"})
+@RunWith(MockitoJUnitRunner.class)
 public class LdapListUsersCmdTest implements LdapConfigurationChanger {
 
     public static final String LOCAL_DOMAIN_ID = "12345678-90ab-cdef-fedc-ba0987654321";
@@ -76,23 +73,30 @@
 
     Domain localDomain;
 
+    MockedStatic<CallContext> callContextMocked;
+
     @Before
     public void setUp() throws NoSuchFieldException, IllegalAccessException {
         ldapListUsersCmd = new LdapListUsersCmd(ldapManager, queryService);
         cmdSpy = spy(ldapListUsersCmd);
 
-        PowerMockito.mockStatic(CallContext.class);
-        CallContext callContextMock = PowerMockito.mock(CallContext.class);
-        PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
-        Account accountMock = PowerMockito.mock(Account.class);
-        PowerMockito.when(accountMock.getDomainId()).thenReturn(1l);
-        PowerMockito.when(callContextMock.getCallingAccount()).thenReturn(accountMock);
+        callContextMocked = Mockito.mockStatic(CallContext.class);
+        CallContext callContextMock = Mockito.mock(CallContext.class);
+        callContextMocked.when(CallContext::current).thenReturn(callContextMock);
+        Account accountMock = Mockito.mock(Account.class);
+        when(accountMock.getDomainId()).thenReturn(1l);
+        when(callContextMock.getCallingAccount()).thenReturn(accountMock);
 
         ldapListUsersCmd._domainService = domainService;
 
 // no need to        setHiddenField(ldapListUsersCmd, .... );
     }
 
+    @After
+    public void tearDown() throws Exception {
+        callContextMocked.close();
+    }
+
     /**
      * given: "We have an LdapManager, QueryService and LdapListUsersCmd"
      *  when: "Get entity owner id is called"
@@ -114,7 +118,7 @@
      */
     @Test
     public void successfulEmptyResponseFromExecute() throws NoLdapUserMatchingQueryException {
-        doThrow(new NoLdapUserMatchingQueryException("")).when(ldapManager).getUsers(null);
+        Mockito.doThrow(new NoLdapUserMatchingQueryException("")).when(ldapManager).getUsers(null);
         ldapListUsersCmd.execute();
         assertEquals(0, ((ListResponse)ldapListUsersCmd.getResponseObject()).getResponses().size());
     }
diff --git a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LinkAccountToLdapCmdTest.java b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LinkAccountToLdapCmdTest.java
index 1a00a05..e355d77 100644
--- a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LinkAccountToLdapCmdTest.java
+++ b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LinkAccountToLdapCmdTest.java
@@ -36,7 +36,7 @@
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.isNull;
-import static org.powermock.api.mockito.PowerMockito.when;
+import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
 public class LinkAccountToLdapCmdTest implements LdapConfigurationChanger {
diff --git a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LinkDomainToLdapCmdTest.java b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LinkDomainToLdapCmdTest.java
index 04594e2..204e985 100644
--- a/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LinkDomainToLdapCmdTest.java
+++ b/plugins/user-authenticators/ldap/src/test/java/org/apache/cloudstack/api/command/LinkDomainToLdapCmdTest.java
@@ -35,7 +35,7 @@
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.isNull;
-import static org.powermock.api.mockito.PowerMockito.when;
+import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
 public class LinkDomainToLdapCmdTest implements LdapConfigurationChanger
diff --git a/plugins/user-authenticators/ldap/src/test/resources/cloudstack.org.ldif b/plugins/user-authenticators/ldap/src/test/resources/cloudstack.org.ldif
index 4078372..ad677bc 100644
--- a/plugins/user-authenticators/ldap/src/test/resources/cloudstack.org.ldif
+++ b/plugins/user-authenticators/ldap/src/test/resources/cloudstack.org.ldif
@@ -308,4 +308,3 @@
 mail: cpetri@cloudstack.org
 uid: cpetri
 userpassword:: cGFzc3dvcmQ=
-
diff --git a/plugins/user-authenticators/ldap/src/test/resources/ldapunit.ldif b/plugins/user-authenticators/ldap/src/test/resources/ldapunit.ldif
index a6c1da1..e2e7f99 100644
--- a/plugins/user-authenticators/ldap/src/test/resources/ldapunit.ldif
+++ b/plugins/user-authenticators/ldap/src/test/resources/ldapunit.ldif
@@ -148,4 +148,4 @@
 sn: User
 givenName: demo
 mail: d@b.c
-uid: noadmin
\ No newline at end of file
+uid: noadmin
diff --git a/plugins/user-authenticators/ldap/src/test/resources/minimal.ldif b/plugins/user-authenticators/ldap/src/test/resources/minimal.ldif
index 46e87c2..035c216 100644
--- a/plugins/user-authenticators/ldap/src/test/resources/minimal.ldif
+++ b/plugins/user-authenticators/ldap/src/test/resources/minimal.ldif
@@ -240,4 +240,3 @@
 inetUserStatus: Active
 mail: d@b.c
 uid: noadmin
-
diff --git a/plugins/user-authenticators/ldap/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/plugins/user-authenticators/ldap/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d4
--- /dev/null
+++ b/plugins/user-authenticators/ldap/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/plugins/user-authenticators/ldap/src/test/resources/unboundid.ldif b/plugins/user-authenticators/ldap/src/test/resources/unboundid.ldif
index 4078372..ad677bc 100644
--- a/plugins/user-authenticators/ldap/src/test/resources/unboundid.ldif
+++ b/plugins/user-authenticators/ldap/src/test/resources/unboundid.ldif
@@ -308,4 +308,3 @@
 mail: cpetri@cloudstack.org
 uid: cpetri
 userpassword:: cGFzc3dvcmQ=
-
diff --git a/plugins/user-authenticators/md5/pom.xml b/plugins/user-authenticators/md5/pom.xml
index 718dd31..084471b 100644
--- a/plugins/user-authenticators/md5/pom.xml
+++ b/plugins/user-authenticators/md5/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/user-authenticators/md5/src/main/resources/META-INF/cloudstack/md5/module.properties b/plugins/user-authenticators/md5/src/main/resources/META-INF/cloudstack/md5/module.properties
index 03ba739..c79f1b6 100644
--- a/plugins/user-authenticators/md5/src/main/resources/META-INF/cloudstack/md5/module.properties
+++ b/plugins/user-authenticators/md5/src/main/resources/META-INF/cloudstack/md5/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=md5
-parent=api
\ No newline at end of file
+parent=api
diff --git a/plugins/user-authenticators/pbkdf2/pom.xml b/plugins/user-authenticators/pbkdf2/pom.xml
index 8dcf9c9..154e811 100644
--- a/plugins/user-authenticators/pbkdf2/pom.xml
+++ b/plugins/user-authenticators/pbkdf2/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/user-authenticators/plain-text/pom.xml b/plugins/user-authenticators/plain-text/pom.xml
index 153ad94..4529e0c 100644
--- a/plugins/user-authenticators/plain-text/pom.xml
+++ b/plugins/user-authenticators/plain-text/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/user-authenticators/plain-text/src/main/resources/META-INF/cloudstack/plaintext/module.properties b/plugins/user-authenticators/plain-text/src/main/resources/META-INF/cloudstack/plaintext/module.properties
index 5a29563..1ff77da 100644
--- a/plugins/user-authenticators/plain-text/src/main/resources/META-INF/cloudstack/plaintext/module.properties
+++ b/plugins/user-authenticators/plain-text/src/main/resources/META-INF/cloudstack/plaintext/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=plaintext
-parent=api
\ No newline at end of file
+parent=api
diff --git a/plugins/user-authenticators/saml2/pom.xml b/plugins/user-authenticators/saml2/pom.xml
index 2d47e67..cbcd511 100644
--- a/plugins/user-authenticators/saml2/pom.xml
+++ b/plugins/user-authenticators/saml2/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/plugins/user-authenticators/sha256salted/pom.xml b/plugins/user-authenticators/sha256salted/pom.xml
index 32342d7..f202855 100644
--- a/plugins/user-authenticators/sha256salted/pom.xml
+++ b/plugins/user-authenticators/sha256salted/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/plugins/user-authenticators/sha256salted/src/main/resources/META-INF/cloudstack/sha256salted/module.properties b/plugins/user-authenticators/sha256salted/src/main/resources/META-INF/cloudstack/sha256salted/module.properties
index c70a2f5..ae81f5a 100644
--- a/plugins/user-authenticators/sha256salted/src/main/resources/META-INF/cloudstack/sha256salted/module.properties
+++ b/plugins/user-authenticators/sha256salted/src/main/resources/META-INF/cloudstack/sha256salted/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=sha256salted
-parent=api
\ No newline at end of file
+parent=api
diff --git a/plugins/user-two-factor-authenticators/static-pin/pom.xml b/plugins/user-two-factor-authenticators/static-pin/pom.xml
index b740bfc..2a731aa 100644
--- a/plugins/user-two-factor-authenticators/static-pin/pom.xml
+++ b/plugins/user-two-factor-authenticators/static-pin/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
-</project>
\ No newline at end of file
+</project>
diff --git a/plugins/user-two-factor-authenticators/static-pin/src/main/resources/META-INF/cloudstack/staticpin/module.properties b/plugins/user-two-factor-authenticators/static-pin/src/main/resources/META-INF/cloudstack/staticpin/module.properties
index 14deddd..2c92233 100644
--- a/plugins/user-two-factor-authenticators/static-pin/src/main/resources/META-INF/cloudstack/staticpin/module.properties
+++ b/plugins/user-two-factor-authenticators/static-pin/src/main/resources/META-INF/cloudstack/staticpin/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=staticpin
-parent=api
\ No newline at end of file
+parent=api
diff --git a/plugins/user-two-factor-authenticators/totp/pom.xml b/plugins/user-two-factor-authenticators/totp/pom.xml
index 0eb1b80..1aaae7f 100644
--- a/plugins/user-two-factor-authenticators/totp/pom.xml
+++ b/plugins/user-two-factor-authenticators/totp/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-plugins</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
-</project>
\ No newline at end of file
+</project>
diff --git a/plugins/user-two-factor-authenticators/totp/src/main/resources/META-INF/cloudstack/totp/module.properties b/plugins/user-two-factor-authenticators/totp/src/main/resources/META-INF/cloudstack/totp/module.properties
index 1b735ac..9b37b69 100644
--- a/plugins/user-two-factor-authenticators/totp/src/main/resources/META-INF/cloudstack/totp/module.properties
+++ b/plugins/user-two-factor-authenticators/totp/src/main/resources/META-INF/cloudstack/totp/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=totp
-parent=api
\ No newline at end of file
+parent=api
diff --git a/pom.xml b/pom.xml
index f9be3ab..c42049f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,7 @@
 
     <groupId>org.apache.cloudstack</groupId>
     <artifactId>cloudstack</artifactId>
-    <version>4.18.1.0-SNAPSHOT</version>
+    <version>4.19.0.0-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>Apache CloudStack</name>
     <description>Apache CloudStack is an IaaS ("Infrastructure as a Service") cloud orchestration platform.</description>
@@ -114,7 +114,7 @@
         <cs.junit.dataprovider.version>1.13.1</cs.junit.dataprovider.version>
         <cs.junit.jupiter.version>5.9.1</cs.junit.jupiter.version>
         <cs.guava-testlib.version>18.0</cs.guava-testlib.version>
-        <cs.mockito.version>3.2.4</cs.mockito.version>
+        <cs.mockito.version>3.12.4</cs.mockito.version>
         <cs.powermock.version>2.0.5</cs.powermock.version>
         <cs.selenium.server.version>1.0-20081010.060147</cs.selenium.server.version>
         <cs.selenium-java-client-driver.version>1.0.1</cs.selenium-java-client-driver.version>
@@ -134,6 +134,7 @@
         <cs.bcprov.version>1.70</cs.bcprov.version>
         <cs.cglib.version>3.3.0</cs.cglib.version>
         <cs.checkstyle-lib.version>8.18</cs.checkstyle-lib.version>
+        <cs.cron-utils.version>9.2.0</cs.cron-utils.version>
         <cs.cxf.version>3.2.14</cs.cxf.version>
         <cs.ehcache.version>2.6.11</cs.ehcache.version>
         <cs.globodns-client.version>0.0.27</cs.globodns-client.version>
@@ -1063,6 +1064,7 @@
                             <exclude>ui/public/**</exclude>
                             <exclude>ui/legacy/**</exclude>
                             <exclude>utils/testsmallfileinactive</exclude>
+                            <exclude>**/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker</exclude>
                         </excludes>
                     </configuration>
                 </plugin>
diff --git a/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in b/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in
index 3921484..4944fc0 100755
--- a/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in
+++ b/python/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in
@@ -93,4 +93,3 @@
 esac
 
 exit $RETVAL
-
diff --git a/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in b/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in
index 23ec8f3..28d5a11 100755
--- a/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in
+++ b/python/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in
@@ -93,4 +93,3 @@
 esac
 
 exit $RETVAL
-
diff --git a/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in b/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in
index 51b4f58..de68534 100755
--- a/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in
+++ b/python/distro/opensuse/SYSCONFDIR/init.d/cloud-ipallocator.in
@@ -113,4 +113,3 @@
 esac
 
 exit $RETVAL
-
diff --git a/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in b/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in
index 23ec8f3..28d5a11 100644
--- a/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in
+++ b/python/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-ipallocator.in
@@ -93,4 +93,3 @@
 esac
 
 exit $RETVAL
-
diff --git a/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in b/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in
index 51b4f58..de68534 100755
--- a/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in
+++ b/python/distro/sles/SYSCONFDIR/init.d/cloud-ipallocator.in
@@ -113,4 +113,3 @@
 esac
 
 exit $RETVAL
-
diff --git a/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in b/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in
index e2cb361..4acb11a 100755
--- a/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in
+++ b/python/distro/ubuntu/SYSCONFDIR/init.d/cloud-ipallocator.in
@@ -107,4 +107,3 @@
 esac
 
 exit $RETVAL
-
diff --git a/quickcloud/pom.xml b/quickcloud/pom.xml
index 42a294b..e3b77a8 100644
--- a/quickcloud/pom.xml
+++ b/quickcloud/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 </project>
diff --git a/scripts/installer/export-templates.sh b/scripts/installer/export-templates.sh
index 9371f1c..dbd560e 100644
--- a/scripts/installer/export-templates.sh
+++ b/scripts/installer/export-templates.sh
@@ -189,4 +189,3 @@
 else
   echo "Conversion of template to $1's compatible format not supported "
 fi
-
diff --git a/scripts/network/juniper/dest-nat-rule-getone.xml b/scripts/network/juniper/dest-nat-rule-getone.xml
index 992dc0e..9dd2a1b 100644
--- a/scripts/network/juniper/dest-nat-rule-getone.xml
+++ b/scripts/network/juniper/dest-nat-rule-getone.xml
@@ -34,5 +34,3 @@
 </configuration>
 </get-configuration>
 </rpc>
-
-
diff --git a/scripts/network/juniper/firewall-filter-bytes-getall.xml b/scripts/network/juniper/firewall-filter-bytes-getall.xml
index 9384daf..c5a3728 100644
--- a/scripts/network/juniper/firewall-filter-bytes-getall.xml
+++ b/scripts/network/juniper/firewall-filter-bytes-getall.xml
@@ -20,4 +20,3 @@
 <get-firewall-information>
 </get-firewall-information>
 </rpc>
-
diff --git a/scripts/network/juniper/src-nat-rule-add.xml b/scripts/network/juniper/src-nat-rule-add.xml
index 4093af7..58faf1c 100644
--- a/scripts/network/juniper/src-nat-rule-add.xml
+++ b/scripts/network/juniper/src-nat-rule-add.xml
@@ -44,5 +44,3 @@
 </configuration>
 </load-configuration>
 </rpc>
-
-
diff --git a/scripts/network/juniper/src-nat-rule-getall.xml b/scripts/network/juniper/src-nat-rule-getall.xml
index e04378b..d42d4b6 100644
--- a/scripts/network/juniper/src-nat-rule-getall.xml
+++ b/scripts/network/juniper/src-nat-rule-getall.xml
@@ -28,4 +28,3 @@
 </configuration>
 </get-configuration>
 </rpc>
-
diff --git a/scripts/network/juniper/src-nat-rule-getone.xml b/scripts/network/juniper/src-nat-rule-getone.xml
index 999969b..80bcbbc 100644
--- a/scripts/network/juniper/src-nat-rule-getone.xml
+++ b/scripts/network/juniper/src-nat-rule-getone.xml
@@ -34,5 +34,3 @@
 </configuration>
 </get-configuration>
 </rpc>
-
-
diff --git a/scripts/network/juniper/static-nat-rule-add.xml b/scripts/network/juniper/static-nat-rule-add.xml
index 8316e63..bc8d53c 100644
--- a/scripts/network/juniper/static-nat-rule-add.xml
+++ b/scripts/network/juniper/static-nat-rule-add.xml
@@ -45,5 +45,3 @@
 </configuration>
 </load-configuration>
 </rpc>
-
-
diff --git a/scripts/network/juniper/static-nat-rule-getall.xml b/scripts/network/juniper/static-nat-rule-getall.xml
index a5d0f0a..11755f3 100644
--- a/scripts/network/juniper/static-nat-rule-getall.xml
+++ b/scripts/network/juniper/static-nat-rule-getall.xml
@@ -28,5 +28,3 @@
 </configuration>
 </get-configuration>
 </rpc>
-
-
diff --git a/scripts/network/juniper/static-nat-rule-getone.xml b/scripts/network/juniper/static-nat-rule-getone.xml
index bbec6c3..e2b9102 100644
--- a/scripts/network/juniper/static-nat-rule-getone.xml
+++ b/scripts/network/juniper/static-nat-rule-getone.xml
@@ -34,5 +34,3 @@
 </configuration>
 </get-configuration>
 </rpc>
-
-
diff --git a/scripts/network/juniper/test.xml b/scripts/network/juniper/test.xml
index 16bbd79..84fe3a4 100644
--- a/scripts/network/juniper/test.xml
+++ b/scripts/network/juniper/test.xml
@@ -31,4 +31,3 @@
 </configuration>
 </get-configuration>
 </rpc>
-
diff --git a/scripts/network/juniper/zone-interface-add.xml b/scripts/network/juniper/zone-interface-add.xml
index 4b93ba3..9b2d372 100644
--- a/scripts/network/juniper/zone-interface-add.xml
+++ b/scripts/network/juniper/zone-interface-add.xml
@@ -32,4 +32,3 @@
 </configuration>
 </load-configuration>
 </rpc>
-
diff --git a/scripts/network/juniper/zone-interface-getone.xml b/scripts/network/juniper/zone-interface-getone.xml
index b0ead3c..4bc5c4b 100644
--- a/scripts/network/juniper/zone-interface-getone.xml
+++ b/scripts/network/juniper/zone-interface-getone.xml
@@ -32,4 +32,3 @@
 </configuration>
 </get-configuration>
 </rpc>
-
diff --git a/scripts/storage/qcow2/managevolume.sh b/scripts/storage/qcow2/managevolume.sh
index abf8dd6..1f53047 100755
--- a/scripts/storage/qcow2/managevolume.sh
+++ b/scripts/storage/qcow2/managevolume.sh
@@ -176,5 +176,3 @@
 fi
 
 exit 0
-
-
diff --git a/scripts/storage/secondary/setup-sysvm-tmplt b/scripts/storage/secondary/setup-sysvm-tmplt
index 905d0d5..8b65662 100755
--- a/scripts/storage/secondary/setup-sysvm-tmplt
+++ b/scripts/storage/secondary/setup-sysvm-tmplt
@@ -171,4 +171,4 @@
 fi
 
 echo "Successfully installed system VM template $tmpltimg and template.properties to $destdir"
-exit 0
\ No newline at end of file
+exit 0
diff --git a/scripts/util/keystore-cert-import b/scripts/util/keystore-cert-import
index c4ec3be..a7523ca 100755
--- a/scripts/util/keystore-cert-import
+++ b/scripts/util/keystore-cert-import
@@ -49,7 +49,7 @@
 KS_PASS=$(sed -n '/keystore.passphrase/p' "$PROPS_FILE" 2>/dev/null  | sed 's/keystore.passphrase=//g' 2>/dev/null)
 
 if [ -z "${KS_PASS// }" ]; then
-    echo "Failed to find keystore passphrase from file: $PROPS_FILE, quiting!"
+    echo "Failed to find keystore passphrase from file: $PROPS_FILE, quitting!"
     exit 1
 fi
 
diff --git a/scripts/vm/hypervisor/kvm/nsrkvmbackup.sh b/scripts/vm/hypervisor/kvm/nsrkvmbackup.sh
index c6e115f..2fcfa0b 100755
--- a/scripts/vm/hypervisor/kvm/nsrkvmbackup.sh
+++ b/scripts/vm/hypervisor/kvm/nsrkvmbackup.sh
@@ -257,4 +257,4 @@
 
  backup_domain "$kvmDName" "$snapPrefix$kvmDName"
 
- exit 0
\ No newline at end of file
+ exit 0
diff --git a/scripts/vm/hypervisor/kvm/nsrkvmrestore.sh b/scripts/vm/hypervisor/kvm/nsrkvmrestore.sh
index ad3865d..40a9021 100755
--- a/scripts/vm/hypervisor/kvm/nsrkvmrestore.sh
+++ b/scripts/vm/hypervisor/kvm/nsrkvmrestore.sh
@@ -220,4 +220,4 @@
         sanity_checks
         restore_all_volumes
 fi
-exit 0
\ No newline at end of file
+exit 0
diff --git a/scripts/vm/hypervisor/xenserver/add_to_vcpus_params_live.sh b/scripts/vm/hypervisor/xenserver/add_to_vcpus_params_live.sh
index 0fadcd8..b44fec9 100644
--- a/scripts/vm/hypervisor/xenserver/add_to_vcpus_params_live.sh
+++ b/scripts/vm/hypervisor/xenserver/add_to_vcpus_params_live.sh
@@ -30,4 +30,3 @@
 then
     xe vm-param-set VCPUs-params:cap=$value uuid=$uuid
 fi
-
diff --git a/scripts/vm/hypervisor/xenserver/cloud-plugin-storage b/scripts/vm/hypervisor/xenserver/cloud-plugin-storage
index bc90947..d28c195 100644
--- a/scripts/vm/hypervisor/xenserver/cloud-plugin-storage
+++ b/scripts/vm/hypervisor/xenserver/cloud-plugin-storage
@@ -302,4 +302,3 @@
         "umountNfsSecondaryStorage":umountNfsSecondaryStorage,
         "makeDirectory":makeDirectory})
     
-
diff --git a/scripts/vm/hypervisor/xenserver/cloud-prepare-upgrade.sh b/scripts/vm/hypervisor/xenserver/cloud-prepare-upgrade.sh
index 4f80f72..3a1f88b 100755
--- a/scripts/vm/hypervisor/xenserver/cloud-prepare-upgrade.sh
+++ b/scripts/vm/hypervisor/xenserver/cloud-prepare-upgrade.sh
@@ -98,4 +98,3 @@
     echo "Warning : Don't know how to handle VM $vm, it is in $state state"
   fi
 done
-
diff --git a/scripts/vm/hypervisor/xenserver/cloud-setup-bonding.sh b/scripts/vm/hypervisor/xenserver/cloud-setup-bonding.sh
index 3b806b5..699d1d3 100755
--- a/scripts/vm/hypervisor/xenserver/cloud-setup-bonding.sh
+++ b/scripts/vm/hypervisor/xenserver/cloud-setup-bonding.sh
@@ -107,4 +107,3 @@
   fi
 done
 echo "#check is successful, you can add these hosts to CloudStack."
-
diff --git a/scripts/vm/hypervisor/xenserver/cloudlog b/scripts/vm/hypervisor/xenserver/cloudlog
index ed7e690..bf0202e 100644
--- a/scripts/vm/hypervisor/xenserver/cloudlog
+++ b/scripts/vm/hypervisor/xenserver/cloudlog
@@ -34,4 +34,3 @@
     size 1M
     rotate 2
 }
-
diff --git a/scripts/vm/hypervisor/xenserver/make_migratable.sh b/scripts/vm/hypervisor/xenserver/make_migratable.sh
index aada316..a7ae262 100755
--- a/scripts/vm/hypervisor/xenserver/make_migratable.sh
+++ b/scripts/vm/hypervisor/xenserver/make_migratable.sh
@@ -78,5 +78,3 @@
     exit 3
     ;;
 esac
-
-
diff --git a/scripts/vm/hypervisor/xenserver/network_info.sh b/scripts/vm/hypervisor/xenserver/network_info.sh
index 96df382..ff4805a 100755
--- a/scripts/vm/hypervisor/xenserver/network_info.sh
+++ b/scripts/vm/hypervisor/xenserver/network_info.sh
@@ -55,4 +55,3 @@
 fi
 
 [ -n "$gflag" ] && echo $gateway && exit 0
-
diff --git a/scripts/vm/hypervisor/xenserver/ovstunnel b/scripts/vm/hypervisor/xenserver/ovstunnel
index 72855cd..f349873 100755
--- a/scripts/vm/hypervisor/xenserver/ovstunnel
+++ b/scripts/vm/hypervisor/xenserver/ovstunnel
@@ -356,4 +356,4 @@
                            "getLabel": getLabel,
                            "setup_ovs_bridge_for_distributed_routing": setup_ovs_bridge_for_distributed_routing,
                            "configure_ovs_bridge_for_network_topology": configure_ovs_bridge_for_network_topology,
-                           "configure_ovs_bridge_for_routing_policies": configure_ovs_bridge_for_routing_policies})
\ No newline at end of file
+                           "configure_ovs_bridge_for_routing_policies": configure_ovs_bridge_for_routing_policies})
diff --git a/scripts/vm/hypervisor/xenserver/setup_iscsi.sh b/scripts/vm/hypervisor/xenserver/setup_iscsi.sh
index 660a92f..096e161 100755
--- a/scripts/vm/hypervisor/xenserver/setup_iscsi.sh
+++ b/scripts/vm/hypervisor/xenserver/setup_iscsi.sh
@@ -50,4 +50,3 @@
   exit 1
 fi
 printf "=======> DONE <======\n"
-
diff --git a/scripts/vm/hypervisor/xenserver/setupxenserver.sh b/scripts/vm/hypervisor/xenserver/setupxenserver.sh
index 6c850c6..ef1f68f 100755
--- a/scripts/vm/hypervisor/xenserver/setupxenserver.sh
+++ b/scripts/vm/hypervisor/xenserver/setupxenserver.sh
@@ -62,4 +62,3 @@
 rm -f /opt/xensource/packages/iso/systemvm-premium.iso
 
 echo "success"
-
diff --git a/scripts/vm/hypervisor/xenserver/upgrade_vnc_config.sh b/scripts/vm/hypervisor/xenserver/upgrade_vnc_config.sh
index e65b9ec..c6a1467 100755
--- a/scripts/vm/hypervisor/xenserver/upgrade_vnc_config.sh
+++ b/scripts/vm/hypervisor/xenserver/upgrade_vnc_config.sh
@@ -21,4 +21,3 @@
 # remove listening vnc on all interface
 sed -i 's/0\.0\.0\.0/127\.0\.0\.1/' /opt/xensource/libexec/vncterm-wrapper 2>&1
 sed -i 's/0\.0\.0\.0/127\.0\.0\.1/' /opt/xensource/libexec/qemu-dm-wrapper 2>&1
-
diff --git a/scripts/vm/hypervisor/xenserver/vmopsSnapshot b/scripts/vm/hypervisor/xenserver/vmopsSnapshot
index b74a855..d4cd4b9 100755
--- a/scripts/vm/hypervisor/xenserver/vmopsSnapshot
+++ b/scripts/vm/hypervisor/xenserver/vmopsSnapshot
@@ -621,4 +621,3 @@
 if __name__ == "__main__":
     XenAPIPlugin.dispatch({"getVhdParent":getVhdParent,  "create_secondary_storage_folder":create_secondary_storage_folder, "delete_secondary_storage_folder":delete_secondary_storage_folder, "post_create_private_template":post_create_private_template, "backupSnapshot": backupSnapshot, "deleteSnapshotBackup": deleteSnapshotBackup, "unmountSnapshotsDir": unmountSnapshotsDir, "revert_memory_snapshot":revert_memory_snapshot, "getSnapshotSize":getSnapshotSize})
     
-
diff --git a/scripts/vm/hypervisor/xenserver/xcposs/patch b/scripts/vm/hypervisor/xenserver/xcposs/patch
index 1edd35a..f516251 100644
--- a/scripts/vm/hypervisor/xenserver/xcposs/patch
+++ b/scripts/vm/hypervisor/xenserver/xcposs/patch
@@ -60,4 +60,4 @@
 cloudstack_plugins.conf=..,0644,/etc/xensource
 cloudstack_pluginlib.py=..,0755,/etc/xapi.d/plugins
 cloudlog=..,0644,/etc/logrotate.d
-update_host_passwd.sh=../..,0755,/opt/cloud/bin
\ No newline at end of file
+update_host_passwd.sh=../..,0755,/opt/cloud/bin
diff --git a/scripts/vm/hypervisor/xenserver/xcpserver/patch b/scripts/vm/hypervisor/xenserver/xcpserver/patch
index 8bb1ead..e08fe4d 100644
--- a/scripts/vm/hypervisor/xenserver/xcpserver/patch
+++ b/scripts/vm/hypervisor/xenserver/xcpserver/patch
@@ -61,4 +61,4 @@
 cloudstack_plugins.conf=..,0644,/etc/xensource
 cloudstack_pluginlib.py=..,0755,/etc/xapi.d/plugins
 cloudlog=..,0644,/etc/logrotate.d
-update_host_passwd.sh=../..,0755,/opt/cloud/bin
\ No newline at end of file
+update_host_passwd.sh=../..,0755,/opt/cloud/bin
diff --git a/scripts/vm/hypervisor/xenserver/xenheartbeat.sh b/scripts/vm/hypervisor/xenserver/xenheartbeat.sh
index b4ef56e..355f06f 100755
--- a/scripts/vm/hypervisor/xenserver/xenheartbeat.sh
+++ b/scripts/vm/hypervisor/xenserver/xenheartbeat.sh
@@ -109,4 +109,4 @@
 done
 
 /usr/bin/logger -t heartbeat "Problem with $hb: not reachable for $(($(date +%s) - $lastdate)) seconds, rebooting system!"
-echo b > /proc/sysrq-trigger
\ No newline at end of file
+echo b > /proc/sysrq-trigger
diff --git a/scripts/vm/hypervisor/xenserver/xenserver60/patch b/scripts/vm/hypervisor/xenserver/xenserver60/patch
index 2652c30..67475de 100644
--- a/scripts/vm/hypervisor/xenserver/xenserver60/patch
+++ b/scripts/vm/hypervisor/xenserver/xenserver60/patch
@@ -71,4 +71,4 @@
 ovs-get-bridge.sh=..,0755,/opt/cloud/bin
 cloudlog=..,0644,/etc/logrotate.d
 update_host_passwd.sh=../..,0755,/opt/cloud/bin
-logrotate=..,0755,/etc/cron.hourly
\ No newline at end of file
+logrotate=..,0755,/etc/cron.hourly
diff --git a/scripts/vm/hypervisor/xenserver/xenserver62/patch b/scripts/vm/hypervisor/xenserver/xenserver62/patch
index f18a325..e225105 100644
--- a/scripts/vm/hypervisor/xenserver/xenserver62/patch
+++ b/scripts/vm/hypervisor/xenserver/xenserver62/patch
@@ -67,4 +67,4 @@
 ovs-get-bridge.sh=..,0755,/opt/cloud/bin
 cloudlog=..,0644,/etc/logrotate.d
 update_host_passwd.sh=../..,0755,/opt/cloud/bin
-logrotate=..,0755,/etc/cron.hourly
\ No newline at end of file
+logrotate=..,0755,/etc/cron.hourly
diff --git a/scripts/vm/hypervisor/xenserver/xenserver65/patch b/scripts/vm/hypervisor/xenserver/xenserver65/patch
index f18a325..e225105 100644
--- a/scripts/vm/hypervisor/xenserver/xenserver65/patch
+++ b/scripts/vm/hypervisor/xenserver/xenserver65/patch
@@ -67,4 +67,4 @@
 ovs-get-bridge.sh=..,0755,/opt/cloud/bin
 cloudlog=..,0644,/etc/logrotate.d
 update_host_passwd.sh=../..,0755,/opt/cloud/bin
-logrotate=..,0755,/etc/cron.hourly
\ No newline at end of file
+logrotate=..,0755,/etc/cron.hourly
diff --git a/scripts/vm/hypervisor/xenserver/xs_cleanup.sh b/scripts/vm/hypervisor/xenserver/xs_cleanup.sh
index 7ea3836..d2efa86 100755
--- a/scripts/vm/hypervisor/xenserver/xs_cleanup.sh
+++ b/scripts/vm/hypervisor/xenserver/xs_cleanup.sh
@@ -66,4 +66,3 @@
 
 echo "======> DONE <======"
 exit 0
-
diff --git a/scripts/vm/network/ovs-pvlan-cleanup.sh b/scripts/vm/network/ovs-pvlan-cleanup.sh
index 7493bed..b79c2bd 100755
--- a/scripts/vm/network/ovs-pvlan-cleanup.sh
+++ b/scripts/vm/network/ovs-pvlan-cleanup.sh
@@ -20,4 +20,3 @@
 
 ovs-ofctl del-flows xenbr0
 ovs-ofctl add-flow xenbr0 priority=0,actions=NORMAL
-
diff --git a/scripts/vm/network/ovs-pvlan-vm.sh b/scripts/vm/network/ovs-pvlan-vm.sh
index 06e41fe..c306faa 100755
--- a/scripts/vm/network/ovs-pvlan-vm.sh
+++ b/scripts/vm/network/ovs-pvlan-vm.sh
@@ -97,4 +97,3 @@
     ovs-ofctl del-flows --strict $br priority=50,dl_vlan=0xffff,dl_src=$vm_mac
     ovs-ofctl del-flows --strict $br priority=60,dl_vlan=$sec_iso_vlan,dl_src=$vm_mac
 fi
-
diff --git a/scripts/vm/network/tungsten/create_tap_device.sh b/scripts/vm/network/tungsten/create_tap_device.sh
index c10a0e7..90c24d6 100755
--- a/scripts/vm/network/tungsten/create_tap_device.sh
+++ b/scripts/vm/network/tungsten/create_tap_device.sh
@@ -16,5 +16,5 @@
 # specific language governing permissions and limitations
 # under the License.
 
-ip tuntap add dev $1 mode tap
-ip link set $1 up
\ No newline at end of file
+#ip tuntap add dev $1 mode tap multi_queue
+#ip link set $1 up
diff --git a/scripts/vm/network/tungsten/delete_tap_device.sh b/scripts/vm/network/tungsten/delete_tap_device.sh
index 37d668a..8a36772 100755
--- a/scripts/vm/network/tungsten/delete_tap_device.sh
+++ b/scripts/vm/network/tungsten/delete_tap_device.sh
@@ -16,4 +16,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-ip tuntap del dev $1 mode tap
\ No newline at end of file
+ip tuntap del dev $1 mode tap multi_queue 2>/dev/null
+if [ $? -ne 0 ];then
+  ip tuntap del dev $1 mode tap
+fi
diff --git a/scripts/vm/network/tungsten/setup_tungsten_vrouter.sh b/scripts/vm/network/tungsten/setup_tungsten_vrouter.sh
index e041eac..9d19af3 100755
--- a/scripts/vm/network/tungsten/setup_tungsten_vrouter.sh
+++ b/scripts/vm/network/tungsten/setup_tungsten_vrouter.sh
@@ -21,4 +21,4 @@
 then
     container=$(docker ps | grep contrail-vrouter-agent | awk '{print $1}')
     docker exec $container python /opt/contrail/utils/provision_vgw_interface.py --oper $1 --interface $2 --subnets "$3" --routes "$4" --vrf $5
-fi
\ No newline at end of file
+fi
diff --git a/server/conf/cloudstack-catalina.logrotate b/server/conf/cloudstack-catalina.logrotate
index 498f690..3fd67c9 100644
--- a/server/conf/cloudstack-catalina.logrotate
+++ b/server/conf/cloudstack-catalina.logrotate
@@ -23,4 +23,4 @@
     compress
     missingok
     create 0644 cloud cloud
-}
\ No newline at end of file
+}
diff --git a/server/pom.xml b/server/pom.xml
index c1a7e02..a6c33dd 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
     </parent>
     <repositories>
         <repository>
diff --git a/server/src/main/java/com/cloud/api/ApiDispatcher.java b/server/src/main/java/com/cloud/api/ApiDispatcher.java
index 3880f2a..09a7a92 100644
--- a/server/src/main/java/com/cloud/api/ApiDispatcher.java
+++ b/server/src/main/java/com/cloud/api/ApiDispatcher.java
@@ -35,6 +35,7 @@
 import org.apache.cloudstack.context.CallContext;
 import org.apache.cloudstack.framework.jobs.AsyncJob;
 import org.apache.cloudstack.framework.jobs.AsyncJobManager;
+import org.apache.cloudstack.framework.jobs.impl.AsyncJobManagerImpl;
 import org.apache.log4j.Logger;
 
 import com.cloud.api.dispatch.DispatchChain;
@@ -44,6 +45,7 @@
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
 import com.cloud.utils.db.EntityManager;
+import com.cloud.utils.exception.CloudRuntimeException;
 
 public class ApiDispatcher {
     private static final Logger s_logger = Logger.getLogger(ApiDispatcher.class.getName());
@@ -63,6 +65,9 @@
     @Inject()
     protected DispatchChainFactory dispatchChainFactory;
 
+    @Inject
+    AsyncJobManagerImpl asyncJobManager;
+
     protected DispatchChain standardDispatchChain;
 
     protected DispatchChain asyncCreationDispatchChain;
@@ -85,7 +90,11 @@
     }
 
     public void dispatchCreateCmd(final BaseAsyncCreateCmd cmd, final Map<String, String> params) throws Exception {
-        asyncCreationDispatchChain.dispatch(new DispatchTask(cmd, params));
+        if (asyncJobManager.isAsyncJobsEnabled()) {
+            asyncCreationDispatchChain.dispatch(new DispatchTask(cmd, params));
+        } else {
+            throw new CloudRuntimeException("A shutdown has been triggered. Can not accept new jobs");
+        }
     }
 
     private void doAccessChecks(BaseCmd cmd, Map<Object, AccessType> entitiesToAccess) {
diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
index 8fffebb..568625c 100644
--- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
@@ -33,6 +33,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TimeZone;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
 import javax.inject.Inject;
@@ -43,6 +44,7 @@
 import org.apache.cloudstack.affinity.AffinityGroupResponse;
 import org.apache.cloudstack.annotation.AnnotationService;
 import org.apache.cloudstack.annotation.dao.AnnotationDao;
+import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiConstants.DomainDetails;
 import org.apache.cloudstack.api.ApiConstants.HostDetails;
 import org.apache.cloudstack.api.ApiConstants.VMDetails;
@@ -91,6 +93,8 @@
 import org.apache.cloudstack.api.response.HostForMigrationResponse;
 import org.apache.cloudstack.api.response.HostResponse;
 import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse;
+import org.apache.cloudstack.api.response.HypervisorGuestOsNamesResponse;
+import org.apache.cloudstack.api.response.HypervisorGuestOsResponse;
 import org.apache.cloudstack.api.response.IPAddressResponse;
 import org.apache.cloudstack.api.response.ImageStoreResponse;
 import org.apache.cloudstack.api.response.InstanceGroupResponse;
@@ -199,6 +203,7 @@
 import org.apache.cloudstack.usage.UsageService;
 import org.apache.cloudstack.usage.UsageTypes;
 import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
@@ -291,6 +296,7 @@
 import com.cloud.network.as.Condition;
 import com.cloud.network.as.ConditionVO;
 import com.cloud.network.as.Counter;
+import com.cloud.network.dao.FirewallRulesDao;
 import com.cloud.network.dao.IPAddressDao;
 import com.cloud.network.dao.IPAddressVO;
 import com.cloud.network.dao.LoadBalancerVO;
@@ -455,6 +461,8 @@
     UserVmJoinDao userVmJoinDao;
     @Inject
     NetworkServiceMapDao ntwkSrvcDao;
+    @Inject
+    FirewallRulesDao firewallRulesDao;
 
     @Override
     public UserResponse createUserResponse(User user) {
@@ -935,6 +943,42 @@
         return userIpAddresVO != null ? userIpAddresVO.isForSystemVms() : false;
     }
 
+    private void addVmDetailsInIpResponse(IPAddressResponse response, IpAddress ipAddress) {
+        if (ipAddress.getAllocatedToAccountId() != null && ipAddress.getAllocatedToAccountId() == Account.ACCOUNT_ID_SYSTEM) {
+            NicVO nic = ApiDBUtils.findByIp4AddressAndNetworkId(ipAddress.getAddress().toString(), ipAddress.getNetworkId());
+            if (nic != null) {
+                addSystemVmInfoToIpResponse(nic, response);
+            }
+        }
+        if (ipAddress.getAssociatedWithVmId() != null) {
+            addUserVmDetailsInIpResponse(response, ipAddress);
+        }
+    }
+
+    private void addSystemVmInfoToIpResponse(NicVO nic, IPAddressResponse ipResponse) {
+        final boolean isAdmin = Account.Type.ADMIN.equals(CallContext.current().getCallingAccount().getType());
+        if (!isAdmin) {
+            return;
+        }
+        VirtualMachine vm = ApiDBUtils.findVMInstanceById(nic.getInstanceId());
+        if (vm == null) {
+            return;
+        }
+        ipResponse.setVirtualMachineId(vm.getUuid());
+        ipResponse.setVirtualMachineName(vm.getHostName());
+        ipResponse.setVirtualMachineType(vm.getType().toString());
+    }
+
+    private void addUserVmDetailsInIpResponse(IPAddressResponse response, IpAddress ipAddress) {
+        UserVm userVm = ApiDBUtils.findUserVmById(ipAddress.getAssociatedWithVmId());
+        if (userVm != null) {
+            response.setVirtualMachineId(userVm.getUuid());
+            response.setVirtualMachineName(userVm.getHostName());
+            response.setVirtualMachineType(userVm.getType().toString());
+            response.setVirtualMachineDisplayName(ObjectUtils.firstNonNull(userVm.getDisplayName(), userVm.getHostName()));
+        }
+    }
+
     @Override
     public IPAddressResponse createIPAddressResponse(ResponseView view, IpAddress ipAddr) {
         VlanVO vlan = ApiDBUtils.findVlanById(ipAddr.getVlanId());
@@ -963,18 +1007,7 @@
         ipResponse.setForVirtualNetwork(forVirtualNetworks);
         ipResponse.setStaticNat(ipAddr.isOneToOneNat());
 
-        if (ipAddr.getAssociatedWithVmId() != null) {
-            UserVm vm = ApiDBUtils.findUserVmById(ipAddr.getAssociatedWithVmId());
-            if (vm != null) {
-                ipResponse.setVirtualMachineId(vm.getUuid());
-                ipResponse.setVirtualMachineName(vm.getHostName());
-                if (vm.getDisplayName() != null) {
-                    ipResponse.setVirtualMachineDisplayName(vm.getDisplayName());
-                } else {
-                    ipResponse.setVirtualMachineDisplayName(vm.getHostName());
-                }
-            }
-        }
+        addVmDetailsInIpResponse(ipResponse, ipAddr);
         if (ipAddr.getVmIp() != null) {
             ipResponse.setVirtualMachineIp(ipAddr.getVmIp());
         }
@@ -987,13 +1020,9 @@
             }
         }
 
-        if (ipAddr.getVpcId() != null) {
-            Vpc vpc = ApiDBUtils.findVpcById(ipAddr.getVpcId());
-            if (vpc != null) {
-                ipResponse.setVpcId(vpc.getUuid());
-                ipResponse.setVpcName(vpc.getName());
-            }
-        }
+
+        setVpcIdInResponse(ipAddr.getVpcId(), ipResponse::setVpcId, ipResponse::setVpcName);
+
 
         // Network id the ip is associated with (if associated networkId is
         // null, try to get this information from vlan)
@@ -1058,10 +1087,27 @@
         ipResponse.setHasAnnotation(annotationDao.hasAnnotations(ipAddr.getUuid(), AnnotationService.EntityType.PUBLIC_IP_ADDRESS.name(),
                 _accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())));
 
+        ipResponse.setHasRules(firewallRulesDao.countRulesByIpId(ipAddr.getId()) > 0);
         ipResponse.setObjectName("ipaddress");
         return ipResponse;
     }
 
+
+    private void setVpcIdInResponse(Long vpcId, Consumer<String> vpcUuidSetter, Consumer<String> vpcNameSetter) {
+        if (vpcId != null) {
+            Vpc vpc = ApiDBUtils.findVpcById(vpcId);
+            if (vpc != null) {
+                try {
+                    _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, false, vpc);
+                    vpcUuidSetter.accept(vpc.getUuid());
+                } catch (PermissionDeniedException e) {
+                    s_logger.debug("Not setting the vpcId to the response because the caller does not have access to the VPC");
+                }
+                vpcNameSetter.accept(vpc.getName());
+            }
+        }
+    }
+
     private void showVmInfoForSharedNetworks(boolean forVirtualNetworks, IpAddress ipAddr, IPAddressResponse ipResponse) {
         if (!forVirtualNetworks) {
             NicVO nic = ApiDBUtils.findByIp4AddressAndNetworkId(ipAddr.getAddress().toString(), ipAddr.getNetworkId());
@@ -1092,8 +1138,9 @@
                         ipResponse.setVirtualMachineDisplayName(vm.getHostName());
                     }
                 }
-            } else if (nic.getVmType() == VirtualMachine.Type.DomainRouter) {
+            } else if (nic.getVmType().isUsedBySystem()) {
                 ipResponse.setIsSystem(true);
+                addSystemVmInfoToIpResponse(nic, ipResponse);
             }
         }
     }
@@ -2531,13 +2578,9 @@
         }
 
         response.setSpecifyIpRanges(network.getSpecifyIpRanges());
-        if (network.getVpcId() != null) {
-            Vpc vpc = ApiDBUtils.findVpcById(network.getVpcId());
-            if (vpc != null) {
-                response.setVpcId(vpc.getUuid());
-                response.setVpcName(vpc.getName());
-            }
-        }
+
+
+        setVpcIdInResponse(network.getVpcId(), response::setVpcId, response::setVpcName);
 
         setResponseAssociatedNetworkInformation(response, network.getId());
 
@@ -3629,12 +3672,14 @@
     @Override
     public GuestOSResponse createGuestOSResponse(GuestOS guestOS) {
         GuestOSResponse response = new GuestOSResponse();
+        response.setName(guestOS.getDisplayName());
         response.setDescription(guestOS.getDisplayName());
         response.setId(guestOS.getUuid());
-        response.setIsUserDefined(guestOS.getIsUserDefined());
+        response.setIsUserDefined(String.valueOf(guestOS.getIsUserDefined()));
         GuestOSCategoryVO category = ApiDBUtils.findGuestOsCategoryById(guestOS.getCategoryId());
         if (category != null) {
             response.setOsCategoryId(category.getUuid());
+            response.setOsCategoryName(category.getName());
         }
 
         response.setObjectName("ostype");
@@ -3660,6 +3705,28 @@
     }
 
     @Override
+    public HypervisorGuestOsNamesResponse createHypervisorGuestOSNamesResponse(List<Pair<String, String>> hypervisorGuestOsNames) {
+        HypervisorGuestOsNamesResponse response = new HypervisorGuestOsNamesResponse();
+        List<HypervisorGuestOsResponse> hypervisorGuestOsResponses = new ArrayList<>();
+        for (Pair<String, String> hypervisorGuestOsName : hypervisorGuestOsNames) {
+            HypervisorGuestOsResponse hypervisorGuestOsResponse = createHypervisorGuestOsResponse(hypervisorGuestOsName);
+            hypervisorGuestOsResponses.add(hypervisorGuestOsResponse);
+        }
+        response.setGuestOSList(hypervisorGuestOsResponses);
+        response.setGuestOSCount(hypervisorGuestOsResponses.size());
+        response.setObjectName("hypervisorguestosnames");
+        return response;
+    }
+
+    private HypervisorGuestOsResponse createHypervisorGuestOsResponse(Pair<String, String> hypervisorGuestOsName) {
+        HypervisorGuestOsResponse hypervisorGuestOsResponse = new HypervisorGuestOsResponse();
+        hypervisorGuestOsResponse.setOsStdName(hypervisorGuestOsName.first());
+        hypervisorGuestOsResponse.setOsNameForHypervisor(hypervisorGuestOsName.second());
+        hypervisorGuestOsResponse.setObjectName(ApiConstants.GUEST_OS_LIST);
+        return hypervisorGuestOsResponse;
+    }
+
+    @Override
     public SnapshotScheduleResponse createSnapshotScheduleResponse(SnapshotSchedule snapshotSchedule) {
         SnapshotScheduleResponse response = new SnapshotScheduleResponse();
         response.setId(snapshotSchedule.getUuid());
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 74367a0..dc90b26 100644
--- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
+++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
@@ -184,6 +184,8 @@
 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.DataCenter;
 import com.cloud.dc.DedicatedResourceVO;
 import com.cloud.dc.dao.DedicatedResourceDao;
@@ -457,6 +459,10 @@
     private ResourceIconDao resourceIconDao;
 
     @Inject
+    private ManagementServerHostDao msHostDao;
+
+
+    @Inject
     EntityManager entityManager;
 
     private SearchCriteria<ServiceOfferingJoinVO> getMinimumCpuServiceOfferingJoinSearchCriteria(int cpu) {
@@ -795,7 +801,9 @@
             sc.setParameters("resourceType", resourceType.toString());
         }
 
-        sc.setParameters("archived", false);
+        if (id == null) {
+            sc.setParameters("archived", cmd.getArchived());
+        }
 
         Pair<List<EventJoinVO>, Integer> eventPair = null;
         // event_view will not have duplicate rows for each event, so
@@ -970,6 +978,12 @@
     public ListResponse<UserVmResponse> searchForUserVMs(ListVMsCmd cmd) {
         Pair<List<UserVmJoinVO>, Integer> result = searchForUserVMsInternal(cmd);
         ListResponse<UserVmResponse> response = new ListResponse<>();
+
+        if (cmd.getRetrieveOnlyResourceCount()) {
+            response.setResponses(new ArrayList<>(), result.second());
+            return response;
+        }
+
         ResponseView respView = ResponseView.Restricted;
         Account caller = CallContext.current().getCallingAccount();
         if (_accountMgr.isRootAdmin(caller.getId())) {
@@ -2058,7 +2072,12 @@
     @Override
     public ListResponse<VolumeResponse> searchForVolumes(ListVolumesCmd cmd) {
         Pair<List<VolumeJoinVO>, Integer> result = searchForVolumesInternal(cmd);
-        ListResponse<VolumeResponse> response = new ListResponse<VolumeResponse>();
+        ListResponse<VolumeResponse> response = new ListResponse<>();
+
+        if (cmd.getRetrieveOnlyResourceCount()) {
+            response.setResponses(new ArrayList<>(), result.second());
+            return response;
+        }
 
         ResponseView respView = cmd.getResponseView();
         Account account = CallContext.current().getCallingAccount();
@@ -2547,6 +2566,10 @@
             }
         }
 
+        if (cmd.getManagementServerId() != null) {
+            sb.and("executingMsid", sb.entity().getExecutingMsid(), SearchCriteria.Op.EQ);
+        }
+
         Object keyword = cmd.getKeyword();
         Object startDate = cmd.getStartDate();
 
@@ -2575,6 +2598,11 @@
             sc.addAnd("created", SearchCriteria.Op.GTEQ, startDate);
         }
 
+        if (cmd.getManagementServerId() != null) {
+            ManagementServerHostVO msHost = msHostDao.findById(cmd.getManagementServerId());
+            sc.setParameters("executingMsid", msHost.getMsid());
+        }
+
         return _jobJoinDao.searchAndCount(sc, searchFilter);
     }
 
@@ -4040,6 +4068,8 @@
             options.put(VmDetailConstants.VIDEO_RAM, Collections.emptyList());
             options.put(VmDetailConstants.IO_POLICY, Arrays.asList("threads", "native", "io_uring", "storage_specific"));
             options.put(VmDetailConstants.IOTHREADS, Arrays.asList("enabled"));
+            options.put(VmDetailConstants.NIC_MULTIQUEUE_NUMBER, Collections.emptyList());
+            options.put(VmDetailConstants.NIC_PACKED_VIRTQUEUES_ENABLED, Arrays.asList("true", "false"));
         }
 
         if (HypervisorType.VMware.equals(hypervisorType)) {
diff --git a/server/src/main/java/com/cloud/api/query/dao/AsyncJobJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/AsyncJobJoinDaoImpl.java
index bd11015..32cd1c2 100644
--- a/server/src/main/java/com/cloud/api/query/dao/AsyncJobJoinDaoImpl.java
+++ b/server/src/main/java/com/cloud/api/query/dao/AsyncJobJoinDaoImpl.java
@@ -53,6 +53,11 @@
     public AsyncJobResponse newAsyncJobResponse(final AsyncJobJoinVO job) {
         final AsyncJobResponse jobResponse = new AsyncJobResponse();
         jobResponse.setAccountId(job.getAccountUuid());
+        jobResponse.setAccount(job.getAccountName());
+        jobResponse.setDomainId(job.getDomainUuid());
+        StringBuilder domainPath = new StringBuilder("ROOT");
+        (domainPath.append(job.getDomainPath())).deleteCharAt(domainPath.length() - 1);
+        jobResponse.setDomainPath(domainPath.toString());
         jobResponse.setUserId(job.getUserUuid());
         jobResponse.setCmd(job.getCmd());
         jobResponse.setCreated(job.getCreated());
@@ -60,6 +65,7 @@
         jobResponse.setJobId(job.getUuid());
         jobResponse.setJobStatus(job.getStatus());
         jobResponse.setJobProcStatus(job.getProcessStatus());
+        jobResponse.setMsid(job.getExecutingMsid());
 
         if (job.getInstanceType() != null && job.getInstanceId() != null) {
             jobResponse.setJobInstanceType(job.getInstanceType().toString());
diff --git a/server/src/main/java/com/cloud/api/query/vo/AsyncJobJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/AsyncJobJoinVO.java
index a4db864..cee5526 100644
--- a/server/src/main/java/com/cloud/api/query/vo/AsyncJobJoinVO.java
+++ b/server/src/main/java/com/cloud/api/query/vo/AsyncJobJoinVO.java
@@ -75,6 +75,9 @@
     @Column(name = "job_cmd")
     private String cmd;
 
+    @Column(name = "job_executing_msid")
+    private Long executingMsid;
+
     @Column(name = "job_status")
     private int status;
 
@@ -214,6 +217,10 @@
         return null;
     }
 
+    public Long getExecutingMsid() {
+        return executingMsid;
+    }
+
     @Override
     public String getProjectUuid() {
         // TODO Auto-generated method stub
diff --git a/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java b/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java
index 9c5f3e0..6926f67 100644
--- a/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java
+++ b/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java
@@ -978,16 +978,12 @@
         allocateVmCapacity(vm, fromLastHost);
       }
 
-      if (newState == State.Stopped) {
-        if (vm.getType() == VirtualMachine.Type.User) {
-
+      if (newState == State.Stopped && event != Event.RestoringFailed && event != Event.RestoringSuccess && vm.getType() == VirtualMachine.Type.User) {
           UserVmVO userVM = _userVMDao.findById(vm.getId());
           _userVMDao.loadDetails(userVM);
           // free the message sent flag if it exists
           userVM.setDetail(VmDetailConstants.MESSAGE_RESERVED_CAPACITY_FREED_FLAG, "false");
           _userVMDao.saveDetails(userVM);
-
-        }
       }
 
       return true;
diff --git a/server/src/main/java/com/cloud/configuration/Config.java b/server/src/main/java/com/cloud/configuration/Config.java
index aeefdb5..f1b5836 100644
--- a/server/src/main/java/com/cloud/configuration/Config.java
+++ b/server/src/main/java/com/cloud/configuration/Config.java
@@ -844,7 +844,7 @@
             "The interval (in milliseconds) when vm stats are retrieved from agents.",
             null),
     VmDiskStatsInterval("Advanced", ManagementServer.class, Integer.class, "vm.disk.stats.interval", "0", "Interval (in seconds) to report vm disk statistics.", null),
-    VolumeStatsInterval("Advanced", ManagementServer.class, Integer.class, "volume.stats.interval", "60000", "Interval (in miliseconds) to report volume statistics.", null),
+    VolumeStatsInterval("Advanced", ManagementServer.class, Integer.class, "volume.stats.interval", "60000", "Interval (in milliseconds) to report volume statistics.", null),
     VmTransitionWaitInterval(
             "Advanced",
             ManagementServer.class,
@@ -1621,7 +1621,7 @@
             String.class,
             "implicit.host.tags",
             "GPU",
-            "Tag hosts at the time of host disovery based on the host properties/capabilities",
+            "Tag hosts at the time of host discovery based on the host properties/capabilities",
             null),
     VpcCleanupInterval(
             "Advanced",
diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
index 737cdc7..890fb11 100644
--- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -295,6 +295,8 @@
 
 public class ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, ConfigurationService, Configurable {
     public static final Logger s_logger = Logger.getLogger(ConfigurationManagerImpl.class);
+    public static final String PERACCOUNT = "peraccount";
+    public static final String PERZONE = "perzone";
 
     @Inject
     EntityManager _entityMgr;
@@ -458,7 +460,6 @@
     protected Set<String> configValuesForValidation;
     private Set<String> weightBasedParametersForValidation;
     private Set<String> overprovisioningFactorsForValidation;
-    public static final String VM_USERDATA_MAX_LENGTH_STRING = "vm.userdata.max.length";
 
     public static final ConfigKey<Boolean> SystemVMUseLocalStorage = new ConfigKey<Boolean>(Boolean.class, "system.vm.use.local.storage", "Advanced", "false",
             "Indicates whether to use local storage pools or shared storage pools for system VMs.", false, ConfigKey.Scope.Zone, null);
@@ -489,8 +490,6 @@
     public static ConfigKey<Integer> VM_SERVICE_OFFERING_MAX_RAM_SIZE = new ConfigKey<Integer>("Advanced", Integer.class, "vm.serviceoffering.ram.size.max", "0", "Maximum RAM size in "
       + "MB for vm service offering. If 0 - no limitation", true);
 
-    public static final ConfigKey<Integer> VM_USERDATA_MAX_LENGTH = new ConfigKey<Integer>("Advanced", Integer.class, VM_USERDATA_MAX_LENGTH_STRING, "32768",
-            "Max length of vm userdata after base64 decoding. Default is 32768 and maximum is 1048576", true);
     public static final ConfigKey<Boolean> MIGRATE_VM_ACROSS_CLUSTERS = new ConfigKey<Boolean>(Boolean.class, "migrate.vm.across.clusters", "Advanced", "false",
             "Indicates whether the VM can be migrated to different cluster if no host is found in same cluster",true, ConfigKey.Scope.Zone, null);
 
@@ -6235,34 +6234,32 @@
     }
 
     void validateSourceNatServiceCapablities(final Map<Capability, String> sourceNatServiceCapabilityMap) {
-        if (sourceNatServiceCapabilityMap != null && !sourceNatServiceCapabilityMap.isEmpty()) {
-            if (sourceNatServiceCapabilityMap.keySet().size() > 2) {
-                throw new InvalidParameterValueException("Only " + Capability.SupportedSourceNatTypes.getName() + " and " + Capability.RedundantRouter
-                        + " capabilities can be sepcified for source nat service");
-            }
+        if (MapUtils.isNotEmpty(sourceNatServiceCapabilityMap) && (sourceNatServiceCapabilityMap.size() > 2 || ! sourceNatCapabilitiesContainValidValues(sourceNatServiceCapabilityMap))) {
+            throw new InvalidParameterValueException("Only " + Capability.SupportedSourceNatTypes.getName()
+                    + ", " + Capability.RedundantRouter
+                    + " capabilities can be specified for source nat service");
+        }
+    }
 
-            for (final Map.Entry<Capability ,String> srcNatPair : sourceNatServiceCapabilityMap.entrySet()) {
-                final Capability capability = srcNatPair.getKey();
-                final String value = srcNatPair.getValue();
-                if (capability == Capability.SupportedSourceNatTypes) {
-                    final boolean perAccount = value.contains("peraccount");
-                    final boolean perZone = value.contains("perzone");
-                    if (perAccount && perZone || !perAccount && !perZone) {
-                        throw new InvalidParameterValueException("Either peraccount or perzone source NAT type can be specified for "
-                                + Capability.SupportedSourceNatTypes.getName());
-                    }
-                } else if (capability == Capability.RedundantRouter) {
-                    final boolean enabled = value.contains("true");
-                    final boolean disabled = value.contains("false");
-                    if (!enabled && !disabled) {
-                        throw new InvalidParameterValueException("Unknown specified value for " + Capability.RedundantRouter.getName());
-                    }
-                } else {
-                    throw new InvalidParameterValueException("Only " + Capability.SupportedSourceNatTypes.getName() + " and " + Capability.RedundantRouter
-                            + " capabilities can be sepcified for source nat service");
+    boolean sourceNatCapabilitiesContainValidValues(Map<Capability, String> sourceNatServiceCapabilityMap) {
+        for (final Entry<Capability ,String> srcNatPair : sourceNatServiceCapabilityMap.entrySet()) {
+            final Capability capability = srcNatPair.getKey();
+            final String value = srcNatPair.getValue();
+            if (Capability.SupportedSourceNatTypes.equals(capability)) {
+                List<String> snatTypes = Arrays.asList(PERACCOUNT, PERZONE);
+                if (! snatTypes.contains(value) || ( value.contains(PERACCOUNT) && value.contains(PERZONE))) {
+                    throw new InvalidParameterValueException("Either peraccount or perzone source NAT type can be specified for "
+                            + Capability.SupportedSourceNatTypes.getName());
                 }
+            } else if (Capability.RedundantRouter.equals(capability)) {
+                if (! Arrays.asList("true", "false").contains(value.toLowerCase())) {
+                    throw new InvalidParameterValueException("Unknown specified value for " + capability.getName());
+                }
+            } else {
+                return false;
             }
         }
+        return true;
     }
 
     void validateStaticNatServiceCapablities(final Map<Capability, String> staticNatServiceCapabilityMap) {
@@ -6439,17 +6436,8 @@
 
             final Map<Capability, String> sourceNatServiceCapabilityMap = serviceCapabilityMap.get(Service.SourceNat);
             if (sourceNatServiceCapabilityMap != null && !sourceNatServiceCapabilityMap.isEmpty()) {
-                final String sourceNatType = sourceNatServiceCapabilityMap.get(Capability.SupportedSourceNatTypes);
-                if (sourceNatType != null) {
-                    _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.SourceNat), Service.SourceNat, Capability.SupportedSourceNatTypes, sourceNatType);
-                    sharedSourceNat = sourceNatType.contains("perzone");
-                }
-
-                final String param = sourceNatServiceCapabilityMap.get(Capability.RedundantRouter);
-                if (param != null) {
-                    _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.SourceNat), Service.SourceNat, Capability.RedundantRouter, param);
-                    redundantRouter = param.contains("true");
-                }
+                sharedSourceNat = isSharedSourceNat(serviceProviderMap, sourceNatServiceCapabilityMap);
+                redundantRouter = isRedundantRouter(serviceProviderMap, sourceNatServiceCapabilityMap);
             }
 
             final Map<Capability, String> staticNatServiceCapabilityMap = serviceCapabilityMap.get(Service.StaticNat);
@@ -6599,6 +6587,26 @@
         });
     }
 
+    boolean isRedundantRouter(Map<Service, Set<Provider>> serviceProviderMap, Map<Capability, String> sourceNatServiceCapabilityMap) {
+        boolean redundantRouter = false;
+        String param = sourceNatServiceCapabilityMap.get(Capability.RedundantRouter);
+        if (param != null) {
+            _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.SourceNat), Service.SourceNat, Capability.RedundantRouter, param);
+            redundantRouter = param.contains("true");
+        }
+        return redundantRouter;
+    }
+
+    boolean isSharedSourceNat(Map<Service, Set<Provider>> serviceProviderMap, Map<Capability, String> sourceNatServiceCapabilityMap) {
+        boolean sharedSourceNat = false;
+        String param = sourceNatServiceCapabilityMap.get(Capability.SupportedSourceNatTypes);
+        if (param != null) {
+            _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.SourceNat), Service.SourceNat, Capability.SupportedSourceNatTypes, param);
+            sharedSourceNat = param.contains(PERZONE);
+        }
+        return sharedSourceNat;
+    }
+
     protected void validateNtwkOffDetails(final Map<Detail, String> details, final Map<Service, Set<Provider>> serviceProviderMap) {
         for (final Detail detail : details.keySet()) {
 
diff --git a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java
index cf4e7fd..f71f46f 100644
--- a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java
+++ b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java
@@ -16,6 +16,8 @@
 // under the License.
 package com.cloud.deploy;
 
+import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -23,28 +25,17 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.Timer;
 import java.util.TreeSet;
+import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
 import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO;
-import com.cloud.storage.VMTemplateVO;
-import com.cloud.storage.dao.VMTemplateDao;
-import com.cloud.user.AccountVO;
-import com.cloud.user.dao.AccountDao;
-import com.cloud.exception.StorageUnavailableException;
-import com.cloud.utils.db.Filter;
-import com.cloud.utils.fsm.StateMachine2;
-
-import org.apache.cloudstack.framework.config.ConfigKey;
-import org.apache.cloudstack.framework.config.Configurable;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.log4j.Logger;
 import org.apache.cloudstack.affinity.AffinityGroupProcessor;
 import org.apache.cloudstack.affinity.AffinityGroupService;
 import org.apache.cloudstack.affinity.AffinityGroupVMMapVO;
@@ -57,6 +48,8 @@
 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.StoragePoolAllocator;
+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.framework.messagebus.MessageBus;
 import org.apache.cloudstack.framework.messagebus.MessageSubscriber;
@@ -64,6 +57,9 @@
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.utils.identity.ManagementServerNode;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Logger;
 
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.Listener;
@@ -95,6 +91,7 @@
 import com.cloud.exception.AffinityConflictException;
 import com.cloud.exception.ConnectionException;
 import com.cloud.exception.InsufficientServerCapacityException;
+import com.cloud.exception.StorageUnavailableException;
 import com.cloud.gpu.GPU;
 import com.cloud.host.DetailVO;
 import com.cloud.host.Host;
@@ -115,26 +112,32 @@
 import com.cloud.storage.StorageManager;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.StoragePoolHostVO;
+import com.cloud.storage.VMTemplateVO;
 import com.cloud.storage.Volume;
 import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.storage.dao.GuestOSCategoryDao;
 import com.cloud.storage.dao.GuestOSDao;
 import com.cloud.storage.dao.StoragePoolHostDao;
+import com.cloud.storage.dao.VMTemplateDao;
 import com.cloud.storage.dao.VolumeDao;
 import com.cloud.user.AccountManager;
+import com.cloud.user.AccountVO;
+import com.cloud.user.dao.AccountDao;
 import com.cloud.utils.DateUtil;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
 import com.cloud.utils.component.Manager;
 import com.cloud.utils.component.ManagerBase;
 import com.cloud.utils.db.DB;
+import com.cloud.utils.db.Filter;
 import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.Transaction;
 import com.cloud.utils.db.TransactionCallback;
 import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.fsm.StateListener;
+import com.cloud.utils.fsm.StateMachine2;
 import com.cloud.vm.DiskProfile;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
@@ -144,8 +147,6 @@
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
 
-import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
-
 public class DeploymentPlanningManagerImpl extends ManagerBase implements DeploymentPlanningManager, Manager, Listener,
 StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
 
@@ -266,6 +267,35 @@
         _affinityProcessors = affinityProcessors;
     }
 
+    protected void avoidOtherClustersForDeploymentIfMigrationDisabled(VirtualMachine vm, Host lastHost, ExcludeList avoids) {
+        if (lastHost == null || lastHost.getClusterId() == null ||
+                ConfigurationManagerImpl.MIGRATE_VM_ACROSS_CLUSTERS.valueIn(vm.getDataCenterId())) {
+            return;
+        }
+        List<VolumeVO> volumes = _volsDao.findUsableVolumesForInstance(vm.getId());
+        if (CollectionUtils.isEmpty(volumes)) {
+            return;
+        }
+        boolean storageMigrationNeededDuringClusterMigration = false;
+        for (Volume volume : volumes) {
+            StoragePoolVO pool = _storagePoolDao.findById(volume.getPoolId());
+            if (List.of(ScopeType.HOST, ScopeType.CLUSTER).contains(pool.getScope())) {
+                storageMigrationNeededDuringClusterMigration = true;
+                break;
+            }
+        }
+        if (!storageMigrationNeededDuringClusterMigration) {
+            return;
+        }
+        final Long lastHostClusterId = lastHost.getClusterId();
+        s_logger.warn(String.format("VM last host ID: %d belongs to zone ID: %s for which config - %s is false and storage migration would be needed for inter-cluster migration, therefore, adding all other clusters except ID: %d from this zone to avoid list",
+                lastHost.getId(), vm.getDataCenterId(), ConfigurationManagerImpl.MIGRATE_VM_ACROSS_CLUSTERS.key(), lastHostClusterId));
+        List<Long> clusterIds = _clusterDao.listAllClusters(lastHost.getDataCenterId());
+        Set<Long> existingAvoidedClusters = avoids.getClustersToAvoid();
+        clusterIds = clusterIds.stream().filter(x -> !Objects.equals(x, lastHostClusterId) && (existingAvoidedClusters == null || !existingAvoidedClusters.contains(x))).collect(Collectors.toList());
+        avoids.addClusterList(clusterIds);
+    }
+
     @Override
     public DeployDestination planDeployment(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoids, DeploymentPlanner planner)
             throws InsufficientServerCapacityException, AffinityConflictException {
@@ -408,6 +438,8 @@
             planner = getDeploymentPlannerByName(plannerName);
         }
 
+        Host lastHost = null;
+
         String considerLastHostStr = (String)vmProfile.getParameter(VirtualMachineProfile.Param.ConsiderLastHost);
         boolean considerLastHost = vm.getLastHostId() != null && haVmTag == null &&
                 (considerLastHostStr == null || Boolean.TRUE.toString().equalsIgnoreCase(considerLastHostStr));
@@ -415,6 +447,7 @@
             s_logger.debug("This VM has last host_id specified, trying to choose the same host: " + vm.getLastHostId());
 
             HostVO host = _hostDao.findById(vm.getLastHostId());
+            lastHost = host;
             _hostDao.loadHostTags(host);
             _hostDao.loadDetails(host);
             ServiceOfferingDetailsVO offeringDetails = null;
@@ -519,6 +552,8 @@
             s_logger.debug("Cannot choose the last host to deploy this VM ");
         }
 
+        avoidOtherClustersForDeploymentIfMigrationDisabled(vm, lastHost, avoids);
+
         DeployDestination dest = null;
         List<Long> clusterList = null;
 
diff --git a/server/src/main/java/com/cloud/event/dao/EventJoinDaoImpl.java b/server/src/main/java/com/cloud/event/dao/EventJoinDaoImpl.java
index c73f575..24c699a 100644
--- a/server/src/main/java/com/cloud/event/dao/EventJoinDaoImpl.java
+++ b/server/src/main/java/com/cloud/event/dao/EventJoinDaoImpl.java
@@ -110,6 +110,9 @@
         responseEvent.setParentId(event.getStartUuid());
         responseEvent.setState(event.getState());
         responseEvent.setUsername(event.getUserName());
+        if (event.getArchived()) {
+            responseEvent.setArchived(true);
+        }
         Long resourceId = event.getResourceId();
         responseEvent.setResourceType(event.getResourceType());
         ApiCommandResourceType resourceType = ApiCommandResourceType.fromString(event.getResourceType());
diff --git a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
index b690acd..1352393 100644
--- a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
@@ -1471,15 +1471,7 @@
             throw new InvalidParameterValueException("Ip address can be associated to the network with trafficType " + TrafficType.Guest);
         }
 
-        // Check that network belongs to IP owner - skip this check
-        //     - if zone is basic zone as there is just one guest network,
-        //     - if shared network in Advanced zone
-        //     - and it belongs to the system
-        if (network.getAccountId() != owner.getId()) {
-            if (zone.getNetworkType() != NetworkType.Basic && !(zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Shared)) {
-                throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP");
-            }
-        }
+        validateNetworkAndIpOwnership(owner, ipToAssoc, network, zone);
 
         if (zone.getNetworkType() == NetworkType.Advanced) {
             // In Advance zone allow to do IP assoc only for Isolated networks with source nat service enabled
@@ -1544,6 +1536,21 @@
     }
 
     /**
+     * Check that network belongs to IP owner - skip this check
+     *  - if the IP belongs to the same VPC as the network
+     *  - if zone is basic zone as there is just one guest network,
+     *  - if shared network in Advanced zone
+     *  - and it belongs to the system
+     */
+    private static void validateNetworkAndIpOwnership(Account owner, IPAddressVO ipToAssoc, Network network, DataCenter zone) {
+        if (network.getAccountId() != owner.getId()) {
+            if (!network.getVpcId().equals(ipToAssoc.getVpcId()) && zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() != GuestType.Shared) {
+                throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP");
+            }
+        }
+    }
+
+    /**
      * Prevents associating an IP address to an allocated (unimplemented network) network, throws an Exception otherwise
      * @param owner Used to check if the user belongs to the Network
      * @param ipToAssoc IP address to be associated to a Network, can only be associated to an implemented network for Source NAT
@@ -1625,15 +1632,7 @@
 
         DataCenter zone = _entityMgr.findById(DataCenter.class, network.getDataCenterId());
 
-        // Check that network belongs to IP owner - skip this check
-        //     - if zone is basic zone as there is just one guest network,
-        //     - if shared network in Advanced zone
-        //     - and it belongs to the system
-        if (network.getAccountId() != owner.getId()) {
-            if (zone.getNetworkType() != NetworkType.Basic && !(zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Shared)) {
-                throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP");
-            }
-        }
+        validateNetworkAndIpOwnership(owner, ipToAssoc, network, zone);
 
         // Check if IP has any services (rules) associated in the network
         List<PublicIpAddress> ipList = new ArrayList<PublicIpAddress>();
@@ -2358,4 +2357,19 @@
     public static ConfigKey<Boolean> getSystemvmpublicipreservationmodestrictness() {
         return SystemVmPublicIpReservationModeStrictness;
     }
+
+    @Override
+    public void updateSourceNatIpAddress(IPAddressVO requestedIp, List<IPAddressVO> userIps) throws Exception{
+        Transaction.execute((TransactionCallbackWithException<IpAddress, Exception>) status -> {
+            // update all other IPs to not be sourcenat, should be at most one
+            for(IPAddressVO oldIpAddress :userIps) {
+                oldIpAddress.setSourceNat(false);
+                _ipAddressDao.update(oldIpAddress.getId(), oldIpAddress);
+            }
+            requestedIp.setSourceNat(true);
+            _ipAddressDao.update(requestedIp.getId(),requestedIp);
+            return requestedIp;
+        });
+    }
+
 }
diff --git a/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java b/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java
index e1f4fe7..0cfd6e6 100644
--- a/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkMigrationManagerImpl.java
@@ -297,6 +297,7 @@
         Vpc copyOfVpc;
         long copyOfVpcId;
         try {
+
             copyOfVpc = _vpcService.createVpc(vpc.getZoneId(), vpcOfferingId, vpc.getAccountId(), vpc.getName(),
                     vpc.getDisplayText(), vpc.getCidr(), vpc.getNetworkDomain(), vpc.getIp4Dns1(), vpc.getIp4Dns2(),
                     vpc.getIp6Dns1(), vpc.getIp6Dns2(), vpc.isDisplay(), vpc.getPublicMtu());
diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
index 896292d..ac698f6 100644
--- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
@@ -80,6 +80,8 @@
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 
@@ -264,9 +266,13 @@
     private static final long MIN_GRE_KEY = 0L;
     private static final long MAX_GRE_KEY = 4294967295L; // 2^32 -1
     private static final long MIN_VXLAN_VNI = 0L;
+    /**
+     // MAX_VXLAN_VNI should be 16777215L (2^24-1), but Linux vxlan interface doesn't accept VNI:2^24-1 now.
+     // It seems a bug.
+     // Is this still valid (per 2023?)
+     */
     private static final long MAX_VXLAN_VNI = 16777214L; // 2^24 -2
-    // MAX_VXLAN_VNI should be 16777215L (2^24-1), but Linux vxlan interface doesn't accept VNI:2^24-1 now.
-    // It seems a bug.
+    private static final String NETWORK_OFFERING_ID = "networkOfferingId";
 
     @Inject
     DataCenterDao _dcDao = null;
@@ -1289,15 +1295,20 @@
         }
     }
 
-    private void validateRouterIps(String routerIp, String routerIpv6, String startIp, String endIp, String gateway,
-                                   String netmask, String startIpv6, String endIpv6, String ip6Cidr) {
+    void validateSharedNetworkRouterIPs(String gateway, String startIP, String endIP, String netmask, String routerIPv4, String routerIPv6, String startIPv6, String endIPv6, String ip6Cidr, NetworkOffering ntwkOff) {
+        if (ntwkOff.getGuestType() == GuestType.Shared) {
+            validateSharedNetworkRouterIPv4(routerIPv4, startIP, endIP, gateway, netmask);
+            validateSharedNetworkRouterIPv6(routerIPv6, startIPv6, endIPv6, ip6Cidr);
+
+        }
+    }
+
+    private void validateSharedNetworkRouterIPv4(String routerIp, String startIp, String endIp, String gateway, String netmask) {
         if (StringUtils.isNotBlank(routerIp)) {
             if (startIp != null && endIp == null) {
                 endIp = startIp;
             }
-            if (!NetUtils.isValidIp4(routerIp)) {
-                throw new CloudRuntimeException("Router IPv4 IP provided is of incorrect format");
-            }
+            isIPv4AddressValid(routerIp);
             if (StringUtils.isNoneBlank(startIp, endIp)) {
                 if (!NetUtils.isIpInRange(routerIp, startIp, endIp)) {
                     throw new CloudRuntimeException("Router IPv4 IP provided is not within the specified range: " + startIp + " - " + endIp);
@@ -1309,26 +1320,39 @@
                 }
             }
         }
-        if (StringUtils.isNotBlank(routerIpv6)) {
-            if (startIpv6 != null && endIpv6 == null) {
-                endIpv6 = startIpv6;
+    }
+
+    private void validateSharedNetworkRouterIPv6(String routerIPv6, String startIPv6, String endIPv6, String cidrIPv6) {
+        if (StringUtils.isNotBlank(routerIPv6)) {
+            if (startIPv6 != null && endIPv6 == null) {
+                endIPv6 = startIPv6;
             }
-            if (!NetUtils.isValidIp6(routerIpv6)) {
-                throw new CloudRuntimeException("Router IPv6 address provided is of incorrect format");
-            }
-            if (StringUtils.isNoneBlank(startIpv6, endIpv6)) {
-                String ipv6Range = startIpv6 + "-" + endIpv6;
-                if (!NetUtils.isIp6InRange(routerIpv6, ipv6Range)) {
-                    throw new CloudRuntimeException("Router IPv6 address provided is not within the specified range: " + startIpv6 + " - " + endIpv6);
+            isIPv6AddressValid(routerIPv6);
+            if (StringUtils.isNoneBlank(startIPv6, endIPv6)) {
+                String ipv6Range = startIPv6 + "-" + endIPv6;
+                if (!NetUtils.isIp6InRange(routerIPv6, ipv6Range)) {
+                    throw new CloudRuntimeException("Router IPv6 address provided is not within the specified range: " + startIPv6 + " - " + endIPv6);
                 }
             } else {
-                if (!NetUtils.isIp6InNetwork(routerIpv6, ip6Cidr)) {
+                if (!NetUtils.isIp6InNetwork(routerIPv6, cidrIPv6)) {
                     throw new CloudRuntimeException("Router IPv6 address provided is not with the network range");
                 }
             }
         }
     }
 
+    private void isIPv4AddressValid(String routerIp) {
+        if (!NetUtils.isValidIp4(routerIp)) {
+            throw new CloudRuntimeException("Router IPv4 IP provided is of incorrect format");
+        }
+    }
+
+    private void isIPv6AddressValid(String routerIPv6) {
+        if (!NetUtils.isValidIp6(routerIPv6)) {
+            throw new CloudRuntimeException("Router IPv6 address provided is of incorrect format");
+        }
+    }
+
     @Override
     @DB
     @ActionEvent(eventType = EventTypes.EVENT_NETWORK_CREATE, eventDescription = "creating network")
@@ -1339,34 +1363,26 @@
         String endIP = cmd.getEndIp();
         String netmask = cmd.getNetmask();
         String networkDomain = cmd.getNetworkDomain();
-        String vlanId = null;
-        boolean bypassVlanOverlapCheck = false;
-        boolean hideIpAddressUsage = false;
-        String routerIp = null;
-        String routerIpv6 = null;
-        if (cmd instanceof CreateNetworkCmdByAdmin) {
-            vlanId = ((CreateNetworkCmdByAdmin)cmd).getVlan();
-            bypassVlanOverlapCheck = ((CreateNetworkCmdByAdmin)cmd).getBypassVlanOverlapCheck();
-            hideIpAddressUsage = ((CreateNetworkCmdByAdmin)cmd).getHideIpAddressUsage();
-            routerIp = ((CreateNetworkCmdByAdmin)cmd).getRouterIp();
-            routerIpv6 = ((CreateNetworkCmdByAdmin)cmd).getRouterIpv6();
-        }
+
+        boolean adminCalledUs = cmd instanceof CreateNetworkCmdByAdmin;
+        String vlanId = adminCalledUs ? ((CreateNetworkCmdByAdmin)cmd).getVlan() : null;
+        boolean bypassVlanOverlapCheck = adminCalledUs && ((CreateNetworkCmdByAdmin)cmd).getBypassVlanOverlapCheck();
+        boolean hideIpAddressUsage = adminCalledUs && ((CreateNetworkCmdByAdmin)cmd).getHideIpAddressUsage();
+        String routerIPv4 = adminCalledUs ? ((CreateNetworkCmdByAdmin)cmd).getRouterIp() : null;
+        String routerIPv6 = adminCalledUs ? ((CreateNetworkCmdByAdmin)cmd).getRouterIpv6() : null;
 
         String name = cmd.getNetworkName();
         String displayText = cmd.getDisplayText();
         Account caller = CallContext.current().getCallingAccount();
         Long physicalNetworkId = cmd.getPhysicalNetworkId();
-        Long zoneId = cmd.getZoneId();
-        String aclTypeStr = cmd.getAclType();
         Long domainId = cmd.getDomainId();
-        boolean isDomainSpecific = false;
         Boolean subdomainAccess = cmd.getSubdomainAccess();
         Long vpcId = cmd.getVpcId();
         String startIPv6 = cmd.getStartIpv6();
         String endIPv6 = cmd.getEndIpv6();
         String ip6Gateway = cmd.getIp6Gateway();
         String ip6Cidr = cmd.getIp6Cidr();
-        Boolean displayNetwork = cmd.getDisplayNetwork();
+        boolean displayNetwork = ! Boolean.FALSE.equals(cmd.getDisplayNetwork());
         Long aclId = cmd.getAclId();
         String isolatedPvlan = cmd.getIsolatedPvlan();
         String externalId = cmd.getExternalId();
@@ -1379,127 +1395,31 @@
         String ip6Dns1 = cmd.getIp6Dns1();
         String ip6Dns2 = cmd.getIp6Dns2();
 
-        // Validate network offering
-        NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
-        if (ntwkOff == null || ntwkOff.isSystemOnly()) {
-            InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering by specified id");
-            if (ntwkOff != null) {
-                ex.addProxyObject(ntwkOff.getUuid(), "networkOfferingId");
-            }
-            throw ex;
-        }
+        // Validate network offering id
+        NetworkOffering ntwkOff = getAndValidateNetworkOffering(networkOfferingId);
 
-        Account owner = null;
-        if ((cmd.getAccountName() != null && domainId != null) || cmd.getProjectId() != null) {
-            owner = _accountMgr.finalizeOwner(caller, cmd.getAccountName(), domainId, cmd.getProjectId());
-        } else {
-            s_logger.info(String.format("Assigning the network to caller:%s because either projectId or accountname and domainId are not provided", caller.getAccountName()));
-            owner = caller;
-        }
+        Account owner = getOwningAccount(cmd, caller);
 
-        // validate physical network and zone
-        // Check if physical network exists
-        PhysicalNetwork pNtwk = null;
-        if (physicalNetworkId != null) {
-            pNtwk = _physicalNetworkDao.findById(physicalNetworkId);
-            if (pNtwk == null) {
-                throw new InvalidParameterValueException("Unable to find a physical network having the specified physical network id");
-            }
-        }
+        PhysicalNetwork pNtwk = getAndValidatePhysicalNetwork(physicalNetworkId);
 
-        if (zoneId == null) {
-            zoneId = pNtwk.getDataCenterId();
-        }
-
-        if (displayNetwork == null) {
-            displayNetwork = true;
-        }
-
-        DataCenter zone = _dcDao.findById(zoneId);
-        if (zone == null) {
-            throw new InvalidParameterValueException("Specified zone id was not found");
-        }
+        DataCenter zone = getAndValidateZone(cmd, pNtwk);
 
         _accountMgr.checkAccess(owner, ntwkOff, zone);
 
-        if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) {
-            // See DataCenterVO.java
-            PermissionDeniedException ex = new PermissionDeniedException("Cannot perform this operation since specified Zone is currently disabled");
-            ex.addProxyObject(zone.getUuid(), "zoneId");
-            throw ex;
-        }
+        validateZoneAvailability(caller, zone);
 
-        // Only domain and account ACL types are supported in Acton.
-        ACLType aclType = null;
-        if (aclTypeStr != null) {
-            if (aclTypeStr.equalsIgnoreCase(ACLType.Account.toString())) {
-                aclType = ACLType.Account;
-            } else if (aclTypeStr.equalsIgnoreCase(ACLType.Domain.toString())) {
-                aclType = ACLType.Domain;
-            } else {
-                throw new InvalidParameterValueException("Incorrect aclType specified. Check the API documentation for supported types");
-            }
-            // In 3.0 all Shared networks should have aclType == Domain, all Isolated networks aclType==Account
-            if (ntwkOff.getGuestType() == GuestType.Isolated) {
-                if (aclType != ACLType.Account) {
-                    throw new InvalidParameterValueException("AclType should be " + ACLType.Account + " for network of type " + Network.GuestType.Isolated);
-                }
-            } else if (ntwkOff.getGuestType() == GuestType.Shared) {
-                if (!(aclType == ACLType.Domain || aclType == ACLType.Account)) {
-                    throw new InvalidParameterValueException("AclType should be " + ACLType.Domain + " or " + ACLType.Account + " for network of type " + Network.GuestType.Shared);
-                }
-            }
-        } else {
-            if (ntwkOff.getGuestType() == GuestType.Isolated || ntwkOff.getGuestType() == GuestType.L2) {
-                aclType = ACLType.Account;
-            } else if (ntwkOff.getGuestType() == GuestType.Shared) {
-                if (_accountMgr.isRootAdmin(caller.getId())) {
-                    aclType = ACLType.Domain;
-                } else if (_accountMgr.isNormalUser(caller.getId())) {
-                    aclType = ACLType.Account;
-                } else {
-                    throw new InvalidParameterValueException("AclType must be specified for shared network created by domain admin");
-                }
-            }
-        }
+        ACLType aclType = getAclType(caller, cmd.getAclType(), ntwkOff);
 
-        if (ntwkOff.getGuestType() != GuestType.Shared && (!StringUtils.isAllBlank(routerIp, routerIpv6))) {
+        if (ntwkOff.getGuestType() != GuestType.Shared && (!StringUtils.isAllBlank(routerIPv4, routerIPv6))) {
             throw new InvalidParameterValueException("Router IP can be specified only for Shared networks");
         }
 
         if (ntwkOff.getGuestType() == GuestType.Shared && !_networkModel.isProviderForNetworkOffering(Provider.VirtualRouter, networkOfferingId)
-                && (!StringUtils.isAllBlank(routerIp, routerIpv6))) {
+                && (!StringUtils.isAllBlank(routerIPv4, routerIPv6))) {
             throw new InvalidParameterValueException("Virtual Router is not a supported provider for the Shared network, hence router ip should not be provided");
         }
 
-        // Check if the network is domain specific
-        if (aclType == ACLType.Domain) {
-            // only Admin can create domain with aclType=Domain
-            if (!_accountMgr.isAdmin(caller.getId())) {
-                throw new PermissionDeniedException("Only admin can create networks with aclType=Domain");
-            }
-
-            // only shared networks can be Domain specific
-            if (ntwkOff.getGuestType() != GuestType.Shared) {
-                throw new InvalidParameterValueException("Only " + GuestType.Shared + " networks can have aclType=" + ACLType.Domain);
-            }
-
-            if (domainId != null) {
-                if (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != Network.GuestType.Shared) {
-                    throw new InvalidParameterValueException("Domain level networks are supported just for traffic type " + TrafficType.Guest + " and guest type " + Network.GuestType.Shared);
-                }
-
-                DomainVO domain = _domainDao.findById(domainId);
-                if (domain == null) {
-                    throw new InvalidParameterValueException("Unable to find domain by specified id");
-                }
-                _accountMgr.checkAccess(caller, domain);
-            }
-            isDomainSpecific = true;
-
-        } else if (subdomainAccess != null) {
-            throw new InvalidParameterValueException("Parameter subDomainAccess can be specified only with aclType=Domain");
-        }
+        boolean isDomainSpecific = isDomainSpecificNetworkRequested(caller, domainId, subdomainAccess, ntwkOff, aclType);
 
         if (aclType == ACLType.Domain) {
             owner = _accountDao.findById(Account.ACCOUNT_ID_SYSTEM);
@@ -1601,7 +1521,8 @@
             }
         }
 
-        validateRouterIps(routerIp, routerIpv6, startIP, endIP, gateway, netmask, startIPv6, endIPv6, ip6Cidr);
+        validateSharedNetworkRouterIPs(gateway, startIP, endIP, netmask, routerIPv4, routerIPv6, startIPv6, endIPv6, ip6Cidr, ntwkOff);
+
         Pair<String, String> ip6GatewayCidr = null;
         if (zone.getNetworkType() == NetworkType.Advanced && ntwkOff.getGuestType() == GuestType.Isolated) {
             ipv6 = _networkOfferingDao.isIpv6Supported(ntwkOff.getId());
@@ -1673,7 +1594,7 @@
         if (cidr != null && providersConfiguredForExternalNetworking(ntwkProviders)) {
             if (ntwkOff.getGuestType() == GuestType.Shared && (zone.getNetworkType() == NetworkType.Advanced) && isSharedNetworkOfferingWithServices(networkOfferingId)) {
                 // validate if CIDR specified overlaps with any of the CIDR's allocated for isolated networks and shared networks in the zone
-                checkSharedNetworkCidrOverlap(zoneId, pNtwk.getId(), cidr);
+                checkSharedNetworkCidrOverlap(zone.getId(), pNtwk.getId(), cidr);
             } else {
                 // if the guest network is for the VPC, if any External Provider are supported in VPC
                 // cidr will not be null as it is generated from the super cidr of vpc.
@@ -1698,10 +1619,10 @@
 
         // Can add vlan range only to the network which allows it
         if (createVlan && !ntwkOff.isSpecifyIpRanges()) {
-            throwInvalidIdException("Network offering with specified id doesn't support adding multiple ip ranges", ntwkOff.getUuid(), "networkOfferingId");
+            throwInvalidIdException("Network offering with specified id doesn't support adding multiple ip ranges", ntwkOff.getUuid(), NETWORK_OFFERING_ID);
         }
 
-        Pair<Integer, Integer> interfaceMTUs = validateMtuConfig(publicMtu, privateMtu, zoneId);
+        Pair<Integer, Integer> interfaceMTUs = validateMtuConfig(publicMtu, privateMtu, zone.getId());
         mtuCheckForVpcNetwork(vpcId, interfaceMTUs, publicMtu, privateMtu);
 
         Network associatedNetwork = null;
@@ -1720,9 +1641,12 @@
 
         checkNetworkDns(ipv6, ntwkOff, vpcId, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2);
 
-        Network network = commitNetwork(networkOfferingId, gateway, startIP, endIP, netmask, networkDomain, vlanId, bypassVlanOverlapCheck, name, displayText, caller, physicalNetworkId, zoneId,
+        Network network = commitNetwork(networkOfferingId, gateway, startIP, endIP, netmask, networkDomain, vlanId, bypassVlanOverlapCheck, name, displayText, caller, physicalNetworkId, zone.getId(),
                 domainId, isDomainSpecific, subdomainAccess, vpcId, startIPv6, endIPv6, ip6Gateway, ip6Cidr, displayNetwork, aclId, secondaryVlanId, privateVlanType, ntwkOff, pNtwk, aclType, owner, cidr, createVlan,
-                externalId, routerIp, routerIpv6, associatedNetwork, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, interfaceMTUs);
+                externalId, routerIPv4, routerIPv6, associatedNetwork, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, interfaceMTUs);
+
+        // retrieve, acquire and associate the correct ip adresses
+        checkAndSetRouterSourceNatIp(owner, cmd, network);
 
         if (hideIpAddressUsage) {
             _networkDetailsDao.persist(new NetworkDetailVO(network.getId(), Network.hideIpAddressUsage, String.valueOf(hideIpAddressUsage), false));
@@ -1739,6 +1663,213 @@
         return network;
     }
 
+    void checkAndSetRouterSourceNatIp(Account owner, CreateNetworkCmd cmd, Network network) throws InsufficientAddressCapacityException, ResourceAllocationException {
+        String sourceNatIp = cmd.getSourceNatIP();
+        if (sourceNatIp == null) {
+            s_logger.debug(String.format("no source nat ip given for create network %s command, using something arbitrary.", cmd.getNetworkName()));
+            return; // nothing to try
+        }
+        IpAddress ip = allocateIP(owner, cmd.getZoneId(), network.getId(), null, sourceNatIp);
+        try {
+            associateIPToNetwork(ip.getId(), network.getId());
+        } catch (ResourceUnavailableException e) {
+            String msg = String.format("can´t use %s as sourcenat IP address for network %s/%s as it is un available", sourceNatIp, network.getName(), network.getUuid());
+            s_logger.error(msg);
+            throw new CloudRuntimeException(msg,e);
+        }
+    }
+
+    /**
+     * @param cmd
+     * @param network
+     * @return whether the sourceNat is changed, and consequently restart is needed
+     * @throws InsufficientAddressCapacityException
+     * @throws ResourceAllocationException
+     */
+    private boolean checkAndUpdateRouterSourceNatIp(UpdateNetworkCmd cmd, Network network) {
+        IPAddressVO requestedIp = checkSourceNatIpAddressForUpdate(cmd, network);
+        if (requestedIp == null) return false; // ip not associated with this network
+
+        List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), true);
+        if (! userIps.isEmpty()) {
+            try {
+                _ipAddrMgr.updateSourceNatIpAddress(requestedIp, userIps);
+            } catch (Exception e) { // pokemon execption from transaction
+                String msg = String.format("Update of source NAT ip to %s for network \"%s\"/%s failed due to %s",
+                        requestedIp.getAddress().addr(), network.getName(), network.getUuid(), e.getLocalizedMessage());
+                s_logger.error(msg);
+                throw new CloudRuntimeException(msg, e);
+            }
+        }
+        return true;
+    }
+
+    @Nullable
+    private IPAddressVO checkSourceNatIpAddressForUpdate(UpdateNetworkCmd cmd, Network network) {
+        String sourceNatIp = cmd.getSourceNatIP();
+        if (sourceNatIp == null) {
+            s_logger.trace(String.format("no source NAT ip given to update network %s with.", cmd.getNetworkName()));
+            return null;
+        } else {
+            s_logger.info(String.format("updating network %s to have source NAT ip %s", cmd.getNetworkName(), sourceNatIp));
+        }
+        // check if the address is already aqcuired for this network
+        IPAddressVO requestedIp = _ipAddressDao.findByIp(sourceNatIp);
+        if (requestedIp == null || requestedIp.getAssociatedWithNetworkId() == null || ! requestedIp.getAssociatedWithNetworkId().equals(network.getId())) {
+            s_logger.warn(String.format("Source NAT IP %s is not associated with network %s/%s. It cannot be used as source NAT IP.",
+                    sourceNatIp, network.getName(), network.getUuid()));
+            return null;
+        }
+        // check if it is the current source NAT address
+        if (requestedIp.isSourceNat()) {
+            s_logger.info(String.format("IP address %s is allready the source Nat address. Not updating!", sourceNatIp));
+            return null;
+        }
+        return requestedIp;
+    }
+
+    @Nullable
+    private ACLType getAclType(Account caller, String aclTypeStr, NetworkOffering ntwkOff) {
+        // Only domain and account ACL types are supported in Acton.
+        ACLType aclType = null;
+        if (aclTypeStr != null) {
+            aclType = getAclType(aclTypeStr, ntwkOff);
+        } else {
+            aclType = getAclType(caller, ntwkOff, aclType);
+        }
+        return aclType;
+    }
+
+    @NotNull
+    private static ACLType getAclType(String aclTypeStr, NetworkOffering ntwkOff) {
+        ACLType aclType;
+        if (aclTypeStr.equalsIgnoreCase(ACLType.Account.toString())) {
+            aclType = ACLType.Account;
+        } else if (aclTypeStr.equalsIgnoreCase(ACLType.Domain.toString())) {
+            aclType = ACLType.Domain;
+        } else {
+            throw new InvalidParameterValueException("Incorrect aclType specified. Check the API documentation for supported types");
+        }
+        // In 3.0 all Shared networks should have aclType == Domain, all Isolated networks aclType==Account
+        if (ntwkOff.getGuestType() == GuestType.Isolated && aclType != ACLType.Account) {
+            throw new InvalidParameterValueException("AclType should be " + ACLType.Account + " for network of type " + GuestType.Isolated);
+        }
+        return aclType;
+    }
+
+    private ACLType getAclType(Account caller, NetworkOffering ntwkOff, ACLType aclType) {
+        if (ntwkOff.getGuestType() == GuestType.Isolated || ntwkOff.getGuestType() == GuestType.L2) {
+            aclType = ACLType.Account;
+        } else if (ntwkOff.getGuestType() == GuestType.Shared) {
+            if (_accountMgr.isRootAdmin(caller.getId())) {
+                aclType = ACLType.Domain;
+            } else if (_accountMgr.isNormalUser(caller.getId())) {
+                aclType = ACLType.Account;
+            } else {
+                throw new InvalidParameterValueException("AclType must be specified for shared network created by domain admin");
+            }
+        }
+        return aclType;
+    }
+
+    private void validateZoneAvailability(Account caller, DataCenter zone) {
+        if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) {
+            // See DataCenterVO.java
+            PermissionDeniedException ex = new PermissionDeniedException("Cannot perform this operation since specified Zone is currently disabled");
+            ex.addProxyObject(zone.getUuid(), "zoneId");
+            throw ex;
+        }
+    }
+
+    private boolean isDomainSpecificNetworkRequested(Account caller, Long domainId, Boolean subdomainAccess, NetworkOffering ntwkOff, ACLType aclType) {
+        boolean isDomainSpecific = false;
+        // Check if the network is domain specific
+        if (aclType == ACLType.Domain) {
+            // only Admin can create domain with aclType=Domain
+            if (!_accountMgr.isAdmin(caller.getId())) {
+                throw new PermissionDeniedException("Only admin can create networks with aclType=Domain");
+            }
+
+            // only shared networks can be Domain specific
+            if (ntwkOff.getGuestType() != GuestType.Shared) {
+                throw new InvalidParameterValueException("Only " + GuestType.Shared + " networks can have aclType=" + ACLType.Domain);
+            }
+
+            if (domainId != null) {
+                if (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != GuestType.Shared) {
+                    throw new InvalidParameterValueException("Domain level networks are supported just for traffic type " + TrafficType.Guest + " and guest type " + GuestType.Shared);
+                }
+
+                DomainVO domain = _domainDao.findById(domainId);
+                if (domain == null) {
+                    throw new InvalidParameterValueException("Unable to find domain by specified id");
+                }
+                _accountMgr.checkAccess(caller, domain);
+            }
+            isDomainSpecific = true;
+
+        } else if (subdomainAccess != null) {
+            throw new InvalidParameterValueException("Parameter subDomainAccess can be specified only with aclType=Domain");
+        }
+        return isDomainSpecific;
+    }
+
+    @NotNull
+    private DataCenter getAndValidateZone(CreateNetworkCmd cmd, PhysicalNetwork pNtwk) {
+        Long zoneId = (cmd.getZoneId() == null) ? pNtwk.getDataCenterId() : cmd.getZoneId();
+        DataCenter zone = _dcDao.findById(zoneId);
+        if (zone == null) {
+            throw new InvalidParameterValueException("Specified zone id was not found");
+        }
+        return zone;
+    }
+
+    /**
+     // validate physical network and zone
+     // Check if physical network exists
+     *
+     * @param physicalNetworkId the id of the required physical network
+     * @return the data object for the physical network
+     */
+    @NotNull
+    private PhysicalNetwork getAndValidatePhysicalNetwork(Long physicalNetworkId) {
+        PhysicalNetwork pNtwk = null;
+        if (physicalNetworkId != null) {
+            pNtwk = getPhysicalNetwork(physicalNetworkId);
+            if (pNtwk == null) {
+                throw new InvalidParameterValueException("Unable to find a physical network having the specified physical network id");
+            }
+        } else {
+            throw new CloudRuntimeException("cannot create Guestnetwork without physical network.");
+        }
+        return pNtwk;
+    }
+
+    private Account getOwningAccount(CreateNetworkCmd cmd, Account caller) {
+        Account owner = null;
+        Long domainId = cmd.getDomainId();
+        if ((cmd.getAccountName() != null && domainId != null) || cmd.getProjectId() != null) {
+            owner = _accountMgr.finalizeOwner(caller, cmd.getAccountName(), domainId, cmd.getProjectId());
+        } else {
+            s_logger.info(String.format("Assigning the network to caller:%s because either projectId or accountname and domainId are not provided", caller.getAccountName()));
+            owner = caller;
+        }
+        return owner;
+    }
+
+    @NotNull
+    private NetworkOffering getAndValidateNetworkOffering(Long networkOfferingId) {
+        NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
+        if (ntwkOff == null || ntwkOff.isSystemOnly()) {
+            InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering by specified id");
+            if (ntwkOff != null) {
+                ex.addProxyObject(ntwkOff.getUuid(), NETWORK_OFFERING_ID);
+            }
+            throw ex;
+        }
+        return ntwkOff;
+    }
+
     protected void mtuCheckForVpcNetwork(Long vpcId, Pair<Integer, Integer> interfaceMTUs, Integer publicMtu, Integer privateMtu) {
         if (vpcId != null && publicMtu != null) {
             VpcVO vpc = _vpcDao.findById(vpcId);
@@ -1853,7 +1984,7 @@
         }
     }
 
-    private void validateNetworkOfferingForNonRootAdminUser(NetworkOfferingVO ntwkOff) {
+    private void validateNetworkOfferingForNonRootAdminUser(NetworkOffering ntwkOff) {
         if (ntwkOff.getTrafficType() != TrafficType.Guest) {
             throw new InvalidParameterValueException("This user can only create a Guest network");
         }
@@ -1915,7 +2046,7 @@
     private Network commitNetwork(final Long networkOfferingId, final String gateway, final String startIP, final String endIP, final String netmask, final String networkDomain, final String vlanIdFinal,
                                   final Boolean bypassVlanOverlapCheck, final String name, final String displayText, final Account caller, final Long physicalNetworkId, final Long zoneId, final Long domainId,
                                   final boolean isDomainSpecific, final Boolean subdomainAccessFinal, final Long vpcId, final String startIPv6, final String endIPv6, final String ip6Gateway, final String ip6Cidr,
-                                  final Boolean displayNetwork, final Long aclId, final String isolatedPvlan, final PVlanType isolatedPvlanType, final NetworkOfferingVO ntwkOff, final PhysicalNetwork pNtwk, final ACLType aclType, final Account ownerFinal,
+                                  final Boolean displayNetwork, final Long aclId, final String isolatedPvlan, final PVlanType isolatedPvlanType, final NetworkOffering ntwkOff, final PhysicalNetwork pNtwk, final ACLType aclType, final Account ownerFinal,
                                   final String cidr, final boolean createVlan, final String externalId, String routerIp, String routerIpv6,
                                   final Network associatedNetwork, final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs) throws InsufficientCapacityException, ResourceAllocationException {
         try {
@@ -2364,7 +2495,7 @@
         }
 
         if (networkOfferingId != null) {
-            sc.addAnd("networkOfferingId", SearchCriteria.Op.EQ, networkOfferingId);
+            sc.addAnd(NETWORK_OFFERING_ID, SearchCriteria.Op.EQ, networkOfferingId);
         }
 
         if (associatedNetworkId != null) {
@@ -2787,6 +2918,8 @@
         _accountMgr.checkAccess(callerAccount, AccessType.OperateEntry, true, network);
         _accountMgr.checkAccess(_accountMgr.getActiveAccountById(network.getAccountId()), offering, _dcDao.findById(network.getDataCenterId()));
 
+        restartNetwork |= checkAndUpdateRouterSourceNatIp(cmd, network);
+
         if (cmd instanceof UpdateNetworkCmdByAdmin) {
             final Boolean hideIpAddressUsage = ((UpdateNetworkCmdByAdmin) cmd).getHideIpAddressUsage();
             if (hideIpAddressUsage != null) {
@@ -2835,13 +2968,13 @@
         NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId);
         if (networkOfferingId != null) {
             if (networkOffering == null || networkOffering.isSystemOnly()) {
-                throwInvalidIdException("Unable to find network offering with specified id", networkOfferingId.toString(), "networkOfferingId");
+                throwInvalidIdException("Unable to find network offering with specified id", networkOfferingId.toString(), NETWORK_OFFERING_ID);
             }
 
             // network offering should be in Enabled state
             if (networkOffering.getState() != NetworkOffering.State.Enabled) {
                 throwInvalidIdException("Network offering with specified id is not in " + NetworkOffering.State.Enabled + " state, can't upgrade to it", networkOffering.getUuid(),
-                        "networkOfferingId");
+                        NETWORK_OFFERING_ID);
             }
             //can't update from vpc to non-vpc network offering
             boolean forVpcNew = _configMgr.isOfferingForVpc(networkOffering);
@@ -2884,10 +3017,8 @@
             }
         }
 
-        if (checkAndUpdateNetworkDns(network, networkOfferingChanged ? networkOffering : oldNtwkOff, ip4Dns1, ip4Dns2,
-                ip6Dns1, ip6Dns2)) {
-            restartNetwork = true;
-        }
+        restartNetwork |= checkAndUpdateNetworkDns(network, networkOfferingChanged ? networkOffering : oldNtwkOff, ip4Dns1, ip4Dns2,
+                ip6Dns1, ip6Dns2);
 
         final Map<String, String> newSvcProviders = networkOfferingChanged
                 ? _networkMgr.finalizeServicesAndProvidersForNetwork(_entityMgr.findById(NetworkOffering.class, networkOfferingId), network.getPhysicalNetworkId())
@@ -3084,7 +3215,7 @@
             if (servicesNotInNewOffering != null && !servicesNotInNewOffering.isEmpty()) {
                 _networkMgr.cleanupConfigForServicesInNetwork(servicesNotInNewOffering, network);
             }
-        } catch (Throwable e) {
+        } catch (Exception e) { // old pokemon catch that used to catch throwable
             s_logger.debug("failed to cleanup config related to unused services error:" + e.getMessage());
         }
 
@@ -3638,7 +3769,7 @@
         if (newNtwkOff == null || newNtwkOff.isSystemOnly()) {
             InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering.");
             if (newNtwkOff != null) {
-                ex.addProxyObject(String.valueOf(newNtwkOff.getId()), "networkOfferingId");
+                ex.addProxyObject(String.valueOf(newNtwkOff.getId()), NETWORK_OFFERING_ID);
             }
             throw ex;
         }
@@ -4078,7 +4209,7 @@
         for (String vlanRange : listOfRanges) {
             String[] VnetRange = vlanRange.split("-");
 
-            // Init with [min,max] of VLAN. Actually 0x000 and 0xFFF are reserved by IEEE, shoudn't be used.
+            // Init with [min,max] of VLAN. Actually 0x000 and 0xFFF are reserved by IEEE, shouldn't be used.
             long minVnet = MIN_VLAN_ID;
             long maxVnet = MAX_VLAN_ID;
 
diff --git a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
index 3c51e12..c9c0e83 100644
--- a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
@@ -2351,7 +2351,7 @@
             }
         }
 
-        List<UserVmVO> userVms = _vmDao.listVirtualNetworkInstancesByAcctAndNetwork(loadBalancer.getAccountId(), loadBalancer.getNetworkId());
+        List<UserVmVO> userVms = _vmDao.listByIds(appliedInstanceIdList);
 
         for (UserVmVO userVm : userVms) {
             // if the VM is destroyed, being expunged, in an error state, or in
diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java
index 9343360..99d3e7d 100644
--- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java
+++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java
@@ -542,6 +542,7 @@
 
                 router.setDynamicallyScalable(template.isDynamicallyScalable());
                 router.setRole(Role.VIRTUAL_ROUTER);
+                router.setLimitCpuUse(routerOffering.getLimitCpuUse());
                 router = _routerDao.persist(router);
 
                 reallocateRouterNetworks(routerDeploymentDefinition, router, template, null);
diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
index f568266..4456f10 100644
--- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
@@ -53,7 +53,9 @@
 import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd;
 import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd;
 import org.apache.cloudstack.api.command.user.vpc.ListVPCOfferingsCmd;
+import org.apache.cloudstack.api.command.user.vpc.ListVPCsCmd;
 import org.apache.cloudstack.api.command.user.vpc.RestartVPCCmd;
+import org.apache.cloudstack.api.command.user.vpc.UpdateVPCCmd;
 import org.apache.cloudstack.context.CallContext;
 import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
@@ -62,6 +64,7 @@
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.log4j.Logger;
+import org.jetbrains.annotations.Nullable;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 
@@ -1017,7 +1020,7 @@
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create = true)
     public Vpc createVpc(final long zoneId, final long vpcOffId, final long vpcOwnerId, final String vpcName, final String displayText, final String cidr, String networkDomain,
-            final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2, final Boolean displayVpc, Integer publicMtu) throws ResourceAllocationException {
+                         final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2, final Boolean displayVpc, Integer publicMtu) throws ResourceAllocationException {
         final Account caller = CallContext.current().getCallingAccount();
         final Account owner = _accountMgr.getAccount(vpcOwnerId);
 
@@ -1091,6 +1094,7 @@
         final VpcVO vpc = new VpcVO(zoneId, vpcName, displayText, owner.getId(), owner.getDomainId(), vpcOffId, cidr, networkDomain, useDistributedRouter, isRegionLevelVpcOff,
                 vpcOff.isRedundantRouter(), ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2);
             vpc.setPublicMtu(publicMtu);
+            vpc.setDisplay(Boolean.TRUE.equals(displayVpc));
 
         return createVpc(displayVpc, vpc);
     }
@@ -1098,9 +1102,24 @@
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create = true)
     public Vpc createVpc(CreateVPCCmd cmd) throws ResourceAllocationException {
-        return createVpc(cmd.getZoneId(), cmd.getVpcOffering(), cmd.getEntityOwnerId(), cmd.getVpcName(), cmd.getDisplayText(),
+        Vpc vpc = createVpc(cmd.getZoneId(), cmd.getVpcOffering(), cmd.getEntityOwnerId(), cmd.getVpcName(), cmd.getDisplayText(),
             cmd.getCidr(), cmd.getNetworkDomain(), cmd.getIp4Dns1(), cmd.getIp4Dns2(), cmd.getIp6Dns1(),
             cmd.getIp6Dns2(), cmd.isDisplay(), cmd.getPublicMtu());
+        // associate cmd.getSourceNatIP() with this vpc
+        allocateSourceNatIp(vpc, cmd.getSourceNatIP());
+        return vpc;
+    }
+
+    private void allocateSourceNatIp(Vpc vpc, String sourceNatIP) {
+        Account account = _accountMgr.getAccount(vpc.getAccountId());
+        DataCenter zone = _dcDao.findById(vpc.getZoneId());
+        // reserve this ip and then
+        try {
+            IpAddress ip = _ipAddrMgr.allocateIp(account, false, CallContext.current().getCallingAccount(), CallContext.current().getCallingUserId(), zone, null, sourceNatIP);
+            this.associateIPToVpc(ip.getId(), vpc.getId());
+        } catch (ResourceAllocationException | ResourceUnavailableException | InsufficientAddressCapacityException e){
+            throw new CloudRuntimeException("new source NAT address cannot be acquired", e);
+        }
     }
 
     @DB
@@ -1126,10 +1145,6 @@
         return Transaction.execute(new TransactionCallback<VpcVO>() {
             @Override
             public VpcVO doInTransaction(final TransactionStatus status) {
-                if (displayVpc != null) {
-                    vpc.setDisplay(displayVpc);
-                }
-
                 final VpcVO persistedVpc = vpcDao.persist(vpc, finalizeServicesAndProvidersForVpc(vpc.getZoneId(), vpc.getVpcOfferingId()));
                 _resourceLimitMgr.incrementResourceCount(vpc.getAccountId(), ResourceType.vpc);
                 s_logger.debug("Created VPC " + persistedVpc);
@@ -1243,8 +1258,13 @@
     }
 
     @Override
+    public Vpc updateVpc(UpdateVPCCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException {
+        return updateVpc(cmd.getId(), cmd.getVpcName(), cmd.getDisplayText(), cmd.getCustomId(), cmd.isDisplayVpc(), cmd.getPublicMtu(), cmd.getSourceNatIP());
+    }
+
+    @Override
     @ActionEvent(eventType = EventTypes.EVENT_VPC_UPDATE, eventDescription = "updating vpc")
-    public Vpc updateVpc(final long vpcId, final String vpcName, final String displayText, final String customId, final Boolean displayVpc, Integer mtu) {
+    public Vpc updateVpc(final long vpcId, final String vpcName, final String displayText, final String customId, final Boolean displayVpc, Integer mtu, String sourceNatIp) throws ResourceUnavailableException, InsufficientCapacityException {
         CallContext.current().setEventDetails(" Id: " + vpcId);
         final Account caller = CallContext.current().getCallingAccount();
 
@@ -1279,14 +1299,80 @@
             updateMtuOfVpcNetwork(vpcToUpdate, vpc, mtu);
         }
 
-        if (vpcDao.update(vpcId, vpc)) {
+        boolean restartRequired = checkAndUpdateRouterSourceNatIp(vpcToUpdate, sourceNatIp);
+
+        if (vpcDao.update(vpcId, vpc) || restartRequired) { // Note that the update may fail because nothing has changed, other than the sourcenat ip
             s_logger.debug("Updated VPC id=" + vpcId);
+            if (restartRequired) {
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug(String.format("restarting vpc %s/%s, due to changing sourcenat in Update VPC call", vpc.getName(), vpc.getUuid()));
+                }
+                final User callingUser = _accountMgr.getActiveUser(CallContext.current().getCallingUserId());
+                restartVpc(vpcId, true, false, false, callingUser);
+            } else {
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("no restart needed.");
+                }
+            }
             return vpcDao.findById(vpcId);
         } else {
+            s_logger.error(String.format("failed to update vpc %s/%s",vpc.getName(), vpc.getUuid()));
             return null;
         }
     }
 
+    private boolean checkAndUpdateRouterSourceNatIp(Vpc vpc, String sourceNatIp) {
+        IPAddressVO requestedIp = validateSourceNatip(vpc, sourceNatIp);
+        if (requestedIp == null) return false; // ip not associated with this network
+
+        List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedVpc(vpc.getId(), true);
+        if (! userIps.isEmpty()) {
+            try {
+                _ipAddrMgr.updateSourceNatIpAddress(requestedIp, userIps);
+            } catch (Exception e) { // pokemon exception from transaction
+                String msg = String.format("Update of source NAT ip to %s for network \"%s\"/%s failed due to %s",
+                        requestedIp.getAddress().addr(), vpc.getName(), vpc.getUuid(), e.getLocalizedMessage());
+                s_logger.error(msg);
+                throw new CloudRuntimeException(msg, e);
+            }
+        }
+        return true;
+    }
+
+    @Nullable
+    protected IPAddressVO validateSourceNatip(Vpc vpc, String sourceNatIp) {
+        if (sourceNatIp == null) {
+            s_logger.trace(String.format("no source NAT ip given to update vpc %s with.", vpc.getName()));
+            return null;
+        } else {
+            s_logger.info(String.format("updating VPC %s to have source NAT ip %s", vpc.getName(), sourceNatIp));
+        }
+        IPAddressVO requestedIp = getIpAddressVO(vpc, sourceNatIp);
+        if (requestedIp == null) return null;
+        // check if it is the current source NAT address
+        if (requestedIp.isSourceNat()) {
+            s_logger.info(String.format("IP address %s is already the source Nat address. Not updating!", sourceNatIp));
+            return null;
+        }
+        if (_firewallDao.countRulesByIpId(requestedIp.getId()) > 0) {
+            s_logger.info(String.format("IP address %s has firewall/portforwarding rules. Not updating!", sourceNatIp));
+            return null;
+        }
+        return requestedIp;
+    }
+
+    @Nullable
+    private IPAddressVO getIpAddressVO(Vpc vpc, String sourceNatIp) {
+        // check if the address is already aqcuired for this network
+        IPAddressVO requestedIp = _ipAddressDao.findByIp(sourceNatIp);
+        if (requestedIp == null || requestedIp.getVpcId() == null || ! requestedIp.getVpcId().equals(vpc.getId())) {
+            s_logger.warn(String.format("Source NAT IP %s is not associated with network %s/%s. It cannot be used as source NAT IP.",
+                    sourceNatIp, vpc.getName(), vpc.getUuid()));
+            return null;
+        }
+        return requestedIp;
+    }
+
     protected Integer validateMtu(VpcVO vpcToUpdate, Integer mtu) {
         Long zoneId = vpcToUpdate.getZoneId();
         if (mtu == null || NetworkService.AllowUsersToSpecifyVRMtu.valueIn(zoneId)) {
@@ -1374,6 +1460,13 @@
     }
 
     @Override
+    public Pair<List<? extends Vpc>, Integer> listVpcs(ListVPCsCmd cmd) {
+        return listVpcs(cmd.getId(), cmd.getVpcName(), cmd.getDisplayText(), cmd.getSupportedServices(), cmd.getCidr(), cmd.getVpcOffId(),
+                cmd.getState(), cmd.getAccountName(), cmd.getDomainId(), cmd.getKeyword(), cmd.getStartIndex(), cmd.getPageSizeVal(),
+                cmd.getZoneId(), cmd.isRecursive(), cmd.listAll(), cmd.getRestartRequired(), cmd.getTags(), cmd.getProjectId(),
+                cmd.getDisplay());
+    }
+    @Override
     public Pair<List<? extends Vpc>, Integer> listVpcs(final Long id, final String vpcName, final String displayText, final List<String> supportedServicesStr, final String cidr,
                                                        final Long vpcOffId, final String state, final String accountName, Long domainId, final String keyword, final Long startIndex, final Long pageSizeVal,
                                                        final Long zoneId, Boolean isRecursive, final Boolean listAll, final Boolean restartRequired, final Map<String, String> tags, final Long projectId,
@@ -1476,7 +1569,7 @@
         final boolean listBySupportedServices = supportedServicesStr != null && !supportedServicesStr.isEmpty() && !vpcs.isEmpty();
 
         if (listBySupportedServices) {
-            final List<VpcVO> supportedVpcs = new ArrayList<VpcVO>();
+            final List<Vpc> supportedVpcs = new ArrayList<>();
             Service[] supportedServices = null;
 
             if (listBySupportedServices) {
@@ -1501,22 +1594,20 @@
 
             final List<? extends Vpc> wPagination = StringUtils.applyPagination(supportedVpcs, startIndex, pageSizeVal);
             if (wPagination != null) {
-                final Pair<List<? extends Vpc>, Integer> listWPagination = new Pair<List<? extends Vpc>, Integer>(wPagination, supportedVpcs.size());
-                return listWPagination;
+                return new Pair<>(wPagination, supportedVpcs.size());
             }
-            return new Pair<List<? extends Vpc>, Integer>(supportedVpcs, supportedVpcs.size());
+            return new Pair<>(supportedVpcs, supportedVpcs.size());
         } else {
             final List<? extends Vpc> wPagination = StringUtils.applyPagination(vpcs, startIndex, pageSizeVal);
             if (wPagination != null) {
-                final Pair<List<? extends Vpc>, Integer> listWPagination = new Pair<List<? extends Vpc>, Integer>(wPagination, vpcs.size());
-                return listWPagination;
+                return new Pair<>(wPagination, vpcs.size());
             }
-            return new Pair<List<? extends Vpc>, Integer>(vpcs, vpcs.size());
+            return new Pair<>(vpcs, vpcs.size());
         }
     }
 
     protected List<Service> getSupportedServices() {
-        final List<Service> services = new ArrayList<Service>();
+        final List<Service> services = new ArrayList<>();
         services.add(Network.Service.Dhcp);
         services.add(Network.Service.Dns);
         services.add(Network.Service.UserData);
@@ -1764,10 +1855,8 @@
                         }
                     }
 
-                    // 4) vpc and network should belong to the same owner
-                    if (vpc.getAccountId() != networkOwner.getId()) {
-                        throw new InvalidParameterValueException("Vpc " + vpc + " owner is different from the network owner " + networkOwner);
-                    }
+                    // 4) Vpc's account should be able to access network owner's account
+                    CheckAccountsAccess(vpc, networkOwner);
 
                     // 5) network domain should be the same as VPC's
                     if (!networkDomain.equalsIgnoreCase(vpc.getNetworkDomain())) {
@@ -1786,6 +1875,17 @@
         });
     }
 
+    private void CheckAccountsAccess(Vpc vpc, Account networkAccount) {
+        Account vpcaccount = _accountMgr.getAccount(vpc.getAccountId());
+        try {
+            _accountMgr.checkAccess(vpcaccount, null, false, networkAccount);
+        }
+        catch (PermissionDeniedException e) {
+            s_logger.error(e.getMessage());
+            throw new InvalidParameterValueException(String.format("VPC owner does not have access to account [%s].", networkAccount.getAccountName()));
+        }
+    }
+
     public List<VpcProvider> getVpcElements() {
         if (vpcElements == null) {
             vpcElements = new ArrayList<VpcProvider>();
@@ -2788,11 +2888,11 @@
         }
 
         // check permissions
-        _accountMgr.checkAccess(caller, null, true, owner, vpc);
+        _accountMgr.checkAccess(caller, null, false, owner, vpc);
 
         s_logger.debug("Associating ip " + ipToAssoc + " to vpc " + vpc);
 
-        final boolean isSourceNatFinal = isSrcNatIpRequired(vpc.getVpcOfferingId()) && getExistingSourceNatInVpc(owner.getId(), vpcId) == null;
+        final boolean isSourceNatFinal = isSrcNatIpRequired(vpc.getVpcOfferingId()) && getExistingSourceNatInVpc(vpc.getAccountId(), vpcId) == null;
         Transaction.execute(new TransactionCallbackNoReturn() {
             @Override
             public void doInTransactionWithoutResult(final TransactionStatus status) {
diff --git a/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java b/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java
index f87ab4a..19776d4 100644
--- a/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java
+++ b/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java
@@ -18,9 +18,11 @@
 
 import java.io.UnsupportedEncodingException;
 import java.security.SecureRandom;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
 import java.util.TimeZone;
 import java.util.UUID;
 import java.util.concurrent.Executors;
@@ -33,26 +35,20 @@
 import javax.mail.MessagingException;
 import javax.naming.ConfigurationException;
 
-import com.cloud.network.dao.NetworkDao;
-import com.cloud.network.dao.NetworkVO;
-import com.cloud.network.vpc.Vpc;
-import com.cloud.network.vpc.VpcManager;
-import com.cloud.storage.VMTemplateVO;
-import com.cloud.storage.VolumeVO;
-import com.cloud.storage.dao.VMTemplateDao;
-import com.cloud.storage.dao.VolumeDao;
-import com.cloud.vm.UserVmVO;
-import com.cloud.vm.dao.UserVmDao;
-import com.cloud.vm.snapshot.VMSnapshotVO;
-import com.cloud.vm.snapshot.dao.VMSnapshotDao;
 import org.apache.cloudstack.acl.ProjectRole;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import org.apache.cloudstack.acl.dao.ProjectRoleDao;
 import org.apache.cloudstack.context.CallContext;
+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.framework.messagebus.MessageBus;
 import org.apache.cloudstack.framework.messagebus.PublishScope;
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
+import org.apache.cloudstack.utils.mailing.MailAddress;
+import org.apache.cloudstack.utils.mailing.SMTPMailProperties;
+import org.apache.cloudstack.utils.mailing.SMTPMailSender;
+import org.apache.commons.lang3.BooleanUtils;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
@@ -72,11 +68,19 @@
 import com.cloud.exception.PermissionDeniedException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.vpc.Vpc;
+import com.cloud.network.vpc.VpcManager;
 import com.cloud.projects.Project.State;
 import com.cloud.projects.ProjectAccount.Role;
 import com.cloud.projects.dao.ProjectAccountDao;
 import com.cloud.projects.dao.ProjectDao;
 import com.cloud.projects.dao.ProjectInvitationDao;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.storage.dao.VolumeDao;
 import com.cloud.tags.dao.ResourceTagDao;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
@@ -95,14 +99,10 @@
 import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
 import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
-import java.util.HashSet;
-import java.util.Set;
-import org.apache.cloudstack.framework.config.ConfigKey;
-import org.apache.cloudstack.framework.config.Configurable;
-import org.apache.cloudstack.utils.mailing.MailAddress;
-import org.apache.cloudstack.utils.mailing.SMTPMailProperties;
-import org.apache.cloudstack.utils.mailing.SMTPMailSender;
-import org.apache.commons.lang3.BooleanUtils;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.snapshot.VMSnapshotVO;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
 
 @Component
 public class ProjectManagerImpl extends ManagerBase implements ProjectManager, Configurable {
@@ -650,7 +650,7 @@
     @Override
     @DB
     @ActionEvent(eventType = EventTypes.EVENT_PROJECT_UPDATE, eventDescription = "updating project", async = true)
-    public Project updateProject(final long projectId, final String displayText, final String newOwnerName) throws ResourceAllocationException {
+    public Project updateProject(final long projectId, String name, final String displayText, final String newOwnerName) throws ResourceAllocationException {
         Account caller = CallContext.current().getCallingAccount();
 
         //check that the project exists
@@ -666,10 +666,7 @@
         Transaction.execute(new TransactionCallbackWithExceptionNoReturn<ResourceAllocationException>() {
             @Override
             public void doInTransactionWithoutResult(TransactionStatus status) throws ResourceAllocationException {
-                if (displayText != null) {
-                    project.setDisplayText(displayText);
-                    _projectDao.update(projectId, project);
-                }
+                updateProjectNameAndDisplayText(project, name, displayText);
 
                 if (newOwnerName != null) {
                     //check that the new owner exists
@@ -717,7 +714,7 @@
     @Override
     @DB
     @ActionEvent(eventType = EventTypes.EVENT_PROJECT_UPDATE, eventDescription = "updating project", async = true)
-    public Project updateProject(final long projectId, final String displayText, final String newOwnerName, Long userId,
+    public Project updateProject(final long projectId, String name, final String displayText, final String newOwnerName, Long userId,
                                  Role newRole) throws ResourceAllocationException {
         Account caller = CallContext.current().getCallingAccount();
 
@@ -737,10 +734,8 @@
         Transaction.execute(new TransactionCallbackWithExceptionNoReturn<ResourceAllocationException>() {
             @Override
             public void doInTransactionWithoutResult(TransactionStatus status) throws ResourceAllocationException {
-                if (displayText != null) {
-                    project.setDisplayText(displayText);
-                    _projectDao.update(projectId, project);
-                }
+                updateProjectNameAndDisplayText(project, name, displayText);
+
                 if (newOwnerName != null) {
                     //check that the new owner exists
                     Account updatedAcc = _accountMgr.getActiveAccountByName(newOwnerName, project.getDomainId());
@@ -1443,4 +1438,17 @@
     public ConfigKey<?>[] getConfigKeys() {
         return new ConfigKey<?>[] {ProjectSmtpEnabledSecurityProtocols, ProjectSmtpUseStartTLS};
     }
+
+    protected void updateProjectNameAndDisplayText(final ProjectVO project, String name, String displayText) {
+        if (name == null && displayText == null){
+            return;
+        }
+        if (name != null) {
+            project.setName(name);
+        }
+        if (displayText != null) {
+            project.setDisplayText(displayText);
+        }
+        _projectDao.update(project.getId(), project);
+    }
 }
diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java
index 1909063..150aed6 100755
--- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java
+++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java
@@ -36,11 +36,13 @@
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.alert.AlertManager;
 import com.cloud.exception.StorageConflictException;
 import com.cloud.exception.StorageUnavailableException;
 import com.cloud.storage.Volume;
 import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.VolumeDao;
+import org.apache.cloudstack.alert.AlertService;
 import org.apache.cloudstack.annotation.AnnotationService;
 import org.apache.cloudstack.annotation.dao.AnnotationDao;
 import org.apache.cloudstack.api.ApiConstants;
@@ -298,6 +300,10 @@
     @Inject
     private AnnotationDao annotationDao;
     @Inject
+    private AlertManager alertManager;
+    @Inject
+    private AnnotationService annotationService;
+    @Inject
     private VolumeDao volumeDao;
 
     private final long _nodeId = ManagementServerNode.getManagementServerId();
@@ -1801,73 +1807,149 @@
         return hostInMaintenance;
     }
 
+    private ResourceState.Event getResourceEventFromAllocationStateString(String allocationState) {
+        final ResourceState.Event resourceEvent = ResourceState.Event.toEvent(allocationState);
+        if (resourceEvent != ResourceState.Event.Enable && resourceEvent != ResourceState.Event.Disable) {
+            throw new InvalidParameterValueException(String.format("Invalid allocation state: %s, " +
+                    "only Enable/Disable are allowed", allocationState));
+        }
+        return resourceEvent;
+    }
+
+    private void handleAutoEnableDisableKVMHost(boolean autoEnableDisableKVMSetting,
+                                                boolean isUpdateFromHostHealthCheck,
+                                                HostVO host, DetailVO hostDetail,
+                                                ResourceState.Event resourceEvent) {
+        if (autoEnableDisableKVMSetting) {
+            if (!isUpdateFromHostHealthCheck && hostDetail != null &&
+                    !Boolean.parseBoolean(hostDetail.getValue()) && resourceEvent == ResourceState.Event.Enable) {
+                hostDetail.setValue(Boolean.TRUE.toString());
+                _hostDetailsDao.update(hostDetail.getId(), hostDetail);
+            } else if (!isUpdateFromHostHealthCheck && hostDetail != null &&
+                    Boolean.parseBoolean(hostDetail.getValue()) && resourceEvent == ResourceState.Event.Disable) {
+                s_logger.info(String.format("The setting %s is enabled but the host %s is manually set into %s state," +
+                                "ignoring future auto enabling of the host based on health check results",
+                        AgentManager.EnableKVMAutoEnableDisable.key(), host.getName(), resourceEvent));
+                hostDetail.setValue(Boolean.FALSE.toString());
+                _hostDetailsDao.update(hostDetail.getId(), hostDetail);
+            } else if (hostDetail == null) {
+                String autoEnableValue = !isUpdateFromHostHealthCheck ? Boolean.FALSE.toString() : Boolean.TRUE.toString();
+                hostDetail = new DetailVO(host.getId(), ApiConstants.AUTO_ENABLE_KVM_HOST, autoEnableValue);
+                _hostDetailsDao.persist(hostDetail);
+            }
+        }
+    }
+    private boolean updateHostAllocationState(HostVO host, String allocationState,
+                                           boolean isUpdateFromHostHealthCheck) throws NoTransitionException {
+        boolean autoEnableDisableKVMSetting = AgentManager.EnableKVMAutoEnableDisable.valueIn(host.getClusterId()) &&
+                host.getHypervisorType() == HypervisorType.KVM;
+        ResourceState.Event resourceEvent = getResourceEventFromAllocationStateString(allocationState);
+        DetailVO hostDetail = _hostDetailsDao.findDetail(host.getId(), ApiConstants.AUTO_ENABLE_KVM_HOST);
+
+        if ((host.getResourceState() == ResourceState.Enabled && resourceEvent == ResourceState.Event.Enable) ||
+                (host.getResourceState() == ResourceState.Disabled && resourceEvent == ResourceState.Event.Disable)) {
+            s_logger.info(String.format("The host %s is already on the allocated state", host.getName()));
+            return false;
+        }
+
+        if (isAutoEnableAttemptForADisabledHost(autoEnableDisableKVMSetting, isUpdateFromHostHealthCheck, hostDetail, resourceEvent)) {
+            s_logger.debug(String.format("The setting '%s' is enabled and the health check succeeds on the host, " +
+                            "but the host has been manually disabled previously, ignoring auto enabling",
+                    AgentManager.EnableKVMAutoEnableDisable.key()));
+            return false;
+        }
+
+        handleAutoEnableDisableKVMHost(autoEnableDisableKVMSetting, isUpdateFromHostHealthCheck, host,
+                hostDetail, resourceEvent);
+
+        resourceStateTransitTo(host, resourceEvent, _nodeId);
+        return true;
+    }
+
+    private boolean isAutoEnableAttemptForADisabledHost(boolean autoEnableDisableKVMSetting,
+                                                        boolean isUpdateFromHostHealthCheck,
+                                                        DetailVO hostDetail, ResourceState.Event resourceEvent) {
+        return autoEnableDisableKVMSetting && isUpdateFromHostHealthCheck && hostDetail != null &&
+                !Boolean.parseBoolean(hostDetail.getValue()) && resourceEvent == ResourceState.Event.Enable;
+    }
+
+    private void updateHostName(HostVO host, String name) {
+        s_logger.debug("Updating Host name to: " + name);
+        host.setName(name);
+        _hostDao.update(host.getId(), host);
+    }
+
+    private void updateHostGuestOSCategory(Long hostId, Long guestOSCategoryId) {
+        // Verify that the guest OS Category exists
+        if (!(guestOSCategoryId > 0) || _guestOSCategoryDao.findById(guestOSCategoryId) == null) {
+            throw new InvalidParameterValueException("Please specify a valid guest OS category.");
+        }
+
+        final GuestOSCategoryVO guestOSCategory = _guestOSCategoryDao.findById(guestOSCategoryId);
+        final DetailVO guestOSDetail = _hostDetailsDao.findDetail(hostId, "guest.os.category.id");
+
+        if (guestOSCategory != null && !GuestOSCategoryVO.CATEGORY_NONE.equalsIgnoreCase(guestOSCategory.getName())) {
+            // Create/Update an entry for guest.os.category.id
+            if (guestOSDetail != null) {
+                guestOSDetail.setValue(String.valueOf(guestOSCategory.getId()));
+                _hostDetailsDao.update(guestOSDetail.getId(), guestOSDetail);
+            } else {
+                final Map<String, String> detail = new HashMap<String, String>();
+                detail.put("guest.os.category.id", String.valueOf(guestOSCategory.getId()));
+                _hostDetailsDao.persist(hostId, detail);
+            }
+        } else {
+            // Delete any existing entry for guest.os.category.id
+            if (guestOSDetail != null) {
+                _hostDetailsDao.remove(guestOSDetail.getId());
+            }
+        }
+    }
+
+    private void updateHostTags(HostVO host, Long hostId, List<String> hostTags) {
+        List<VMInstanceVO> activeVMs =  _vmDao.listByHostId(hostId);
+        s_logger.warn(String.format("The following active VMs [%s] are using the host [%s]. " +
+                "Updating the host tags will not affect them.", activeVMs, host));
+
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Updating Host Tags to :" + hostTags);
+        }
+        _hostTagsDao.persist(hostId, new ArrayList<>(new HashSet<>(hostTags)));
+    }
+
     @Override
     public Host updateHost(final UpdateHostCmd cmd) throws NoTransitionException {
-        Long hostId = cmd.getId();
-        String name = cmd.getName();
-        Long guestOSCategoryId = cmd.getOsCategoryId();
+        return updateHost(cmd.getId(), cmd.getName(), cmd.getOsCategoryId(),
+                cmd.getAllocationState(), cmd.getUrl(), cmd.getHostTags(), cmd.getAnnotation(), false);
+    }
 
+    private Host updateHost(Long hostId, String name, Long guestOSCategoryId, String allocationState,
+                            String url, List<String> hostTags, String annotation, boolean isUpdateFromHostHealthCheck) throws NoTransitionException {
         // Verify that the host exists
         final HostVO host = _hostDao.findById(hostId);
         if (host == null) {
             throw new InvalidParameterValueException("Host with id " + hostId + " doesn't exist");
         }
 
-        if (cmd.getAllocationState() != null) {
-            final ResourceState.Event resourceEvent = ResourceState.Event.toEvent(cmd.getAllocationState());
-            if (resourceEvent != ResourceState.Event.Enable && resourceEvent != ResourceState.Event.Disable) {
-                throw new CloudRuntimeException("Invalid allocation state:" + cmd.getAllocationState() + ", only Enable/Disable are allowed");
-            }
-
-            resourceStateTransitTo(host, resourceEvent, _nodeId);
+        boolean isUpdateHostAllocation = false;
+        if (StringUtils.isNotBlank(allocationState)) {
+            isUpdateHostAllocation = updateHostAllocationState(host, allocationState, isUpdateFromHostHealthCheck);
         }
 
         if (StringUtils.isNotBlank(name)) {
-            s_logger.debug("Updating Host name to: " + name);
-            host.setName(name);
-            _hostDao.update(host.getId(), host);
+            updateHostName(host, name);
         }
 
         if (guestOSCategoryId != null) {
-            // Verify that the guest OS Category exists
-            if (!(guestOSCategoryId > 0) || _guestOSCategoryDao.findById(guestOSCategoryId) == null) {
-                throw new InvalidParameterValueException("Please specify a valid guest OS category.");
-            }
-
-            final GuestOSCategoryVO guestOSCategory = _guestOSCategoryDao.findById(guestOSCategoryId);
-            final DetailVO guestOSDetail = _hostDetailsDao.findDetail(hostId, "guest.os.category.id");
-
-            if (guestOSCategory != null && !GuestOSCategoryVO.CATEGORY_NONE.equalsIgnoreCase(guestOSCategory.getName())) {
-                // Create/Update an entry for guest.os.category.id
-                if (guestOSDetail != null) {
-                    guestOSDetail.setValue(String.valueOf(guestOSCategory.getId()));
-                    _hostDetailsDao.update(guestOSDetail.getId(), guestOSDetail);
-                } else {
-                    final Map<String, String> detail = new HashMap<String, String>();
-                    detail.put("guest.os.category.id", String.valueOf(guestOSCategory.getId()));
-                    _hostDetailsDao.persist(hostId, detail);
-                }
-            } else {
-                // Delete any existing entry for guest.os.category.id
-                if (guestOSDetail != null) {
-                    _hostDetailsDao.remove(guestOSDetail.getId());
-                }
-            }
+            updateHostGuestOSCategory(hostId, guestOSCategoryId);
         }
-        final List<String> hostTags = cmd.getHostTags();
+
         if (hostTags != null) {
-            List<VMInstanceVO> activeVMs =  _vmDao.listByHostId(hostId);
-            s_logger.warn(String.format("The following active VMs [%s] are using the host [%s]. Updating the host tags will not affect them.", activeVMs, host));
-
-            if (s_logger.isDebugEnabled()) {
-                s_logger.debug("Updating Host Tags to :" + hostTags);
-            }
-            _hostTagsDao.persist(hostId, new ArrayList(new HashSet<String>(hostTags)));
+            updateHostTags(host, hostId, hostTags);
         }
 
-        final String url = cmd.getUrl();
         if (url != null) {
-            _storageMgr.updateSecondaryStorage(cmd.getId(), cmd.getUrl());
+            _storageMgr.updateSecondaryStorage(hostId, url);
         }
         try {
             _storageMgr.enableHost(hostId);
@@ -1876,9 +1958,55 @@
         }
 
         final HostVO updatedHost = _hostDao.findById(hostId);
+
+        sendAlertAndAnnotationForAutoEnableDisableKVMHostFeature(host, allocationState,
+                isUpdateFromHostHealthCheck, isUpdateHostAllocation, annotation);
+
         return updatedHost;
     }
 
+    private void sendAlertAndAnnotationForAutoEnableDisableKVMHostFeature(HostVO host, String allocationState,
+                                                                          boolean isUpdateFromHostHealthCheck,
+                                                                          boolean isUpdateHostAllocation, String annotation) {
+        boolean isAutoEnableDisableKVMSettingEnabled = host.getHypervisorType() == HypervisorType.KVM &&
+                AgentManager.EnableKVMAutoEnableDisable.valueIn(host.getClusterId());
+        if (!isAutoEnableDisableKVMSettingEnabled) {
+            if (StringUtils.isNotBlank(annotation)) {
+                annotationService.addAnnotation(annotation, AnnotationService.EntityType.HOST, host.getUuid(), true);
+            }
+            return;
+        }
+
+        if (!isUpdateHostAllocation) {
+            return;
+        }
+
+        String msg = String.format("The host %s (%s) ", host.getName(), host.getUuid());
+        ResourceState.Event resourceEvent = getResourceEventFromAllocationStateString(allocationState);
+        boolean isEventEnable = resourceEvent == ResourceState.Event.Enable;
+
+        if (isUpdateFromHostHealthCheck) {
+            msg += String.format("is auto-%s after %s health check results",
+                    isEventEnable ? "enabled" : "disabled",
+                    isEventEnable ? "successful" : "failed");
+            alertManager.sendAlert(AlertService.AlertType.ALERT_TYPE_HOST, host.getDataCenterId(),
+                    host.getPodId(), msg, msg);
+        } else {
+            msg += String.format("is %s despite the setting '%s' is enabled for the cluster %s",
+                    isEventEnable ? "enabled" : "disabled", AgentManager.EnableKVMAutoEnableDisable.key(),
+                    host.getClusterId());
+            if (StringUtils.isNotBlank(annotation)) {
+                msg += String.format(", reason: %s", annotation);
+            }
+        }
+        annotationService.addAnnotation(msg, AnnotationService.EntityType.HOST, host.getUuid(), true);
+    }
+
+    @Override
+    public Host autoUpdateHostAllocationState(Long hostId, ResourceState.Event resourceEvent) throws NoTransitionException {
+        return updateHost(hostId, null, null, resourceEvent.toString(), null, null, null, true);
+    }
+
     @Override
     public Cluster getCluster(final Long clusterId) {
         return _clusterDao.findById(clusterId);
diff --git a/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java b/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
index 288315d..51b1635 100644
--- a/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
+++ b/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java
@@ -1169,12 +1169,28 @@
         @Override
         protected void runInContext() {
             s_logger.info("Started resource counters recalculation periodic task.");
-            List<DomainVO> domains = _domainDao.findImmediateChildrenForParent(Domain.ROOT_DOMAIN);
-            List<AccountVO> accounts = _accountDao.findActiveAccountsForDomain(Domain.ROOT_DOMAIN);
+            List<DomainVO> domains;
+            List<AccountVO> accounts;
+            // try/catch task, otherwise it won't be rescheduled in case of exception
+            try {
+                domains = _domainDao.findImmediateChildrenForParent(Domain.ROOT_DOMAIN);
+            } catch (Exception e) {
+                s_logger.warn("Resource counters recalculation periodic task failed, unable to fetch immediate children for the domain " + Domain.ROOT_DOMAIN, e);
+                // initialize domains as empty list to do best effort recalculation
+                domains = new ArrayList<>();
+            }
+            // try/catch task, otherwise it won't be rescheduled in case of exception
+            try {
+                accounts = _accountDao.findActiveAccountsForDomain(Domain.ROOT_DOMAIN);
+            } catch (Exception e) {
+                s_logger.warn("Resource counters recalculation periodic task failed, unable to fetch active accounts for domain " + Domain.ROOT_DOMAIN, e);
+                // initialize accounts as empty list to do best effort recalculation
+                accounts = new ArrayList<>();
+            }
 
             for (ResourceType type : ResourceType.values()) {
                 if (type.supportsOwner(ResourceOwnerType.Domain)) {
-                    recalculateDomainResourceCount(Domain.ROOT_DOMAIN, type);
+                    recalculateDomainResourceCountInContext(Domain.ROOT_DOMAIN, type);
                     for (Domain domain : domains) {
                         recalculateDomainResourceCount(domain.getId(), type);
                     }
@@ -1183,10 +1199,25 @@
                 if (type.supportsOwner(ResourceOwnerType.Account)) {
                     // run through the accounts in the root domain
                     for (AccountVO account : accounts) {
-                        recalculateAccountResourceCount(account.getId(), type);
+                        recalculateAccountResourceCountInContext(account.getId(), type);
                     }
                 }
             }
         }
+
+        private void recalculateDomainResourceCountInContext(long domainId, ResourceType type) {
+            try {
+                recalculateDomainResourceCount(domainId, type);
+            } catch (Exception e) {
+                s_logger.warn("Resource counters recalculation periodic task failed for the domain " + domainId + " and the resource type " + type + " .", e);
+            }
+        }
+        private void recalculateAccountResourceCountInContext(long accountId, ResourceType type) {
+            try {
+                recalculateAccountResourceCount(accountId, type);
+            } catch (Exception e) {
+                s_logger.warn("Resource counters recalculation periodic task failed for the account " + accountId + " and the resource type " + type + " .", e);
+            }
+        }
     }
 }
diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
index 85e86b5..c16dc4e 100644
--- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
@@ -16,12 +16,7 @@
 // under the License.
 package com.cloud.server;
 
-import static com.cloud.configuration.ConfigurationManagerImpl.VM_USERDATA_MAX_LENGTH;
-import static com.cloud.vm.UserVmManager.MAX_USER_DATA_LENGTH_BYTES;
-
-import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Field;
-import java.net.URLDecoder;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -56,7 +51,6 @@
 import org.apache.cloudstack.annotation.dao.AnnotationDao;
 import org.apache.cloudstack.api.ApiCommandResourceType;
 import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.command.admin.account.CreateAccountCmd;
 import org.apache.cloudstack.api.command.admin.account.DeleteAccountCmd;
 import org.apache.cloudstack.api.command.admin.account.DisableAccountCmd;
@@ -95,6 +89,7 @@
 import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd;
 import org.apache.cloudstack.api.command.admin.guest.AddGuestOsCmd;
 import org.apache.cloudstack.api.command.admin.guest.AddGuestOsMappingCmd;
+import org.apache.cloudstack.api.command.admin.guest.GetHypervisorGuestOsNamesCmd;
 import org.apache.cloudstack.api.command.admin.guest.ListGuestOsMappingCmd;
 import org.apache.cloudstack.api.command.admin.guest.RemoveGuestOsCmd;
 import org.apache.cloudstack.api.command.admin.guest.RemoveGuestOsMappingCmd;
@@ -610,6 +605,7 @@
 import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
 import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
+import org.apache.cloudstack.userdata.UserDataManager;
 import org.apache.cloudstack.utils.CloudStackVersion;
 import org.apache.cloudstack.utils.identity.ManagementServerNode;
 import org.apache.commons.codec.binary.Base64;
@@ -619,7 +615,11 @@
 
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.CheckGuestOsMappingAnswer;
+import com.cloud.agent.api.CheckGuestOsMappingCommand;
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.GetHypervisorGuestOsNamesAnswer;
+import com.cloud.agent.api.GetHypervisorGuestOsNamesCommand;
 import com.cloud.agent.api.GetVncPortAnswer;
 import com.cloud.agent.api.GetVncPortCommand;
 import com.cloud.agent.api.PatchSystemVmAnswer;
@@ -691,7 +691,6 @@
 import com.cloud.host.dao.HostDao;
 import com.cloud.host.dao.HostDetailsDao;
 import com.cloud.host.dao.HostTagsDao;
-import com.cloud.hypervisor.Hypervisor;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.hypervisor.HypervisorCapabilities;
 import com.cloud.hypervisor.HypervisorCapabilitiesVO;
@@ -774,6 +773,7 @@
 import com.cloud.utils.crypt.DBEncryptionUtil;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericSearchBuilder;
 import com.cloud.utils.db.GlobalLock;
 import com.cloud.utils.db.JoinBuilder;
 import com.cloud.utils.db.JoinBuilder.JoinType;
@@ -821,10 +821,6 @@
     static final ConfigKey<Boolean> humanReadableSizes = new ConfigKey<Boolean>("Advanced", Boolean.class, "display.human.readable.sizes", "true", "Enables outputting human readable byte sizes to logs and usage records.", false, ConfigKey.Scope.Global);
     public static final ConfigKey<String> customCsIdentifier = new ConfigKey<String>("Advanced", String.class, "custom.cs.identifier", UUID.randomUUID().toString().split("-")[0].substring(4), "Custom identifier for the cloudstack installation", true, ConfigKey.Scope.Global);
     private static final VirtualMachine.Type []systemVmTypes = { VirtualMachine.Type.SecondaryStorageVm, VirtualMachine.Type.ConsoleProxy};
-
-    private static final int MAX_HTTP_GET_LENGTH = 2 * MAX_USER_DATA_LENGTH_BYTES;
-    private static final int NUM_OF_2K_BLOCKS = 512;
-    private static final int MAX_HTTP_POST_LENGTH = NUM_OF_2K_BLOCKS * MAX_USER_DATA_LENGTH_BYTES;
     private static final List<HypervisorType> LIVE_MIGRATION_SUPPORTING_HYPERVISORS = List.of(HypervisorType.Hyperv, HypervisorType.KVM,
             HypervisorType.LXC, HypervisorType.Ovm, HypervisorType.Ovm3, HypervisorType.Simulator, HypervisorType.VMware, HypervisorType.XenServer);
 
@@ -976,6 +972,8 @@
     protected VMTemplateDao templateDao;
     @Inject
     protected AnnotationDao annotationDao;
+    @Inject
+    UserDataManager userDataManager;
 
     private LockControllerListener _lockControllerListener;
     private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker"));
@@ -993,7 +991,7 @@
 
     protected List<DeploymentPlanner> _planners;
 
-    private final List<HypervisorType> supportedHypervisors = new ArrayList<Hypervisor.HypervisorType>();
+    private final List<HypervisorType> supportedHypervisors = new ArrayList<HypervisorType>();
 
     public List<DeploymentPlanner> getPlanners() {
         return _planners;
@@ -2635,6 +2633,17 @@
 
         if (id != null) {
             sc.addAnd("id", SearchCriteria.Op.EQ, id);
+        } else {
+            GenericSearchBuilder<GuestOSVO, Long> sb = _guestOSDao.createSearchBuilder(Long.class);
+            sb.select(null, SearchCriteria.Func.MAX, sb.entity().getId());
+            sb.groupBy(sb.entity().getCategoryId(), sb.entity().getDisplayName());
+            sb.done();
+
+            final SearchCriteria<Long> scGuestOs = sb.create();
+            final List<Long> guestOSVOList = _guestOSDao.customSearch(scGuestOs, null);
+            if (CollectionUtils.isNotEmpty(guestOSVOList)) {
+                sc.addAnd("id", SearchCriteria.Op.IN, guestOSVOList.toArray());
+            }
         }
 
         if (osCategoryId != null) {
@@ -2680,9 +2689,15 @@
 
     @Override
     public Pair<List<? extends GuestOSHypervisor>, Integer> listGuestOSMappingByCriteria(final ListGuestOsMappingCmd cmd) {
+        final String guestOsId = "guestOsId";
         final Filter searchFilter = new Filter(GuestOSHypervisorVO.class, "hypervisorType", true, cmd.getStartIndex(), cmd.getPageSizeVal());
+        searchFilter.addOrderBy(GuestOSHypervisorVO.class, "hypervisorVersion", false);
+        searchFilter.addOrderBy(GuestOSHypervisorVO.class, guestOsId, true);
+        searchFilter.addOrderBy(GuestOSHypervisorVO.class, "created", false);
         final Long id = cmd.getId();
         final Long osTypeId = cmd.getOsTypeId();
+        final String osDisplayName = cmd.getOsDisplayName();
+        final String osNameForHypervisor = cmd.getOsNameForHypervisor();
         final String hypervisor = cmd.getHypervisor();
         final String hypervisorVersion = cmd.getHypervisorVersion();
 
@@ -2698,15 +2713,27 @@
         }
 
         if (osTypeId != null) {
-            sc.addAnd("guestOsId", SearchCriteria.Op.EQ, osTypeId);
+            sc.addAnd(guestOsId, SearchCriteria.Op.EQ, osTypeId);
+        }
+
+        if (osNameForHypervisor != null) {
+            sc.addAnd("guestOsName", SearchCriteria.Op.LIKE, "%" + osNameForHypervisor + "%");
         }
 
         if (hypervisor != null) {
-            sc.addAnd("hypervisorType", SearchCriteria.Op.EQ, hypervisor);
+            sc.addAnd("hypervisorType", SearchCriteria.Op.LIKE, "%" + hypervisor + "%");
         }
 
         if (hypervisorVersion != null) {
-            sc.addAnd("hypervisorVersion", SearchCriteria.Op.EQ, hypervisorVersion);
+            sc.addAnd("hypervisorVersion", SearchCriteria.Op.LIKE, "%" + hypervisorVersion + "%");
+        }
+
+        if (osDisplayName != null) {
+            List<GuestOSVO> guestOSVOS = _guestOSDao.listLikeDisplayName(osDisplayName);
+            if (CollectionUtils.isNotEmpty(guestOSVOS)) {
+                List<Long> guestOSids = guestOSVOS.stream().map(mo -> mo.getId()).collect(Collectors.toList());
+                sc.addAnd(guestOsId, SearchCriteria.Op.IN, guestOSids.toArray());
+            }
         }
 
         final Pair<List<GuestOSHypervisorVO>, Integer> result = _guestOSHypervisorDao.searchAndCount(sc, searchFilter);
@@ -2724,7 +2751,7 @@
         final String osNameForHypervisor = cmd.getOsNameForHypervisor();
         GuestOS guestOs = null;
 
-        if (osTypeId == null && (osStdName == null || osStdName.isEmpty())) {
+        if (osTypeId == null && StringUtils.isEmpty(osStdName)) {
             throw new InvalidParameterValueException("Please specify either a guest OS name or UUID");
         }
 
@@ -2753,9 +2780,28 @@
         final GuestOSHypervisorVO duplicate = _guestOSHypervisorDao.findByOsIdAndHypervisorAndUserDefined(guestOs.getId(), hypervisorType.toString(), hypervisorVersion, true);
 
         if (duplicate != null) {
-            throw new InvalidParameterValueException(
-                    "Mapping from hypervisor : " + hypervisorType.toString() + ", version : " + hypervisorVersion + " and guest OS : " + guestOs.getDisplayName() + " already exists!");
+            if (!cmd.isForced()) {
+                throw new InvalidParameterValueException(
+                        "Mapping from hypervisor : " + hypervisorType.toString() + ", version : " + hypervisorVersion + " and guest OS : " + guestOs.getDisplayName() + " already exists!");
+            }
+
+            if (Boolean.TRUE.equals(cmd.getOsMappingCheckEnabled())) {
+                checkGuestOSHypervisorMapping(hypervisorType, hypervisorVersion, guestOs.getDisplayName(), osNameForHypervisor);
+            }
+
+            final long guestOsId = duplicate.getId();
+            final GuestOSHypervisorVO guestOsHypervisor = _guestOSHypervisorDao.createForUpdate(guestOsId);
+            guestOsHypervisor.setGuestOsName(osNameForHypervisor);
+            if (_guestOSHypervisorDao.update(guestOsId, guestOsHypervisor)) {
+                return _guestOSHypervisorDao.findById(guestOsId);
+            }
+            return null;
         }
+
+        if (Boolean.TRUE.equals(cmd.getOsMappingCheckEnabled())) {
+            checkGuestOSHypervisorMapping(hypervisorType, hypervisorVersion, guestOs.getDisplayName(), osNameForHypervisor);
+        }
+
         final GuestOSHypervisorVO guestOsMapping = new GuestOSHypervisorVO();
         guestOsMapping.setGuestOsId(guestOs.getId());
         guestOsMapping.setGuestOsName(osNameForHypervisor);
@@ -2763,7 +2809,24 @@
         guestOsMapping.setHypervisorVersion(hypervisorVersion);
         guestOsMapping.setIsUserDefined(true);
         return _guestOSHypervisorDao.persist(guestOsMapping);
+    }
 
+    private void checkGuestOSHypervisorMapping(HypervisorType hypervisorType, String hypervisorVersion, String guestOsName, String guestOsNameForHypervisor) {
+        if (!canCheckGuestOsNameInHypervisor(hypervisorType)) {
+            throw new InvalidParameterValueException(String.format("Guest OS mapping check is not supported for hypervisor: %s, please specify a valid hypervisor : VMware, XenServer", hypervisorType.toString()));
+        }
+        final HostVO host = _hostDao.findHostByHypervisorTypeAndVersion(hypervisorType, hypervisorVersion);
+        if (host == null) {
+            throw new CloudRuntimeException(String.format("No %s hypervisor with version: %s exists, please specify available hypervisor and version", hypervisorType.toString(), hypervisorVersion));
+        }
+        CheckGuestOsMappingAnswer answer = (CheckGuestOsMappingAnswer) _agentMgr.easySend(host.getId(), new CheckGuestOsMappingCommand(guestOsName, guestOsNameForHypervisor, hypervisorVersion));
+        if (answer == null || !answer.getResult()) {
+            throw new CloudRuntimeException(String.format("Invalid hypervisor os mapping: %s for guest os: %s, hypervisor: %s and version: %s", guestOsNameForHypervisor, guestOsName, hypervisorType.toString(), hypervisorVersion));
+        }
+    }
+
+    private boolean canCheckGuestOsNameInHypervisor(HypervisorType hypervisorType) {
+        return (hypervisorType == HypervisorType.VMware || hypervisorType == HypervisorType.XenServer);
     }
 
     @Override
@@ -2773,6 +2836,25 @@
     }
 
     @Override
+    @ActionEvent(eventType = EventTypes.EVENT_GUEST_OS_HYPERVISOR_NAME_FETCH, eventDescription = "Getting guest OS names from hypervisor", async = true)
+    public List<Pair<String, String>> getHypervisorGuestOsNames(GetHypervisorGuestOsNamesCmd getHypervisorGuestOsNamesCmd) {
+        final HypervisorType hypervisorType = HypervisorType.getType(getHypervisorGuestOsNamesCmd.getHypervisor());
+        if (!canCheckGuestOsNameInHypervisor(hypervisorType)) {
+            throw new InvalidParameterValueException(String.format("Guest OS names cannot be fetched for hypervisor: %s, please specify a valid hypervisor : VMware, XenServer", hypervisorType.toString()));
+        }
+
+        final HostVO host = _hostDao.findHostByHypervisorTypeAndVersion(hypervisorType, getHypervisorGuestOsNamesCmd.getHypervisorVersion());
+        if (host == null) {
+            throw new CloudRuntimeException(String.format("No %s hypervisor with version: %s exists, please specify available hypervisor and version", hypervisorType.toString(), getHypervisorGuestOsNamesCmd.getHypervisorVersion()));
+        }
+        GetHypervisorGuestOsNamesAnswer answer = (GetHypervisorGuestOsNamesAnswer) _agentMgr.easySend(host.getId(), new GetHypervisorGuestOsNamesCommand(getHypervisorGuestOsNamesCmd.getKeyword()));
+        if (answer == null || !answer.getResult()) {
+            throw new CloudRuntimeException(String.format("Unable to get guest os names for hypervisor: %s, version: %s", hypervisorType.toString(), getHypervisorGuestOsNamesCmd.getHypervisorVersion()));
+        }
+        return answer.getHypervisorGuestOsNames();
+    }
+
+    @Override
     @DB
     @ActionEvent(eventType = EventTypes.EVENT_GUEST_OS_ADD, eventDescription = "Adding new guest OS type", create = true)
     public GuestOS addGuestOs(final AddGuestOsCmd cmd) {
@@ -2893,6 +2975,14 @@
             throw new InvalidParameterValueException("Unable to modify system defined Guest OS mapping");
         }
 
+        if (Boolean.TRUE.equals(cmd.getOsMappingCheckEnabled())) {
+            GuestOS guestOs = ApiDBUtils.findGuestOSById(guestOsHypervisorHandle.getGuestOsId());
+            if (guestOs == null) {
+                throw new InvalidParameterValueException("Unable to find the guest OS for the mapping");
+            }
+            checkGuestOSHypervisorMapping(HypervisorType.getType(guestOsHypervisorHandle.getHypervisorType()), guestOsHypervisorHandle.getHypervisorVersion(), guestOs.getDisplayName(), osNameForHypervisor);
+        }
+
         final GuestOSHypervisorVO guestOsHypervisor = _guestOSHypervisorDao.createForUpdate(id);
         guestOsHypervisor.setGuestOsName(osNameForHypervisor);
         if (_guestOSHypervisorDao.update(id, guestOsHypervisor)) {
@@ -3469,6 +3559,7 @@
         cmdList.add(UpdateGuestOsMappingCmd.class);
         cmdList.add(RemoveGuestOsCmd.class);
         cmdList.add(RemoveGuestOsMappingCmd.class);
+        cmdList.add(GetHypervisorGuestOsNamesCmd.class);
         cmdList.add(AttachIsoCmd.class);
         cmdList.add(CopyIsoCmd.class);
         cmdList.add(DeleteIsoCmd.class);
@@ -4612,58 +4703,11 @@
         String userdata = cmd.getUserData();
         final String params = cmd.getParams();
 
-        userdata = validateUserData(userdata, cmd.getHttpMethod());
+        userdata = userDataManager.validateUserData(userdata, cmd.getHttpMethod());
 
         return createAndSaveUserData(name, userdata, params, owner);
     }
 
-    private String validateUserData(String userData, BaseCmd.HTTPMethod httpmethod) {
-        byte[] decodedUserData = null;
-        if (userData != null) {
-
-            if (userData.contains("%")) {
-                try {
-                    userData = URLDecoder.decode(userData, "UTF-8");
-                } catch (UnsupportedEncodingException e) {
-                    throw new InvalidParameterValueException("Url decoding of userdata failed.");
-                }
-            }
-
-            if (!Base64.isBase64(userData)) {
-                throw new InvalidParameterValueException("User data is not base64 encoded");
-            }
-            // If GET, use 4K. If POST, support up to 1M.
-            if (httpmethod.equals(BaseCmd.HTTPMethod.GET)) {
-                decodedUserData = validateAndDecodeByHTTPmethod(userData, MAX_HTTP_GET_LENGTH, BaseCmd.HTTPMethod.GET);
-            } else if (httpmethod.equals(BaseCmd.HTTPMethod.POST)) {
-                decodedUserData = validateAndDecodeByHTTPmethod(userData, MAX_HTTP_POST_LENGTH, BaseCmd.HTTPMethod.POST);
-            }
-
-            if (decodedUserData == null || decodedUserData.length < 1) {
-                throw new InvalidParameterValueException("User data is too short");
-            }
-            // Re-encode so that the '=' paddings are added if necessary since 'isBase64' does not require it, but python does on the VR.
-            return Base64.encodeBase64String(decodedUserData);
-        }
-        return null;
-    }
-
-    private byte[] validateAndDecodeByHTTPmethod(String userData, int maxHTTPlength, BaseCmd.HTTPMethod httpMethod) {
-        byte[] decodedUserData = null;
-
-        if (userData.length() >= maxHTTPlength) {
-            throw new InvalidParameterValueException(String.format("User data is too long for an http %s request", httpMethod.toString()));
-        }
-        if (userData.length() > VM_USERDATA_MAX_LENGTH.value()) {
-            throw new InvalidParameterValueException("User data has exceeded configurable max length : " + VM_USERDATA_MAX_LENGTH.value());
-        }
-        decodedUserData = Base64.decodeBase64(userData.getBytes());
-        if (decodedUserData.length > maxHTTPlength) {
-            throw new InvalidParameterValueException(String.format("User data is too long for http %s request", httpMethod.toString()));
-        }
-        return decodedUserData;
-    }
-
     /**
      * @param cmd
      * @param owner
diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
index 7bafbcc..5b1ca90 100644
--- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
@@ -249,8 +249,6 @@
     @Inject
     protected ConfigurationManager _configMgr;
     @Inject
-    protected VolumeDao _volsDao;
-    @Inject
     private VolumeDataStoreDao _volumeDataStoreDao;
     @Inject
     protected HostDao _hostDao;
@@ -299,7 +297,7 @@
     @Inject
     protected HypervisorGuruManager _hvGuruMgr;
     @Inject
-    protected VolumeDao _volumeDao;
+    protected VolumeDao volumeDao;
     @Inject
     ConfigurationDao _configDao;
     @Inject
@@ -372,7 +370,7 @@
     public boolean share(VMInstanceVO vm, List<VolumeVO> vols, HostVO host, boolean cancelPreviousShare) throws StorageUnavailableException {
 
         // if pool is in maintenance and it is the ONLY pool available; reject
-        List<VolumeVO> rootVolForGivenVm = _volsDao.findByInstanceAndType(vm.getId(), Type.ROOT);
+        List<VolumeVO> rootVolForGivenVm = volumeDao.findByInstanceAndType(vm.getId(), Type.ROOT);
         if (rootVolForGivenVm != null && rootVolForGivenVm.size() > 0) {
             boolean isPoolAvailable = isPoolAvailable(rootVolForGivenVm.get(0).getPoolId());
             if (!isPoolAvailable) {
@@ -436,7 +434,7 @@
         for (StoragePoolHostVO storagePoolHostRef : storagePoolHostRefs) {
             StoragePoolVO PrimaryDataStoreVO = _storagePoolDao.findById(storagePoolHostRef.getPoolId());
             if (PrimaryDataStoreVO.getPoolType() == StoragePoolType.LVM || PrimaryDataStoreVO.getPoolType() == StoragePoolType.EXT) {
-                SearchBuilder<VolumeVO> volumeSB = _volsDao.createSearchBuilder();
+                SearchBuilder<VolumeVO> volumeSB = volumeDao.createSearchBuilder();
                 volumeSB.and("poolId", volumeSB.entity().getPoolId(), SearchCriteria.Op.EQ);
                 volumeSB.and("removed", volumeSB.entity().getRemoved(), SearchCriteria.Op.NULL);
                 volumeSB.and("state", volumeSB.entity().getState(), SearchCriteria.Op.NIN);
@@ -450,7 +448,7 @@
                 volumeSC.setParameters("state", Volume.State.Expunging, Volume.State.Destroy);
                 volumeSC.setJoinParameters("activeVmSB", "state", State.Starting, State.Running, State.Stopping, State.Migrating);
 
-                List<VolumeVO> volumes = _volsDao.search(volumeSC, null);
+                List<VolumeVO> volumes = volumeDao.search(volumeSC, null);
                 if (volumes.size() > 0) {
                     return true;
                 }
@@ -598,7 +596,7 @@
 
         StoragePoolSearch = _vmInstanceDao.createSearchBuilder();
 
-        SearchBuilder<VolumeVO> volumeSearch = _volumeDao.createSearchBuilder();
+        SearchBuilder<VolumeVO> volumeSearch = volumeDao.createSearchBuilder();
         volumeSearch.and("volumeType", volumeSearch.entity().getVolumeType(), SearchCriteria.Op.EQ);
         volumeSearch.and("poolId", volumeSearch.entity().getPoolId(), SearchCriteria.Op.EQ);
         volumeSearch.and("state", volumeSearch.entity().getState(), SearchCriteria.Op.EQ);
@@ -1035,10 +1033,10 @@
         List<StoragePoolVO> childStoragePools = _storagePoolDao.listChildStoragePoolsInDatastoreCluster(sPool.getId());
         boolean canDelete = true;
         for (StoragePoolVO childPool : childStoragePools) {
-            Pair<Long, Long> vlms = _volsDao.getCountAndTotalByPool(childPool.getId());
+            Pair<Long, Long> vlms = volumeDao.getCountAndTotalByPool(childPool.getId());
             if (forced) {
                 if (vlms.first() > 0) {
-                    Pair<Long, Long> nonDstrdVlms = _volsDao.getNonDestroyedCountAndTotalByPool(childPool.getId());
+                    Pair<Long, Long> nonDstrdVlms = volumeDao.getNonDestroyedCountAndTotalByPool(childPool.getId());
                     if (nonDstrdVlms.first() > 0) {
                         canDelete = false;
                         break;
@@ -1055,15 +1053,15 @@
     }
 
     private boolean deleteDataStoreInternal(StoragePoolVO sPool, boolean forced) {
-        Pair<Long, Long> vlms = _volsDao.getCountAndTotalByPool(sPool.getId());
+        Pair<Long, Long> vlms = volumeDao.getCountAndTotalByPool(sPool.getId());
         if (forced) {
             if (vlms.first() > 0) {
-                Pair<Long, Long> nonDstrdVlms = _volsDao.getNonDestroyedCountAndTotalByPool(sPool.getId());
+                Pair<Long, Long> nonDstrdVlms = volumeDao.getNonDestroyedCountAndTotalByPool(sPool.getId());
                 if (nonDstrdVlms.first() > 0) {
                     throw new CloudRuntimeException("Cannot delete pool " + sPool.getName() + " as there are associated " + "non-destroyed vols for this pool");
                 }
                 // force expunge non-destroyed volumes
-                List<VolumeVO> vols = _volsDao.listVolumesToBeDestroyed();
+                List<VolumeVO> vols = volumeDao.listVolumesToBeDestroyed();
                 for (VolumeVO vol : vols) {
                     AsyncCallFuture<VolumeApiResult> future = volService.expungeVolumeAsync(volFactory.getVolume(vol.getId()));
                     try {
@@ -1326,7 +1324,7 @@
                     }
                     cleanupSecondaryStorage(recurring);
 
-                    List<VolumeVO> vols = _volsDao.listVolumesToBeDestroyed(new Date(System.currentTimeMillis() - ((long)StorageCleanupDelay.value() << 10)));
+                    List<VolumeVO> vols = volumeDao.listVolumesToBeDestroyed(new Date(System.currentTimeMillis() - ((long)StorageCleanupDelay.value() << 10)));
                     for (VolumeVO vol : vols) {
                         if (Type.ROOT.equals(vol.getVolumeType())) {
                              VMInstanceVO vmInstanceVO = _vmInstanceDao.findById(vol.getInstanceId());
@@ -1378,7 +1376,7 @@
                     // destroy uploaded volumes in abandoned/error state
                     List<VolumeDataStoreVO> volumeDataStores = _volumeDataStoreDao.listByVolumeState(Volume.State.UploadError, Volume.State.UploadAbandoned);
                     for (VolumeDataStoreVO volumeDataStore : volumeDataStores) {
-                        VolumeVO volume = _volumeDao.findById(volumeDataStore.getVolumeId());
+                        VolumeVO volume = volumeDao.findById(volumeDataStore.getVolumeId());
                         if (volume == null) {
                             s_logger.warn("Uploaded volume with id " + volumeDataStore.getVolumeId() + " not found, so cannot be destroyed");
                             continue;
@@ -1486,7 +1484,7 @@
         if (vm == null) {
             return false;
         }
-        List<VolumeVO> vmUsableVolumes = _volumeDao.findUsableVolumesForInstance(vmId);
+        List<VolumeVO> vmUsableVolumes = volumeDao.findUsableVolumesForInstance(vmId);
         for (VolumeVO vol : vmUsableVolumes) {
             if (gcVolume.getPoolId().equals(vol.getPoolId()) && gcVolume.getPath().equals(vol.getPath())) {
                 s_logger.debug(String.format("%s meant for garbage collection could a possible duplicate for %s", gcVolume, vol));
@@ -1976,7 +1974,7 @@
 
         for (String childDatastoreUUID : childDatastoreUUIDs) {
             StoragePoolVO dataStoreVO = _storagePoolDao.findPoolByUUID(childDatastoreUUID);
-            List<VolumeVO> allVolumes = _volumeDao.findByPoolId(dataStoreVO.getId());
+            List<VolumeVO> allVolumes = volumeDao.findByPoolId(dataStoreVO.getId());
             allVolumes.removeIf(volumeVO -> volumeVO.getInstanceId() == null);
             allVolumes.removeIf(volumeVO -> volumeVO.getState() != Volume.State.Ready);
             for (VolumeVO volume : allVolumes) {
@@ -2012,7 +2010,7 @@
                         volume.getUuid() + "Host=" + hostId;
 
                 // check for the changed details of volume and update database
-                VolumeVO volumeVO = _volumeDao.findById(volumeId);
+                VolumeVO volumeVO = volumeDao.findById(volumeId);
                 String datastoreName = answer.getContextParam("datastoreName");
                 if (datastoreName != null) {
                     StoragePoolVO storagePoolVO = _storagePoolDao.findByUuid(datastoreName);
@@ -2033,7 +2031,7 @@
                     volumeVO.setChainInfo(chainInfo);
                 }
 
-                _volumeDao.update(volumeVO.getId(), volumeVO);
+                volumeDao.update(volumeVO.getId(), volumeVO);
             }
             dataStoreVO.setParent(0L);
             _storagePoolDao.update(dataStoreVO.getId(), dataStoreVO);
@@ -2454,14 +2452,14 @@
             // might be clearer that this "volume" in "volumeDiskProfilesList" still might have an old value for hv_ss_reverse.
             Volume volume = volumeDiskProfilePair.first();
             DiskProfile diskProfile = volumeDiskProfilePair.second();
-            VolumeVO volumeVO = _volumeDao.findById(volume.getId());
+            VolumeVO volumeVO = volumeDao.findById(volume.getId());
 
             if (volumeVO.getHypervisorSnapshotReserve() == null) {
                 // update the volume's hv_ss_reserve (hypervisor snapshot reserve) from a disk offering (used for managed storage)
                 volService.updateHypervisorSnapshotReserveForVolume(getDiskOfferingVO(volumeVO), volumeVO.getId(), getHypervisorType(volumeVO));
 
                 // hv_ss_reserve field might have been updated; refresh from DB to make use of it in getDataObjectSizeIncludingHypervisorSnapshotReserve
-                volumeVO = _volumeDao.findById(volume.getId());
+                volumeVO = volumeDao.findById(volume.getId());
             }
 
             // this if statement should resolve to true at most once per execution of the for loop its contained within (for a root disk that is
@@ -3299,9 +3297,9 @@
             if (activeVolumeIds.contains(volumeId)) {
                 continue;
             }
-            Volume volume = _volumeDao.findById(volumeId);
+            Volume volume = volumeDao.findById(volumeId);
             if (volume != null && volume.getState() == Volume.State.Expunged) {
-                _volumeDao.remove(volumeId);
+                volumeDao.remove(volumeId);
             }
         }
 
diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
index e03942e..d0eaebb 100644
--- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
@@ -1682,7 +1682,7 @@
         }
     }
 
-    protected boolean stateTransitTo(Volume vol, Volume.Event event) throws NoTransitionException {
+    public boolean stateTransitTo(Volume vol, Volume.Event event) throws NoTransitionException {
         return _volStateMachine.transitTo(vol, event, null, _volsDao);
     }
 
diff --git a/server/src/main/java/com/cloud/vm/UserVmManager.java b/server/src/main/java/com/cloud/vm/UserVmManager.java
index 39f1e5d..6dd9c27 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManager.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManager.java
@@ -58,8 +58,6 @@
             "Destroys the VM's root volume when the VM is destroyed.",
             true, ConfigKey.Scope.Domain);
 
-    static final int MAX_USER_DATA_LENGTH_BYTES = 2048;
-
     public  static  final String CKS_NODE = "cksnode";
 
     /**
diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
index ecf6055..1dd6d65 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
@@ -16,7 +16,6 @@
 // under the License.
 package com.cloud.vm;
 
-import static com.cloud.configuration.ConfigurationManagerImpl.VM_USERDATA_MAX_LENGTH;
 import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
 
 import java.io.IOException;
@@ -123,9 +122,10 @@
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
+import org.apache.cloudstack.userdata.UserDataManager;
 import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
 import org.apache.cloudstack.utils.security.ParserUtils;
-import org.apache.commons.codec.binary.Base64;
+import org.apache.cloudstack.vm.schedule.VMScheduleManager;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang.math.NumberUtils;
@@ -582,6 +582,9 @@
     @Inject
     private AutoScaleManager autoScaleManager;
 
+    @Inject
+    VMScheduleManager vmScheduleManager;
+
     private ScheduledExecutorService _executor = null;
     private ScheduledExecutorService _vmIpFetchExecutor = null;
     private int _expungeInterval;
@@ -598,10 +601,6 @@
 
     protected static long ROOT_DEVICE_ID = 0;
 
-    private static final int MAX_HTTP_GET_LENGTH = 2 * MAX_USER_DATA_LENGTH_BYTES;
-    private static final int NUM_OF_2K_BLOCKS = 512;
-    private static final int MAX_HTTP_POST_LENGTH = NUM_OF_2K_BLOCKS * MAX_USER_DATA_LENGTH_BYTES;
-
     @Inject
     private OrchestrationService _orchSrvc;
 
@@ -611,6 +610,9 @@
     @Inject
     private ManagementService _mgr;
 
+    @Inject
+    private UserDataManager userDataManager;
+
     private static final ConfigKey<Integer> VmIpFetchWaitInterval = new ConfigKey<Integer>("Advanced", Integer.class, "externaldhcp.vmip.retrieval.interval", "180",
             "Wait Interval (in seconds) for shared network vm dhcp ip addr fetch for next iteration ", true);
 
@@ -939,7 +941,7 @@
             userDataDetails = cmd.getUserdataDetails().toString();
         }
         userData = finalizeUserData(userData, userDataId, template);
-        userData = validateUserData(userData, cmd.getHttpMethod());
+        userData = userDataManager.validateUserData(userData, cmd.getHttpMethod());
 
         userVm.setUserDataId(userDataId);
         userVm.setUserData(userData);
@@ -2942,7 +2944,7 @@
         if (userData != null) {
             // check and replace newlines
             userData = userData.replace("\\n", "");
-            userData = validateUserData(userData, httpMethod);
+            userData = userDataManager.validateUserData(userData, httpMethod);
             // update userData on domain router.
             updateUserdata = true;
         } else {
@@ -4076,7 +4078,7 @@
             _accountMgr.checkAccess(owner, AccessType.UseEntry, false, template);
 
             // check if the user data is correct
-            userData = validateUserData(userData, httpmethod);
+            userData = userDataManager.validateUserData(userData, httpmethod);
 
             // Find an SSH public key corresponding to the key pair name, if one is
             // given
@@ -4769,55 +4771,6 @@
         }
     }
 
-    protected String validateUserData(String userData, HTTPMethod httpmethod) {
-        byte[] decodedUserData = null;
-        if (userData != null) {
-
-            if (userData.contains("%")) {
-                try {
-                    userData = URLDecoder.decode(userData, "UTF-8");
-                } catch (UnsupportedEncodingException e) {
-                    throw new InvalidParameterValueException("Url decoding of userdata failed.");
-                }
-            }
-
-            if (!Base64.isBase64(userData)) {
-                throw new InvalidParameterValueException("User data is not base64 encoded");
-            }
-            // If GET, use 4K. If POST, support up to 1M.
-            if (httpmethod.equals(HTTPMethod.GET)) {
-                if (userData.length() >= MAX_HTTP_GET_LENGTH) {
-                    throw new InvalidParameterValueException("User data is too long for an http GET request");
-                }
-                if (userData.length() > VM_USERDATA_MAX_LENGTH.value()) {
-                    throw new InvalidParameterValueException("User data has exceeded configurable max length : " + VM_USERDATA_MAX_LENGTH.value());
-                }
-                decodedUserData = Base64.decodeBase64(userData.getBytes());
-                if (decodedUserData.length > MAX_HTTP_GET_LENGTH) {
-                    throw new InvalidParameterValueException("User data is too long for GET request");
-                }
-            } else if (httpmethod.equals(HTTPMethod.POST)) {
-                if (userData.length() >= MAX_HTTP_POST_LENGTH) {
-                    throw new InvalidParameterValueException("User data is too long for an http POST request");
-                }
-                if (userData.length() > VM_USERDATA_MAX_LENGTH.value()) {
-                    throw new InvalidParameterValueException("User data has exceeded configurable max length : " + VM_USERDATA_MAX_LENGTH.value());
-                }
-                decodedUserData = Base64.decodeBase64(userData.getBytes());
-                if (decodedUserData.length > MAX_HTTP_POST_LENGTH) {
-                    throw new InvalidParameterValueException("User data is too long for POST request");
-                }
-            }
-
-            if (decodedUserData == null || decodedUserData.length < 1) {
-                throw new InvalidParameterValueException("User data is too short");
-            }
-            // Re-encode so that the '=' paddings are added if necessary since 'isBase64' does not require it, but python does on the VR.
-            return Base64.encodeBase64String(decodedUserData);
-        }
-        return null;
-    }
-
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm", async = true)
     public UserVm startVirtualMachine(DeployVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException {
@@ -5740,9 +5693,9 @@
                     }
                     if (userDataId != null) {
                         UserData apiUserDataVO = userDataDao.findById(userDataId);
-                        return doConcateUserDatas(templateUserDataVO.getUserData(), apiUserDataVO.getUserData());
+                        return userDataManager.concatenateUserData(templateUserDataVO.getUserData(), apiUserDataVO.getUserData(), null);
                     } else if (StringUtils.isNotEmpty(userData)) {
-                        return doConcateUserDatas(templateUserDataVO.getUserData(), userData);
+                        return userDataManager.concatenateUserData(templateUserDataVO.getUserData(), userData, null);
                     } else {
                         return templateUserDataVO.getUserData();
                     }
@@ -5760,16 +5713,6 @@
         return null;
     }
 
-    private String doConcateUserDatas(String userdata1, String userdata2) {
-        byte[] userdata1Bytes = Base64.decodeBase64(userdata1.getBytes());
-        byte[] userdata2Bytes = Base64.decodeBase64(userdata2.getBytes());
-        byte[] finalUserDataBytes = new byte[userdata1Bytes.length + userdata2Bytes.length];
-        System.arraycopy(userdata1Bytes, 0, finalUserDataBytes, 0, userdata1Bytes.length);
-        System.arraycopy(userdata2Bytes, 0, finalUserDataBytes, userdata1Bytes.length, userdata2Bytes.length);
-
-        return Base64.encodeBase64String(finalUserDataBytes);
-    }
-
     @Override
     public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException,
     StorageUnavailableException, ResourceAllocationException {
@@ -5865,6 +5808,7 @@
         }
 
         String userData = cmd.getUserData();
+        userData = userDataManager.validateUserData(userData, cmd.getHttpMethod());
         Long userDataId = cmd.getUserdataId();
         String userDataDetails = null;
         if (MapUtils.isNotEmpty(cmd.getUserdataDetails())) {
@@ -6356,22 +6300,8 @@
     }
 
     public boolean isVMUsingLocalStorage(VMInstanceVO vm) {
-        boolean usesLocalStorage = false;
-
         List<VolumeVO> volumes = _volsDao.findByInstance(vm.getId());
-        for (VolumeVO vol : volumes) {
-            DiskOfferingVO diskOffering = _diskOfferingDao.findById(vol.getDiskOfferingId());
-            if (diskOffering.isUseLocalStorage()) {
-                usesLocalStorage = true;
-                break;
-            }
-            StoragePoolVO storagePool = _storagePoolDao.findById(vol.getPoolId());
-            if (storagePool.isLocal()) {
-                usesLocalStorage = true;
-                break;
-            }
-        }
-        return usesLocalStorage;
+        return isAnyVmVolumeUsingLocalStorage(volumes);
     }
 
     @Override
@@ -6430,7 +6360,7 @@
 
         DeployDestination dest = null;
         if (destinationHost == null) {
-            dest = chooseVmMigrationDestination(vm, srcHost);
+            dest = chooseVmMigrationDestination(vm, srcHost, null);
         } else {
             dest = checkVmMigrationDestination(vm, srcHost, destinationHost);
         }
@@ -6445,7 +6375,7 @@
         return findMigratedVm(vm.getId(), vm.getType());
     }
 
-    private DeployDestination chooseVmMigrationDestination(VMInstanceVO vm, Host srcHost) {
+    private DeployDestination chooseVmMigrationDestination(VMInstanceVO vm, Host srcHost, Long poolId) {
         vm.setLastHostId(null); // Last host does not have higher priority in vm migration
         final ServiceOfferingVO offering = serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
         final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm, null, offering, null, null);
@@ -6453,7 +6383,7 @@
         final Host host = _hostDao.findById(srcHostId);
         ExcludeList excludes = new ExcludeList();
         excludes.addHost(srcHostId);
-        final DataCenterDeployment plan = _itMgr.getMigrationDeployment(vm, host, null, excludes);
+        final DataCenterDeployment plan = _itMgr.getMigrationDeployment(vm, host, poolId, excludes);
         try {
             return _planningMgr.planDeployment(profile, plan, excludes, null);
         } catch (final AffinityConflictException e2) {
@@ -6753,8 +6683,21 @@
         return implicitPlannerUsed;
     }
 
-    private boolean isVmVolumesOnZoneWideStore(VMInstanceVO vm) {
-        final List<VolumeVO> volumes = _volsDao.findCreatedByInstance(vm.getId());
+    protected boolean isAnyVmVolumeUsingLocalStorage(final List<VolumeVO> volumes) {
+        for (VolumeVO vol : volumes) {
+            DiskOfferingVO diskOffering = _diskOfferingDao.findById(vol.getDiskOfferingId());
+            if (diskOffering.isUseLocalStorage()) {
+                return true;
+            }
+            StoragePoolVO storagePool = _storagePoolDao.findById(vol.getPoolId());
+            if (storagePool.isLocal()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    protected boolean isAllVmVolumesOnZoneWideStore(final List<VolumeVO> volumes) {
         if (CollectionUtils.isEmpty(volumes)) {
             return false;
         }
@@ -6778,6 +6721,10 @@
             throw new InvalidParameterValueException("Cannot migrate VM, host with ID: " + srcHostId + " for VM not found");
         }
 
+        if (destinationHost == null) {
+            return new Pair<>(srcHost, null);
+        }
+
         // Check if source and destination hosts are valid and migrating to same host
         if (destinationHost.getId() == srcHostId) {
             throw new InvalidParameterValueException(String.format("Cannot migrate VM as it is already present on host %s (ID: %s), please specify valid destination host to migrate the VM",
@@ -6897,6 +6844,25 @@
         return volToPoolObjectMap;
     }
 
+    protected boolean isVmCanBeMigratedWithoutStorage(Host srcHost, Host destinationHost, List<VolumeVO> volumes,
+          Map<String, String> volumeToPool) {
+        return !isAnyVmVolumeUsingLocalStorage(volumes) &&
+                MapUtils.isEmpty(volumeToPool) && destinationHost != null
+                && (destinationHost.getClusterId().equals(srcHost.getClusterId()) || isAllVmVolumesOnZoneWideStore(volumes));
+    }
+
+    protected Host chooseVmMigrationDestinationUsingVolumePoolMap(VMInstanceVO vm, Host srcHost, Map<Long, Long> volToPoolObjectMap) {
+        Long poolId = null;
+        if (MapUtils.isNotEmpty(volToPoolObjectMap)) {
+            poolId = new ArrayList<>(volToPoolObjectMap.values()).get(0);
+        }
+        DeployDestination deployDestination = chooseVmMigrationDestination(vm, srcHost, poolId);
+        if (deployDestination == null || deployDestination.getHost() == null) {
+            throw new CloudRuntimeException("Unable to find suitable destination to migrate VM " + vm.getInstanceName());
+        }
+        return deployDestination.getHost();
+    }
+
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_VM_MIGRATE, eventDescription = "migrating VM", async = true)
     public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinationHost, Map<String, String> volumeToPool) throws ResourceUnavailableException,
@@ -6941,8 +6907,8 @@
         Pair<Host, Host> sourceDestinationHosts = getHostsForMigrateVmWithStorage(vm, destinationHost);
         Host srcHost = sourceDestinationHosts.first();
 
-        if (!isVMUsingLocalStorage(vm) && MapUtils.isEmpty(volumeToPool)
-                && (destinationHost.getClusterId().equals(srcHost.getClusterId()) || isVmVolumesOnZoneWideStore(vm))){
+        final List<VolumeVO> volumes = _volsDao.findCreatedByInstance(vm.getId());
+        if (isVmCanBeMigratedWithoutStorage(srcHost, destinationHost, volumes, volumeToPool)) {
             // If volumes do not have to be migrated
             // call migrateVirtualMachine for non-user VMs else throw exception
             if (!VirtualMachine.Type.User.equals(vm.getType())) {
@@ -6954,6 +6920,10 @@
 
         Map<Long, Long> volToPoolObjectMap = getVolumePoolMappingForMigrateVmWithStorage(vm, volumeToPool);
 
+        if (destinationHost == null) {
+            destinationHost = chooseVmMigrationDestinationUsingVolumePoolMap(vm, srcHost, volToPoolObjectMap);
+        }
+
         checkHostsDedication(vm, srcHost.getId(), destinationHost.getId());
 
         _itMgr.migrateWithStorage(vm.getUuid(), srcHost.getId(), destinationHost.getId(), volToPoolObjectMap);
diff --git a/server/src/main/java/org/apache/cloudstack/acl/RoleManagerImpl.java b/server/src/main/java/org/apache/cloudstack/acl/RoleManagerImpl.java
index f2f4a6f..ff97d7e 100644
--- a/server/src/main/java/org/apache/cloudstack/acl/RoleManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/acl/RoleManagerImpl.java
@@ -56,7 +56,6 @@
 import com.cloud.utils.Pair;
 import com.cloud.utils.component.ManagerBase;
 import com.cloud.utils.component.PluggableService;
-import com.cloud.utils.db.Filter;
 import com.cloud.utils.db.Transaction;
 import com.cloud.utils.db.TransactionCallback;
 import com.cloud.utils.db.TransactionStatus;
@@ -95,7 +94,7 @@
     }
 
     @Override
-    public Role findRole(Long id) {
+    public Role findRole(Long id, boolean removePrivateRoles) {
         if (id == null || id < 1L) {
             logger.trace(String.format("Role ID is invalid [%s]", id));
             return null;
@@ -105,14 +104,18 @@
             logger.trace(String.format("Role not found [id=%s]", id));
             return null;
         }
-        Account account = getCurrentAccount();
-        if (!accountManager.isRootAdmin(account.getId()) && RoleType.Admin == role.getRoleType()) {
-            logger.debug(String.format("Role [id=%s, name=%s] is of 'Admin' type and is only visible to 'Root admins'.", id, role.getName()));
+        if (!isCallerRootAdmin() && (RoleType.Admin == role.getRoleType() || (!role.isPublicRole() && removePrivateRoles))) {
+            logger.debug(String.format("Role [id=%s, name=%s] is either of 'Admin' type or is private and is only visible to 'Root admins'.", id, role.getName()));
             return null;
         }
         return role;
     }
 
+    @Override
+    public Role findRole(Long id) {
+        return findRole(id, false);
+    }
+
     /**
      * Simple call to {@link CallContext#current()} to retrieve the current calling account.
      * This method facilitates unit testing, it avoids mocking static methods.
@@ -140,7 +143,7 @@
 
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_ROLE_CREATE, eventDescription = "creating Role")
-    public Role createRole(final String name, final RoleType roleType, final String description) {
+    public Role createRole(final String name, final RoleType roleType, final String description, boolean publicRole) {
         checkCallerAccess();
         if (roleType == null || roleType == RoleType.Unknown) {
             throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role type provided");
@@ -148,7 +151,9 @@
         return Transaction.execute(new TransactionCallback<RoleVO>() {
             @Override
             public RoleVO doInTransaction(TransactionStatus status) {
-                RoleVO role = roleDao.persist(new RoleVO(name, roleType, description));
+                RoleVO role = new RoleVO(name, roleType, description);
+                role.setPublicRole(publicRole);
+                role = roleDao.persist(role);
                 CallContext.current().putContextParameter(Role.class, role.getUuid());
                 return role;
             }
@@ -157,12 +162,14 @@
 
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_ROLE_CREATE, eventDescription = "creating role by cloning another role")
-    public Role createRole(String name, Role role, String description) {
+    public Role createRole(String name, Role role, String description, boolean publicRole) {
         checkCallerAccess();
         return Transaction.execute(new TransactionCallback<RoleVO>() {
             @Override
             public RoleVO doInTransaction(TransactionStatus status) {
-                RoleVO newRoleVO = roleDao.persist(new RoleVO(name, role.getRoleType(), description));
+                RoleVO newRole = new RoleVO(name, role.getRoleType(), description);
+                newRole.setPublicRole(publicRole);
+                RoleVO newRoleVO = roleDao.persist(newRole);
                 if (newRoleVO == null) {
                     throw new CloudRuntimeException("Unable to create the role: " + name + ", failed to persist in DB");
                 }
@@ -181,7 +188,7 @@
 
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_ROLE_IMPORT, eventDescription = "importing Role")
-    public Role importRole(String name, RoleType type, String description, List<Map<String, Object>> rules, boolean forced) {
+    public Role importRole(String name, RoleType type, String description, List<Map<String, Object>> rules, boolean forced, boolean isPublicRole) {
         checkCallerAccess();
         if (StringUtils.isEmpty(name)) {
             throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role name provided");
@@ -190,7 +197,7 @@
             throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid role type provided");
         }
 
-        List<RoleVO> existingRoles = roleDao.findByName(name);
+        List<RoleVO> existingRoles = roleDao.findByName(name, isCallerRootAdmin());
         if (CollectionUtils.isNotEmpty(existingRoles) && !forced) {
             throw new CloudRuntimeException("Role already exists");
         }
@@ -199,7 +206,7 @@
             @Override
             public RoleVO doInTransaction(TransactionStatus status) {
                 RoleVO newRole = null;
-                RoleVO existingRole = roleDao.findByNameAndType(name, type);
+                RoleVO existingRole = roleDao.findByNameAndType(name, type, isCallerRootAdmin());
                 if (existingRole != null) {
                     if (existingRole.isDefault()) {
                         throw new CloudRuntimeException("Failed to import the role: " + name + ", default role cannot be overriden");
@@ -216,11 +223,14 @@
                     existingRole.setName(name);
                     existingRole.setRoleType(type);
                     existingRole.setDescription(description);
+                    existingRole.setPublicRole(isPublicRole);
                     roleDao.update(existingRole.getId(), existingRole);
 
                     newRole = existingRole;
                 } else {
-                    newRole = roleDao.persist(new RoleVO(name, type, description));
+                    RoleVO role = new RoleVO(name, type, description);
+                    role.setPublicRole(isPublicRole);
+                    newRole = roleDao.persist(role);
                 }
 
                 if (newRole == null) {
@@ -243,16 +253,23 @@
 
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_ROLE_UPDATE, eventDescription = "updating Role")
-    public Role updateRole(final Role role, final String name, final RoleType roleType, final String description) {
+    public Role updateRole(final Role role, final String name, final RoleType roleType, final String description, Boolean publicRole) {
         checkCallerAccess();
-        if (role.isDefault()) {
-            throw new PermissionDeniedException("Default roles cannot be updated");
-        }
 
         if (roleType != null && roleType == RoleType.Unknown) {
             throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Unknown is not a valid role type");
         }
         RoleVO roleVO = (RoleVO)role;
+
+        if (role.isDefault()) {
+            if (publicRole == null || roleType != null || !StringUtils.isAllEmpty(name, description)) {
+                throw new PermissionDeniedException("Default roles cannot be updated (with the exception of making it private/public).");
+            }
+            roleVO.setPublicRole(publicRole);
+            roleDao.update(role.getId(), roleVO);
+            return role;
+        }
+
         if (StringUtils.isNotEmpty(name)) {
             roleVO.setName(name);
         }
@@ -268,6 +285,10 @@
             roleVO.setDescription(description);
         }
 
+        if (publicRole == null) {
+            publicRole = role.isPublicRole();
+        }
+        roleVO.setPublicRole(publicRole);
         roleDao.update(role.getId(), roleVO);
         return role;
     }
@@ -363,7 +384,7 @@
     @Override
     public Pair<List<Role>, Integer> findRolesByName(String name, String keyword, Long startIndex, Long limit) {
         if (StringUtils.isNotBlank(name) || StringUtils.isNotBlank(keyword)) {
-            Pair<List<RoleVO>, Integer> data = roleDao.findAllByName(name, keyword, startIndex, limit);
+            Pair<List<RoleVO>, Integer> data = roleDao.findAllByName(name, keyword, startIndex, limit, isCallerRootAdmin());
             int removed = removeRootAdminRolesIfNeeded(data.first());
             return new Pair<List<Role>,Integer>(ListUtils.toListOfInterface(data.first()), Integer.valueOf(data.second() - removed));
         }
@@ -375,8 +396,7 @@
      *  The actual removal is executed via {@link #removeRootAdminRoles(List)}. Therefore, if the method is called by a 'root admin', we do nothing here.
      */
     protected int removeRootAdminRolesIfNeeded(List<? extends Role> roles) {
-        Account account = getCurrentAccount();
-        if (!accountManager.isRootAdmin(account.getId())) {
+        if (!isCallerRootAdmin()) {
             return removeRootAdminRoles(roles);
         }
         return 0;
@@ -408,10 +428,10 @@
 
     @Override
     public Pair<List<Role>, Integer> findRolesByType(RoleType roleType, Long startIndex, Long limit) {
-        if (roleType == null || RoleType.Admin == roleType && !accountManager.isRootAdmin(getCurrentAccount().getId())) {
+        if (roleType == null || RoleType.Admin == roleType && !isCallerRootAdmin()) {
             return new Pair<List<Role>, Integer>(Collections.emptyList(), 0);
         }
-        Pair<List<RoleVO>, Integer> data = roleDao.findAllByRoleType(roleType, startIndex, limit);
+        Pair<List<RoleVO>, Integer> data = roleDao.findAllByRoleType(roleType, startIndex, limit, isCallerRootAdmin());
         return new Pair<List<Role>,Integer>(ListUtils.toListOfInterface(data.first()), Integer.valueOf(data.second()));
     }
 
@@ -424,8 +444,7 @@
 
     @Override
     public Pair<List<Role>, Integer> listRoles(Long startIndex, Long limit) {
-        Pair<List<RoleVO>, Integer> data = roleDao.searchAndCount(null,
-                new Filter(RoleVO.class, "id", Boolean.TRUE, startIndex, limit));
+        Pair<List<RoleVO>, Integer> data = roleDao.listAllRoles(startIndex, limit, isCallerRootAdmin());
         int removed = removeRootAdminRolesIfNeeded(data.first());
         return new Pair<List<Role>,Integer>(ListUtils.toListOfInterface(data.first()), Integer.valueOf(data.second() - removed));
     }
@@ -439,6 +458,10 @@
         return Collections.emptyList();
     }
 
+    private boolean isCallerRootAdmin() {
+        return accountManager.isRootAdmin(getCurrentAccount().getId());
+    }
+
     @Override
     public Permission getRolePermission(String permission) {
         if (StringUtils.isEmpty(permission)) {
diff --git a/server/src/main/java/org/apache/cloudstack/annotation/AnnotationManagerImpl.java b/server/src/main/java/org/apache/cloudstack/annotation/AnnotationManagerImpl.java
index cc59846..5987979 100644
--- a/server/src/main/java/org/apache/cloudstack/annotation/AnnotationManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/annotation/AnnotationManagerImpl.java
@@ -26,6 +26,7 @@
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.cluster.ManagementServerHostVO;
 import com.cloud.user.dao.UserDataDao;
 import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.acl.Role;
@@ -50,6 +51,7 @@
 import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 
+import com.cloud.cluster.dao.ManagementServerHostDao;
 import com.cloud.dc.ClusterVO;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.HostPodVO;
@@ -158,6 +160,8 @@
     @Inject
     private UserDataDao userDataDao;
     @Inject
+    private ManagementServerHostDao managementServerHostDao;
+    @Inject
     EntityManager entityManager;
 
     private static final List<RoleType> adminRoles = Collections.singletonList(RoleType.Admin);
@@ -192,6 +196,7 @@
         s_typeMap.put(EntityType.VR, ApiCommandResourceType.DomainRouter);
         s_typeMap.put(EntityType.SYSTEM_VM, ApiCommandResourceType.SystemVm);
         s_typeMap.put(EntityType.AUTOSCALE_VM_GROUP, ApiCommandResourceType.AutoScaleVmGroup);
+        s_typeMap.put(EntityType.MANAGEMENT_SERVER, ApiCommandResourceType.Host);
     }
 
     public List<KubernetesClusterHelper> getKubernetesClusterHelpers() {
@@ -532,6 +537,8 @@
                 return kubernetesClusterHelpers.get(0).findByUuid(entityUuid);
             case AUTOSCALE_VM_GROUP:
                 return autoScaleVmGroupDao.findByUuid(entityUuid);
+            case MANAGEMENT_SERVER:
+                return managementServerHostDao.findByUuid(entityUuid);
             default:
                 throw new CloudRuntimeException("Invalid entity type " + type);
         }
@@ -607,6 +614,9 @@
             case SYSTEM_VM:
                 VMInstanceVO instance = vmInstanceDao.findByUuid(entityUuid);
                 return instance != null ? instance.getInstanceName() : null;
+            case MANAGEMENT_SERVER:
+                ManagementServerHostVO mgmtServer = managementServerHostDao.findByUuid(entityUuid);
+                return mgmtServer != null ? mgmtServer.getName() : null;
             default:
                 return null;
         }
diff --git a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java
index 4e18caa..5da3514 100644
--- a/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/backup/BackupManagerImpl.java
@@ -27,6 +27,9 @@
 import java.util.Timer;
 import java.util.TimerTask;
 
+import com.cloud.storage.VolumeApiService;
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.vm.VirtualMachineManager;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
@@ -53,6 +56,7 @@
 import org.apache.cloudstack.backup.dao.BackupOfferingDao;
 import org.apache.cloudstack.backup.dao.BackupScheduleDao;
 import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
 import org.apache.cloudstack.framework.config.ConfigKey;
 import org.apache.cloudstack.framework.jobs.AsyncJobDispatcher;
 import org.apache.cloudstack.framework.jobs.AsyncJobManager;
@@ -147,6 +151,12 @@
     private ApiDispatcher apiDispatcher;
     @Inject
     private AsyncJobManager asyncJobManager;
+    @Inject
+    private VirtualMachineManager virtualMachineManager;
+    @Inject
+    private VolumeApiService volumeApiService;
+    @Inject
+    private VolumeOrchestrationService volumeOrchestrationService;
 
     private AsyncJobDispatcher asyncJobDispatcher;
     private Timer backupTimer;
@@ -585,17 +595,100 @@
 
         final BackupOffering offering = backupOfferingDao.findByIdIncludingRemoved(vm.getBackupOfferingId());
         if (offering == null) {
-            throw new CloudRuntimeException("Failed to find backup offering of the VM backup");
+            throw new CloudRuntimeException("Failed to find backup offering of the VM backup.");
         }
 
-        final BackupProvider backupProvider = getBackupProvider(offering.getProvider());
-        if (!backupProvider.restoreVMFromBackup(vm, backup)) {
-            throw new CloudRuntimeException("Error restoring VM from backup ID " + backup.getId());
-        }
+        String backupDetailsInMessage = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(backup, "uuid", "externalId", "vmId", "type", "status", "date");
+        tryRestoreVM(backup, vm, offering, backupDetailsInMessage);
+        updateVolumeState(vm, Volume.Event.RestoreSucceeded, Volume.State.Ready);
+        updateVmState(vm, VirtualMachine.Event.RestoringSuccess, VirtualMachine.State.Stopped);
+
         return importRestoredVM(vm.getDataCenterId(), vm.getDomainId(), vm.getAccountId(), vm.getUserId(),
                 vm.getInstanceName(), vm.getHypervisorType(), backup);
     }
 
+    /**
+     * Tries to restore a VM from a backup. <br/>
+     * First update the VM state to {@link VirtualMachine.Event#RestoringRequested} and its volume states to {@link Volume.Event#RestoreRequested}, <br/>
+     * and then try to restore the backup. <br/>
+     *
+     * If restore fails, then update the VM state to {@link VirtualMachine.Event#RestoringFailed}, and its volumes to {@link Volume.Event#RestoreFailed} and throw an {@link CloudRuntimeException}.
+     */
+    protected void tryRestoreVM(BackupVO backup, VMInstanceVO vm, BackupOffering offering, String backupDetailsInMessage) {
+        try {
+            updateVmState(vm, VirtualMachine.Event.RestoringRequested, VirtualMachine.State.Restoring);
+            updateVolumeState(vm, Volume.Event.RestoreRequested, Volume.State.Restoring);
+            final BackupProvider backupProvider = getBackupProvider(offering.getProvider());
+            if (!backupProvider.restoreVMFromBackup(vm, backup)) {
+                throw new CloudRuntimeException(String.format("Error restoring %s from backup [%s].", vm, backupDetailsInMessage));
+            }
+        // The restore process is executed by a backup provider outside of ACS, I am using the catch-all (Exception) to
+        // ensure that no provider-side exception is missed. Therefore, we have a proper handling of exceptions, and rollbacks if needed.
+        } catch (Exception e) {
+            LOG.error(String.format("Failed to restore backup [%s] due to: [%s].", backupDetailsInMessage, e.getMessage()), e);
+            updateVolumeState(vm, Volume.Event.RestoreFailed, Volume.State.Ready);
+            updateVmState(vm, VirtualMachine.Event.RestoringFailed, VirtualMachine.State.Stopped);
+            throw new CloudRuntimeException(String.format("Error restoring VM from backup [%s].", backupDetailsInMessage));
+        }
+    }
+
+    /**
+     * Tries to update the state of given VM, given specified event
+     * @param vm The VM to update its state
+     * @param event The event to update the VM state
+     * @param next The desired state, just needed to add more context to the logs
+     */
+    private void updateVmState(VMInstanceVO vm, VirtualMachine.Event event, VirtualMachine.State next) {
+        LOG.debug(String.format("Trying to update state of VM [%s] with event [%s].", vm, event));
+        Transaction.execute(TransactionLegacy.CLOUD_DB, (TransactionCallback<VMInstanceVO>) status -> {
+            try {
+                if (!virtualMachineManager.stateTransitTo(vm, event, vm.getHostId())) {
+                    throw new CloudRuntimeException(String.format("Unable to change state of VM [%s] to [%s].", vm, next));
+                }
+            } catch (NoTransitionException e) {
+                String errMsg = String.format("Failed to update state of VM [%s] with event [%s] due to [%s].", vm, event, e.getMessage());
+                LOG.error(errMsg, e);
+                throw new RuntimeException(errMsg);
+            }
+            return null;
+        });
+    }
+
+    /**
+     * Tries to update all volume states of given VM, given specified event
+     * @param vm The VM to which the volumes belong
+     * @param event The event to update the volume states
+     * @param next The desired state, just needed to add more context to the logs
+     */
+    private void updateVolumeState(VMInstanceVO vm, Volume.Event event, Volume.State next) {
+        Transaction.execute(TransactionLegacy.CLOUD_DB, (TransactionCallback<VolumeVO>) status -> {
+            for (VolumeVO volume : volumeDao.findIncludingRemovedByInstanceAndType(vm.getId(), null)) {
+                tryToUpdateStateOfSpecifiedVolume(volume, event, next);
+            }
+            return null;
+        });
+    }
+
+    /**
+     * Tries to update the state of just one volume using any passed {@link Volume.Event}. Throws an {@link RuntimeException} when fails.
+     * @param volume The volume to update it state
+     * @param event The event to update the volume state
+     * @param next The desired state, just needed to add more context to the logs
+     *
+     */
+    private void tryToUpdateStateOfSpecifiedVolume(VolumeVO volume, Volume.Event event, Volume.State next) {
+        LOG.debug(String.format("Trying to update state of volume [%s] with event [%s].", volume, event));
+        try {
+            if (!volumeApiService.stateTransitTo(volume, event)) {
+                throw new CloudRuntimeException(String.format("Unable to change state of volume [%s] to [%s].", volume, next));
+            }
+        } catch (NoTransitionException e) {
+            String errMsg = String.format("Failed to update state of volume [%s] with event [%s] due to [%s].", volume, event, e.getMessage());
+            LOG.error(errMsg, e);
+            throw new RuntimeException(errMsg);
+        }
+    }
+
     private Backup.VolumeInfo getVolumeInfo(List<Backup.VolumeInfo> backedUpVolumes, String volumeUuid) {
         for (Backup.VolumeInfo volInfo : backedUpVolumes) {
             if (volInfo.getUuid().equals(volumeUuid)) {
@@ -652,16 +745,20 @@
         String[] hostPossibleValues = {host.getPrivateIpAddress(), host.getName()};
         String[] datastoresPossibleValues = {datastore.getUuid(), datastore.getName()};
 
+        updateVmState(vm, VirtualMachine.Event.RestoringRequested, VirtualMachine.State.Restoring);
         Pair<Boolean, String> result = restoreBackedUpVolume(backedUpVolumeUuid, backup, backupProvider, hostPossibleValues, datastoresPossibleValues);
 
         if (BooleanUtils.isFalse(result.first())) {
+            updateVmState(vm, VirtualMachine.Event.RestoringFailed, VirtualMachine.State.Stopped);
             throw new CloudRuntimeException(String.format("Error restoring volume [%s] of VM [%s] to host [%s] using backup provider [%s] due to: [%s].",
                     backedUpVolumeUuid, vm.getUuid(), host.getUuid(), backupProvider.getName(), result.second()));
         }
         if (!attachVolumeToVM(vm.getDataCenterId(), result.second(), vmFromBackup.getBackupVolumeList(),
                             backedUpVolumeUuid, vm, datastore.getUuid(), backup)) {
+            updateVmState(vm, VirtualMachine.Event.RestoringFailed, VirtualMachine.State.Stopped);
             throw new CloudRuntimeException(String.format("Error attaching volume [%s] to VM [%s]." + backedUpVolumeUuid, vm.getUuid()));
         }
+        updateVmState(vm, VirtualMachine.Event.RestoringSuccess, VirtualMachine.State.Stopped);
         return true;
     }
 
diff --git a/server/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduleManagerImpl.java b/server/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduleManagerImpl.java
new file mode 100644
index 0000000..4b183be
--- /dev/null
+++ b/server/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduleManagerImpl.java
@@ -0,0 +1,317 @@
+/*
+ * 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.vm.schedule;
+
+import com.cloud.api.query.MutualExclusiveIdsManagerBase;
+import com.cloud.event.ActionEvent;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.user.AccountManager;
+import com.cloud.utils.DateUtil;
+import com.cloud.utils.Pair;
+import com.cloud.utils.component.PluggableService;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.UserVmManager;
+import com.cloud.vm.VirtualMachine;
+import org.apache.cloudstack.api.ApiCommandResourceType;
+import org.apache.cloudstack.api.command.user.vm.CreateVMScheduleCmd;
+import org.apache.cloudstack.api.command.user.vm.DeleteVMScheduleCmd;
+import org.apache.cloudstack.api.command.user.vm.ListVMScheduleCmd;
+import org.apache.cloudstack.api.command.user.vm.UpdateVMScheduleCmd;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.VMScheduleResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.vm.schedule.dao.VMScheduleDao;
+import org.apache.commons.lang.time.DateUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Logger;
+import org.springframework.scheduling.support.CronExpression;
+
+import javax.inject.Inject;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.TimeZone;
+
+public class VMScheduleManagerImpl extends MutualExclusiveIdsManagerBase implements VMScheduleManager, PluggableService {
+
+    private static Logger LOGGER = Logger.getLogger(VMScheduleManagerImpl.class);
+
+    @Inject
+    private VMScheduleDao vmScheduleDao;
+    @Inject
+    private UserVmManager userVmManager;
+    @Inject
+    private VMScheduler vmScheduler;
+    @Inject
+    private AccountManager accountManager;
+
+    @Override
+    public List<Class<?>> getCommands() {
+        final List<Class<?>> cmdList = new ArrayList<>();
+        cmdList.add(CreateVMScheduleCmd.class);
+        cmdList.add(ListVMScheduleCmd.class);
+        cmdList.add(UpdateVMScheduleCmd.class);
+        cmdList.add(DeleteVMScheduleCmd.class);
+        return cmdList;
+    }
+
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_VM_SCHEDULE_CREATE, eventDescription = "Creating VM Schedule", create = true)
+    public VMScheduleResponse createSchedule(CreateVMScheduleCmd cmd) {
+        VirtualMachine vm = userVmManager.getUserVm(cmd.getVmId());
+        accountManager.checkAccess(CallContext.current().getCallingAccount(), null, false, vm);
+        if (vm == null) {
+            throw new InvalidParameterValueException(String.format("Invalid value for vmId: %s", cmd.getVmId()));
+        }
+
+        VMSchedule.Action action = null;
+        if (cmd.getAction() != null) {
+            try {
+                action = VMSchedule.Action.valueOf(cmd.getAction().toUpperCase());
+            } catch (IllegalArgumentException exception) {
+                throw new InvalidParameterValueException(String.format("Invalid value for action: %s", cmd.getAction()));
+            }
+        }
+
+        Date cmdStartDate = cmd.getStartDate();
+        Date cmdEndDate = cmd.getEndDate();
+        String cmdTimeZone = cmd.getTimeZone();
+        TimeZone timeZone = TimeZone.getTimeZone(cmdTimeZone);
+        String timeZoneId = timeZone.getID();
+        Date startDate = DateUtils.addMinutes(new Date(), 1);
+        if (cmdStartDate != null) {
+            startDate = Date.from(DateUtil.getZoneDateTime(cmdStartDate, timeZone.toZoneId()).toInstant());
+        }
+        Date endDate = null;
+        if (cmdEndDate != null) {
+            endDate = Date.from(DateUtil.getZoneDateTime(cmdEndDate, timeZone.toZoneId()).toInstant());
+        }
+
+        CronExpression cronExpression = DateUtil.parseSchedule(cmd.getSchedule());
+
+        validateStartDateEndDate(startDate, endDate, timeZone);
+
+        String description = null;
+        if (StringUtils.isBlank(cmd.getDescription())) {
+            description = String.format("%s - %s", action, DateUtil.getHumanReadableSchedule(cronExpression));
+        } else description = cmd.getDescription();
+
+        LOGGER.warn(String.format("Using timezone [%s] for running the schedule for VM [%s], as an equivalent of [%s].", timeZoneId, vm.getUuid(), cmdTimeZone));
+
+        String finalDescription = description;
+        VMSchedule.Action finalAction = action;
+        Date finalStartDate = startDate;
+        Date finalEndDate = endDate;
+
+        return Transaction.execute((TransactionCallback<VMScheduleResponse>) status -> {
+            VMScheduleVO vmSchedule = vmScheduleDao.persist(new VMScheduleVO(cmd.getVmId(), finalDescription, cronExpression.toString(), timeZoneId, finalAction, finalStartDate, finalEndDate, cmd.getEnabled()));
+            vmScheduler.scheduleNextJob(vmSchedule);
+            CallContext.current().setEventResourceId(vm.getId());
+            CallContext.current().setEventResourceType(ApiCommandResourceType.VirtualMachine);
+            return createResponse(vmSchedule);
+        });
+    }
+
+    @Override
+    public VMScheduleResponse createResponse(VMSchedule vmSchedule) {
+        VirtualMachine vm = userVmManager.getUserVm(vmSchedule.getVmId());
+        VMScheduleResponse response = new VMScheduleResponse();
+
+        response.setObjectName(VMSchedule.class.getSimpleName().toLowerCase());
+        response.setId(vmSchedule.getUuid());
+        response.setVmId(vm.getUuid());
+        response.setDescription(vmSchedule.getDescription());
+        response.setSchedule(vmSchedule.getSchedule());
+        response.setTimeZone(vmSchedule.getTimeZone());
+        response.setAction(vmSchedule.getAction());
+        response.setEnabled(vmSchedule.getEnabled());
+        response.setStartDate(vmSchedule.getStartDate());
+        response.setEndDate(vmSchedule.getEndDate());
+        response.setCreated(vmSchedule.getCreated());
+        return response;
+    }
+
+    @Override
+    public ListResponse<VMScheduleResponse> listSchedule(ListVMScheduleCmd cmd) {
+        Long id = cmd.getId();
+        Boolean enabled = cmd.getEnabled();
+        Long vmId = cmd.getVmId();
+
+        VirtualMachine vm = userVmManager.getUserVm(vmId);
+        accountManager.checkAccess(CallContext.current().getCallingAccount(), null, false, vm);
+
+        VMSchedule.Action action = null;
+        if (cmd.getAction() != null) {
+            try {
+                action = VMSchedule.Action.valueOf(cmd.getAction());
+            } catch (IllegalArgumentException exception) {
+                throw new InvalidParameterValueException("Invalid value for action: " + cmd.getAction());
+            }
+        }
+
+        Pair<List<VMScheduleVO>, Integer> result = vmScheduleDao.searchAndCount(id, vmId, action, enabled, cmd.getStartIndex(), cmd.getPageSizeVal());
+
+        ListResponse<VMScheduleResponse> response = new ListResponse<>();
+        List<VMScheduleResponse> responsesList = new ArrayList<>();
+        for (VMSchedule vmSchedule : result.first()) {
+            responsesList.add(createResponse(vmSchedule));
+        }
+        response.setResponses(responsesList, result.second());
+        return response;
+    }
+
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_VM_SCHEDULE_UPDATE, eventDescription = "Updating VM Schedule")
+    public VMScheduleResponse updateSchedule(UpdateVMScheduleCmd cmd) {
+        Long id = cmd.getId();
+        VMScheduleVO vmSchedule = vmScheduleDao.findById(id);
+
+        if (vmSchedule == null) {
+            throw new CloudRuntimeException("VM schedule doesn't exist");
+        }
+
+        VirtualMachine vm = userVmManager.getUserVm(vmSchedule.getVmId());
+        accountManager.checkAccess(CallContext.current().getCallingAccount(), null, false, vm);
+
+        CronExpression cronExpression = Objects.requireNonNullElse(
+                DateUtil.parseSchedule(cmd.getSchedule()),
+                DateUtil.parseSchedule(vmSchedule.getSchedule())
+        );
+
+        String description = cmd.getDescription();
+        if (description == null && vmSchedule.getDescription() == null) {
+            description = String.format("%s - %s", vmSchedule.getAction(), DateUtil.getHumanReadableSchedule(cronExpression));
+        }
+        String cmdTimeZone = cmd.getTimeZone();
+        Date cmdStartDate = cmd.getStartDate();
+        Date cmdEndDate = cmd.getEndDate();
+        Boolean enabled = cmd.getEnabled();
+
+        TimeZone timeZone;
+        String timeZoneId;
+        if (cmdTimeZone != null) {
+            timeZone = TimeZone.getTimeZone(cmdTimeZone);
+            timeZoneId = timeZone.getID();
+            if (!timeZoneId.equals(cmdTimeZone)) {
+                LOGGER.warn(String.format("Using timezone [%s] for running the schedule [%s] for VM %s, as an equivalent of [%s].",
+                        timeZoneId, vmSchedule.getSchedule(), vmSchedule.getVmId(), cmdTimeZone));
+            }
+            vmSchedule.setTimeZone(timeZoneId);
+        } else {
+            timeZoneId = vmSchedule.getTimeZone();
+            timeZone = TimeZone.getTimeZone(timeZoneId);
+        }
+
+        Date startDate = vmSchedule.getStartDate().before(DateUtils.addMinutes(new Date(), 1)) ? DateUtils.addMinutes(new Date(), 1) : vmSchedule.getStartDate();
+        Date endDate = vmSchedule.getEndDate();
+        if (cmdEndDate != null) {
+            endDate = Date.from(DateUtil.getZoneDateTime(cmdEndDate, timeZone.toZoneId()).toInstant());
+        }
+
+        if (cmdStartDate != null) {
+            startDate = Date.from(DateUtil.getZoneDateTime(cmdStartDate, timeZone.toZoneId()).toInstant());
+        }
+
+        validateStartDateEndDate(Objects.requireNonNullElse(startDate, DateUtils.addMinutes(new Date(), 1)), endDate, timeZone);
+
+        if (enabled != null) {
+            vmSchedule.setEnabled(enabled);
+        }
+        if (description != null) {
+            vmSchedule.setDescription(description);
+        }
+        if (cmdEndDate != null) {
+            vmSchedule.setEndDate(endDate);
+        }
+        if (cmdStartDate != null) {
+            vmSchedule.setStartDate(startDate);
+        }
+        vmSchedule.setSchedule(cronExpression.toString());
+
+        return Transaction.execute((TransactionCallback<VMScheduleResponse>) status -> {
+            vmScheduleDao.update(cmd.getId(), vmSchedule);
+            vmScheduler.updateScheduledJob(vmSchedule);
+            CallContext.current().setEventResourceId(vm.getId());
+            CallContext.current().setEventResourceType(ApiCommandResourceType.VirtualMachine);
+            return createResponse(vmSchedule);
+        });
+    }
+
+    void validateStartDateEndDate(Date startDate, Date endDate, TimeZone tz) {
+        ZonedDateTime now = ZonedDateTime.now(tz.toZoneId());
+        ZonedDateTime zonedStartDate = ZonedDateTime.ofInstant(startDate.toInstant(), tz.toZoneId());
+
+        if (zonedStartDate.isBefore(now)) {
+            throw new InvalidParameterValueException(String.format("Invalid value for start date. Start date [%s] can't be before current time [%s].", zonedStartDate, now));
+        }
+
+        if (endDate != null) {
+            ZonedDateTime zonedEndDate = ZonedDateTime.ofInstant(endDate.toInstant(), tz.toZoneId());
+            if (zonedEndDate.isBefore(now)) {
+                throw new InvalidParameterValueException(String.format("Invalid value for end date. End date [%s] can't be before current time [%s].", zonedEndDate, now));
+            }
+            if (zonedEndDate.isBefore(zonedStartDate)) {
+                throw new InvalidParameterValueException(String.format("Invalid value for end date. End date [%s] can't be before start date [%s].", zonedEndDate, zonedStartDate));
+            }
+        }
+    }
+
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_VM_SCHEDULE_DELETE, eventDescription = "Deleting VM Schedule for VM")
+    public long removeScheduleByVmId(long vmId, boolean expunge) {
+        SearchCriteria<VMScheduleVO> sc = vmScheduleDao.getSearchCriteriaForVMId(vmId);
+        List<VMScheduleVO> vmSchedules = vmScheduleDao.search(sc, null);
+        List<Long> ids = new ArrayList<>();
+        for (final VMScheduleVO vmSchedule : vmSchedules) {
+            ids.add(vmSchedule.getId());
+        }
+        vmScheduler.removeScheduledJobs(ids);
+        if (expunge) {
+            return vmScheduleDao.expunge(sc);
+        }
+        CallContext.current().setEventResourceId(vmId);
+        CallContext.current().setEventResourceType(ApiCommandResourceType.VirtualMachine);
+        return vmScheduleDao.remove(sc);
+    }
+
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_VM_SCHEDULE_DELETE, eventDescription = "Deleting VM Schedule")
+    public Long removeSchedule(DeleteVMScheduleCmd cmd) {
+        VirtualMachine vm = userVmManager.getUserVm(cmd.getVmId());
+        accountManager.checkAccess(CallContext.current().getCallingAccount(), null, false, vm);
+
+        List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
+
+        if (ids.isEmpty()) {
+            throw new InvalidParameterValueException("Either id or ids parameter must be specified");
+        }
+        return Transaction.execute((TransactionCallback<Long>) status -> {
+            vmScheduler.removeScheduledJobs(ids);
+            CallContext.current().setEventResourceId(vm.getId());
+            CallContext.current().setEventResourceType(ApiCommandResourceType.VirtualMachine);
+            return vmScheduleDao.removeSchedulesForVmIdAndIds(vm.getId(), ids);
+        });
+    }
+}
diff --git a/server/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduler.java b/server/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduler.java
new file mode 100644
index 0000000..94867dd
--- /dev/null
+++ b/server/src/main/java/org/apache/cloudstack/vm/schedule/VMScheduler.java
@@ -0,0 +1,36 @@
+/*
+ * 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.vm.schedule;
+
+import com.cloud.utils.component.Manager;
+import com.cloud.utils.concurrency.Scheduler;
+import org.apache.cloudstack.framework.config.ConfigKey;
+
+import java.util.Date;
+import java.util.List;
+
+public interface VMScheduler extends Manager, Scheduler {
+    ConfigKey<Integer> VMScheduledJobExpireInterval = new ConfigKey<>(ConfigKey.CATEGORY_ADVANCED, Integer.class, "vmscheduler.jobs.expire.interval", "30", "VM Scheduler expire interval in days", true);
+
+    void removeScheduledJobs(List<Long> vmScheduleIds);
+
+    void updateScheduledJob(VMScheduleVO vmSchedule);
+
+    Date scheduleNextJob(VMScheduleVO vmSchedule);
+}
diff --git a/server/src/main/java/org/apache/cloudstack/vm/schedule/VMSchedulerImpl.java b/server/src/main/java/org/apache/cloudstack/vm/schedule/VMSchedulerImpl.java
new file mode 100644
index 0000000..aab970e
--- /dev/null
+++ b/server/src/main/java/org/apache/cloudstack/vm/schedule/VMSchedulerImpl.java
@@ -0,0 +1,405 @@
+/*
+ * 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.vm.schedule;
+
+import com.cloud.api.ApiGsonHelper;
+import com.cloud.event.ActionEventUtils;
+import com.cloud.event.EventTypes;
+import com.cloud.user.User;
+import com.cloud.utils.DateUtil;
+import com.cloud.utils.component.ComponentContext;
+import com.cloud.utils.component.ManagerBase;
+import com.cloud.utils.db.GlobalLock;
+import com.cloud.vm.UserVmManager;
+import com.cloud.vm.VirtualMachine;
+import com.google.common.primitives.Longs;
+import org.apache.cloudstack.api.ApiCommandResourceType;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.command.user.vm.RebootVMCmd;
+import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
+import org.apache.cloudstack.api.command.user.vm.StopVMCmd;
+import org.apache.cloudstack.framework.jobs.AsyncJobDispatcher;
+import org.apache.cloudstack.framework.jobs.AsyncJobManager;
+import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
+import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
+import org.apache.cloudstack.vm.schedule.dao.VMScheduleDao;
+import org.apache.cloudstack.vm.schedule.dao.VMScheduledJobDao;
+import org.apache.commons.lang.time.DateUtils;
+import org.apache.log4j.Logger;
+import org.springframework.scheduling.support.CronExpression;
+
+import javax.inject.Inject;
+import javax.persistence.EntityExistsException;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class VMSchedulerImpl extends ManagerBase implements VMScheduler {
+    private static Logger LOGGER = Logger.getLogger(VMSchedulerImpl.class);
+    @Inject
+    private VMScheduledJobDao vmScheduledJobDao;
+    @Inject
+    private VMScheduleDao vmScheduleDao;
+    @Inject
+    private UserVmManager userVmManager;
+    @Inject
+    private AsyncJobManager asyncJobManager;
+    private AsyncJobDispatcher asyncJobDispatcher;
+    private Timer vmSchedulerTimer;
+    private Date currentTimestamp;
+
+    private EnumMap<VMSchedule.Action, String> actionEventMap = new EnumMap<>(VMSchedule.Action.class);
+
+    public AsyncJobDispatcher getAsyncJobDispatcher() {
+        return asyncJobDispatcher;
+    }
+
+    public void setAsyncJobDispatcher(final AsyncJobDispatcher dispatcher) {
+        asyncJobDispatcher = dispatcher;
+    }
+
+    @Override
+    public void removeScheduledJobs(List<Long> vmScheduleIds) {
+        if (vmScheduleIds == null || vmScheduleIds.isEmpty()) {
+            LOGGER.debug("Removed 0 scheduled jobs");
+            return;
+        }
+        Date now = new Date();
+        int rowsRemoved = vmScheduledJobDao.expungeJobsForSchedules(vmScheduleIds, now);
+        LOGGER.debug(String.format("Removed %s VM scheduled jobs", rowsRemoved));
+    }
+
+    @Override
+    public void updateScheduledJob(VMScheduleVO vmSchedule) {
+        removeScheduledJobs(Longs.asList(vmSchedule.getId()));
+        scheduleNextJob(vmSchedule);
+    }
+
+    public Date scheduleNextJob(Long vmScheduleId) {
+        VMScheduleVO vmSchedule = vmScheduleDao.findById(vmScheduleId);
+        if (vmSchedule != null) {
+            return scheduleNextJob(vmSchedule);
+        }
+        LOGGER.debug(String.format("VM Schedule [id=%s] is removed. Not scheduling next job.", vmScheduleId));
+        return null;
+    }
+
+    @Override
+    public Date scheduleNextJob(VMScheduleVO vmSchedule) {
+        if (!vmSchedule.getEnabled()) {
+            LOGGER.debug(String.format("VM Schedule [id=%s] for VM [id=%s] is disabled. Not scheduling next job.", vmSchedule.getUuid(), vmSchedule.getVmId()));
+            return null;
+        }
+
+        CronExpression cron = DateUtil.parseSchedule(vmSchedule.getSchedule());
+        Date startDate = vmSchedule.getStartDate();
+        Date endDate = vmSchedule.getEndDate();
+        VirtualMachine vm = userVmManager.getUserVm(vmSchedule.getVmId());
+
+        if (vm == null) {
+            LOGGER.info(String.format("VM [id=%s] is removed. Disabling VM schedule [id=%s].", vmSchedule.getVmId(), vmSchedule.getUuid()));
+            vmSchedule.setEnabled(false);
+            vmScheduleDao.persist(vmSchedule);
+            return null;
+        }
+
+        ZonedDateTime now = ZonedDateTime.now(vmSchedule.getTimeZoneId());
+        ZonedDateTime zonedStartDate = ZonedDateTime.ofInstant(startDate.toInstant(), vmSchedule.getTimeZoneId());
+        ZonedDateTime zonedEndDate = null;
+        if (endDate != null) {
+            zonedEndDate = ZonedDateTime.ofInstant(endDate.toInstant(), vmSchedule.getTimeZoneId());
+        }
+        if (zonedEndDate != null && now.isAfter(zonedEndDate)) {
+            LOGGER.info(String.format("End time is less than current time. Disabling VM schedule [id=%s] for VM [id=%s].", vmSchedule.getUuid(), vmSchedule.getVmId()));
+            vmSchedule.setEnabled(false);
+            vmScheduleDao.persist(vmSchedule);
+            return null;
+        }
+
+        ZonedDateTime ts = null;
+        if (zonedStartDate.isAfter(now)) {
+            ts = cron.next(zonedStartDate);
+        } else {
+            ts = cron.next(now);
+        }
+
+        if (ts == null) {
+            LOGGER.info(String.format("No next schedule found. Disabling VM schedule [id=%s] for VM [id=%s].", vmSchedule.getUuid(), vmSchedule.getVmId()));
+            vmSchedule.setEnabled(false);
+            vmScheduleDao.persist(vmSchedule);
+            return null;
+        }
+
+        Date scheduledDateTime = Date.from(ts.toInstant());
+        VMScheduledJobVO scheduledJob = new VMScheduledJobVO(vmSchedule.getVmId(), vmSchedule.getId(), vmSchedule.getAction(), scheduledDateTime);
+        try {
+            vmScheduledJobDao.persist(scheduledJob);
+            ActionEventUtils.onScheduledActionEvent(User.UID_SYSTEM, vm.getAccountId(), actionEventMap.get(vmSchedule.getAction()),
+                    String.format("Scheduled action (%s) [vmId: %s scheduleId: %s]  at %s", vmSchedule.getAction(), vm.getUuid(), vmSchedule.getUuid(), scheduledDateTime),
+                    vm.getId(), ApiCommandResourceType.VirtualMachine.toString(), true, 0);
+        } catch (EntityExistsException exception) {
+            LOGGER.debug("Job is already scheduled.");
+        }
+        return scheduledDateTime;
+    }
+
+    @Override
+    public boolean start() {
+        actionEventMap.put(VMSchedule.Action.START, EventTypes.EVENT_VM_SCHEDULE_START);
+        actionEventMap.put(VMSchedule.Action.STOP, EventTypes.EVENT_VM_SCHEDULE_STOP);
+        actionEventMap.put(VMSchedule.Action.REBOOT, EventTypes.EVENT_VM_SCHEDULE_REBOOT);
+        actionEventMap.put(VMSchedule.Action.FORCE_STOP, EventTypes.EVENT_VM_SCHEDULE_FORCE_STOP);
+        actionEventMap.put(VMSchedule.Action.FORCE_REBOOT, EventTypes.EVENT_VM_SCHEDULE_FORCE_REBOOT);
+
+        // Adding 1 minute to currentTimestamp to ensure that
+        // jobs which were to be run at current time, doesn't cause issues
+        currentTimestamp = DateUtils.addMinutes(new Date(), 1);
+
+        scheduleNextJobs();
+
+        final TimerTask schedulerPollTask = new ManagedContextTimerTask() {
+            @Override
+            protected void runInContext() {
+                try {
+                    poll(new Date());
+                } catch (final Throwable t) {
+                    LOGGER.warn("Catch throwable in VM scheduler ", t);
+                }
+            }
+        };
+
+        vmSchedulerTimer = new Timer("VMSchedulerPollTask");
+        vmSchedulerTimer.schedule(schedulerPollTask, 5000L, 60 * 1000L);
+        return true;
+    }
+
+    @Override
+    public void poll(Date timestamp) {
+        currentTimestamp = DateUtils.round(timestamp, Calendar.MINUTE);
+        String displayTime = DateUtil.displayDateInTimezone(DateUtil.GMT_TIMEZONE, currentTimestamp);
+        LOGGER.debug(String.format("VM scheduler.poll is being called at %s", displayTime));
+
+        GlobalLock scanLock = GlobalLock.getInternLock("vmScheduler.poll");
+        try {
+            if (scanLock.lock(30)) {
+                try {
+                    scheduleNextJobs();
+                } finally {
+                    scanLock.unlock();
+                }
+            }
+        } finally {
+            scanLock.releaseRef();
+        }
+
+        scanLock = GlobalLock.getInternLock("vmScheduler.poll");
+        try {
+            if (scanLock.lock(30)) {
+                try {
+                    startJobs(); // Create async job and update scheduled job
+                } finally {
+                    scanLock.unlock();
+                }
+            }
+        } finally {
+            scanLock.releaseRef();
+        }
+
+        try {
+            cleanupVMScheduledJobs();
+        } catch (Exception e) {
+            LOGGER.warn("Error in cleaning up vm scheduled jobs", e);
+        }
+    }
+
+    private void scheduleNextJobs() {
+        for (final VMScheduleVO schedule : vmScheduleDao.listAllActiveSchedules()) {
+            try {
+                scheduleNextJob(schedule);
+            } catch (Exception e) {
+                LOGGER.warn("Error in scheduling next job for schedule " + schedule.getUuid(), e);
+            }
+        }
+    }
+
+    /**
+     * Delete scheduled jobs before vm.scheduler.expire.interval days
+     */
+    private void cleanupVMScheduledJobs() {
+        Date deleteBeforeDate = DateUtils.addDays(currentTimestamp, -1 * VMScheduledJobExpireInterval.value());
+        int rowsRemoved = vmScheduledJobDao.expungeJobsBefore(deleteBeforeDate);
+        LOGGER.info(String.format("Cleaned up %d VM scheduled job entries", rowsRemoved));
+    }
+
+    void executeJobs(Map<Long, VMScheduledJob> jobsToExecute) {
+        String displayTime = DateUtil.displayDateInTimezone(DateUtil.GMT_TIMEZONE, currentTimestamp);
+
+        for (Map.Entry<Long, VMScheduledJob> entry : jobsToExecute.entrySet()) {
+            VMScheduledJob vmScheduledJob = entry.getValue();
+            VirtualMachine vm = userVmManager.getUserVm(vmScheduledJob.getVmId());
+
+            VMScheduledJobVO tmpVMScheduleJob = null;
+            try {
+                if (LOGGER.isDebugEnabled()) {
+                    final Date scheduledTimestamp = vmScheduledJob.getScheduledTime();
+                    displayTime = DateUtil.displayDateInTimezone(DateUtil.GMT_TIMEZONE, scheduledTimestamp);
+                    LOGGER.debug(String.format("Executing %s for VM id %d for schedule id: %d at %s", vmScheduledJob.getAction(), vmScheduledJob.getVmId(), vmScheduledJob.getVmScheduleId(), displayTime));
+                }
+
+                tmpVMScheduleJob = vmScheduledJobDao.acquireInLockTable(vmScheduledJob.getId());
+                Long jobId = processJob(vmScheduledJob, vm);
+                if (jobId != null) {
+                    tmpVMScheduleJob.setAsyncJobId(jobId);
+                    vmScheduledJobDao.update(vmScheduledJob.getId(), tmpVMScheduleJob);
+                }
+            } catch (final Exception e) {
+                LOGGER.warn(String.format("Executing scheduled job id: %s failed due to %s", vmScheduledJob.getId(), e));
+            } finally {
+                if (tmpVMScheduleJob != null) {
+                    vmScheduledJobDao.releaseFromLockTable(vmScheduledJob.getId());
+                }
+            }
+        }
+    }
+
+    Long processJob(VMScheduledJob vmScheduledJob, VirtualMachine vm) {
+        if (!Arrays.asList(VirtualMachine.State.Running, VirtualMachine.State.Stopped).contains(vm.getState())) {
+            LOGGER.info(String.format("Skipping action (%s) for [vmId:%s scheduleId: %s] because VM is invalid state: %s", vmScheduledJob.getAction(), vm.getUuid(), vmScheduledJob.getVmScheduleId(), vm.getState()));
+            return null;
+        }
+
+        final Long eventId = ActionEventUtils.onCompletedActionEvent(User.UID_SYSTEM, vm.getAccountId(), null,
+                actionEventMap.get(vmScheduledJob.getAction()), true,
+                String.format("Executing action (%s) for VM Id:%s", vmScheduledJob.getAction(), vm.getUuid()),
+                vm.getId(), ApiCommandResourceType.VirtualMachine.toString(), 0);
+
+        if (vm.getState() == VirtualMachine.State.Running) {
+            switch (vmScheduledJob.getAction()) {
+                case STOP:
+                    return executeStopVMJob(vm, false, eventId);
+                case FORCE_STOP:
+                    return executeStopVMJob(vm, true, eventId);
+                case REBOOT:
+                    return executeRebootVMJob(vm, false, eventId);
+                case FORCE_REBOOT:
+                    return executeRebootVMJob(vm, true, eventId);
+            }
+        } else if (vm.getState() == VirtualMachine.State.Stopped && vmScheduledJob.getAction() == VMSchedule.Action.START) {
+            return executeStartVMJob(vm, eventId);
+        }
+
+        LOGGER.warn(String.format("Skipping action (%s) for [vmId:%s scheduleId: %s] because VM is in state: %s",
+                vmScheduledJob.getAction(), vm.getUuid(), vmScheduledJob.getVmScheduleId(), vm.getState()));
+        return null;
+    }
+
+    private void skipJobs(Map<Long, VMScheduledJob> jobsToExecute, Map<Long, List<VMScheduledJob>> jobsNotToExecute) {
+        for (Map.Entry<Long, List<VMScheduledJob>> entry : jobsNotToExecute.entrySet()) {
+            Long vmId = entry.getKey();
+            List<VMScheduledJob> skippedVmScheduledJobVOS = entry.getValue();
+            VirtualMachine vm = userVmManager.getUserVm(vmId);
+            for (final VMScheduledJob skippedVmScheduledJobVO : skippedVmScheduledJobVOS) {
+                VMScheduledJob scheduledJob = jobsToExecute.get(vmId);
+                LOGGER.info(String.format("Skipping scheduled job [id: %s, vmId: %s] because of conflict with another scheduled job [id: %s]", skippedVmScheduledJobVO.getUuid(), vm.getUuid(), scheduledJob.getUuid()));
+            }
+        }
+    }
+
+    /**
+     * Create async jobs for VM scheduled jobs
+     */
+    private void startJobs() {
+        String displayTime = DateUtil.displayDateInTimezone(DateUtil.GMT_TIMEZONE, currentTimestamp);
+
+        final List<VMScheduledJobVO> vmScheduledJobs = vmScheduledJobDao.listJobsToStart(currentTimestamp);
+        LOGGER.debug(String.format("Got %d scheduled jobs to be executed at %s", vmScheduledJobs.size(), displayTime));
+
+        Map<Long, VMScheduledJob> jobsToExecute = new HashMap<>();
+        Map<Long, List<VMScheduledJob>> jobsNotToExecute = new HashMap<>();
+        for (final VMScheduledJobVO vmScheduledJobVO : vmScheduledJobs) {
+            long vmId = vmScheduledJobVO.getVmId();
+            if (jobsToExecute.get(vmId) == null) {
+                jobsToExecute.put(vmId, vmScheduledJobVO);
+            } else {
+                jobsNotToExecute.computeIfAbsent(vmId, k -> new ArrayList<>()).add(vmScheduledJobVO);
+            }
+        }
+
+        executeJobs(jobsToExecute);
+        skipJobs(jobsToExecute, jobsNotToExecute);
+    }
+
+    long executeStartVMJob(VirtualMachine vm, long eventId) {
+        final Map<String, String> params = new HashMap<>();
+        params.put(ApiConstants.ID, String.valueOf(vm.getId()));
+        params.put("ctxUserId", "1");
+        params.put("ctxAccountId", String.valueOf(vm.getAccountId()));
+        params.put(ApiConstants.CTX_START_EVENT_ID, String.valueOf(eventId));
+
+        final StartVMCmd cmd = new StartVMCmd();
+        ComponentContext.inject(cmd);
+
+        AsyncJobVO job = new AsyncJobVO("", User.UID_SYSTEM, vm.getAccountId(), StartVMCmd.class.getName(), ApiGsonHelper.getBuilder().create().toJson(params), vm.getId(), cmd.getApiResourceType() != null ? cmd.getApiResourceType().toString() : null, null);
+        job.setDispatcher(asyncJobDispatcher.getName());
+
+        return asyncJobManager.submitAsyncJob(job);
+    }
+
+    long executeStopVMJob(VirtualMachine vm, boolean isForced, long eventId) {
+        final Map<String, String> params = new HashMap<>();
+        params.put(ApiConstants.ID, String.valueOf(vm.getId()));
+        params.put("ctxUserId", "1");
+        params.put("ctxAccountId", String.valueOf(vm.getAccountId()));
+        params.put(ApiConstants.CTX_START_EVENT_ID, String.valueOf(eventId));
+        params.put(ApiConstants.FORCED, String.valueOf(isForced));
+
+        final StopVMCmd cmd = new StopVMCmd();
+        ComponentContext.inject(cmd);
+
+        AsyncJobVO job = new AsyncJobVO("", User.UID_SYSTEM, vm.getAccountId(), StopVMCmd.class.getName(), ApiGsonHelper.getBuilder().create().toJson(params), vm.getId(), cmd.getApiResourceType() != null ? cmd.getApiResourceType().toString() : null, null);
+        job.setDispatcher(asyncJobDispatcher.getName());
+
+        return asyncJobManager.submitAsyncJob(job);
+    }
+
+    long executeRebootVMJob(VirtualMachine vm, boolean isForced, long eventId) {
+        final Map<String, String> params = new HashMap<>();
+        params.put(ApiConstants.ID, String.valueOf(vm.getId()));
+        params.put("ctxUserId", "1");
+        params.put("ctxAccountId", String.valueOf(vm.getAccountId()));
+        params.put(ApiConstants.CTX_START_EVENT_ID, String.valueOf(eventId));
+        params.put(ApiConstants.FORCED, String.valueOf(isForced));
+
+        final RebootVMCmd cmd = new RebootVMCmd();
+        ComponentContext.inject(cmd);
+
+        AsyncJobVO job = new AsyncJobVO("", User.UID_SYSTEM, vm.getAccountId(), RebootVMCmd.class.getName(), ApiGsonHelper.getBuilder().create().toJson(params), vm.getId(), cmd.getApiResourceType() != null ? cmd.getApiResourceType().toString() : null, null);
+        job.setDispatcher(asyncJobDispatcher.getName());
+
+        return asyncJobManager.submitAsyncJob(job);
+    }
+}
diff --git a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml
index a9db159..ee676aa 100644
--- a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml
+++ b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml
@@ -21,10 +21,10 @@
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:util="http://www.springframework.org/schema/util"
-       
+
        xsi:schemaLocation="http://www.springframework.org/schema/beans
                       http://www.springframework.org/schema/beans/spring-beans.xsd
-                      http://www.springframework.org/schema/aop 
+                      http://www.springframework.org/schema/aop
                       http://www.springframework.org/schema/aop/spring-aop.xsd
                       http://www.springframework.org/schema/context
                       http://www.springframework.org/schema/context/spring-context.xsd
@@ -129,7 +129,7 @@
 
     <bean id="capacityManagerImpl" class="com.cloud.capacity.CapacityManagerImpl" />
 
-    <bean id="configurationManagerImpl" class="com.cloud.configuration.ConfigurationManagerImpl" >  
+    <bean id="configurationManagerImpl" class="com.cloud.configuration.ConfigurationManagerImpl" >
         <property name="secChecker" value="#{securityCheckersRegistry.registered}" />
     </bean>
 
@@ -211,45 +211,45 @@
 
     <bean id="uploadMonitorImpl" class="com.cloud.storage.upload.UploadMonitorImpl" />
     <bean id="usageServiceImpl" class="com.cloud.usage.UsageServiceImpl" />
-    
+
     <bean id="virtualNetworkApplianceManagerImpl"
         class="com.cloud.network.router.VirtualNetworkApplianceManagerImpl" />
-        
+
     <bean id="vpcManagerImpl" class="com.cloud.network.vpc.VpcManagerImpl" >
         <property name="vpcElements" value="#{vpcProvidersRegistry.registered}"></property>
     </bean>
-    
+
     <bean id="vpcTxCallable" class="com.cloud.network.vpc.VpcPrivateGatewayTransactionCallable" />
-    
+
     <bean id="vpcVirtualNetworkApplianceManagerImpl"
         class="com.cloud.network.router.VpcVirtualNetworkApplianceManagerImpl" />
-    
+
     <bean id="virtualNetworkApplianceFactory"
         class="com.cloud.network.rules.VirtualNetworkApplianceFactory" />
-    
+
     <bean id="topologyContext" class="org.apache.cloudstack.network.topology.NetworkTopologyContext" init-method="init" />
-    
+
     <bean id="basicNetworkTopology" class="org.apache.cloudstack.network.topology.BasicNetworkTopology" />
     <bean id="advancedNetworkTopology" class="org.apache.cloudstack.network.topology.AdvancedNetworkTopology" />
-    
+
     <bean id="basicNetworkVisitor" class="org.apache.cloudstack.network.topology.BasicNetworkVisitor" />
     <bean id="advancedNetworkVisitor" class="org.apache.cloudstack.network.topology.AdvancedNetworkVisitor" />
-    
+
     <bean id="commandSetupHelper"
         class="com.cloud.network.router.CommandSetupHelper" />
-    
+
     <bean id="routerControlHelper"
         class="com.cloud.network.router.RouterControlHelper" />
-        
+
     <bean id="networkHelper"
         class="com.cloud.network.router.NetworkHelperImpl" />
-        
+
     <bean id="vpcNetworkHelper"
         class="com.cloud.network.router.VpcNetworkHelperImpl" />
-        
+
     <bean id="nicProfileHelper"
         class="com.cloud.network.router.NicProfileHelperImpl" />
-        
+
     <bean id="routerDeploymentDefinitionBuilder"
         class="org.apache.cloudstack.network.router.deployment.RouterDeploymentDefinitionBuilder" />
 
@@ -257,6 +257,9 @@
         <property name="name" value="ApiAsyncJobDispatcher" />
     </bean>
 
+    <bean id="shutdownManager" class="org.apache.cloudstack.shutdown.ShutdownManagerImpl" >
+        <property name="name" value="shutdownManager" />
+    </bean>
 
     <bean id="statsCollector" class="com.cloud.server.StatsCollector" />
 
@@ -265,14 +268,14 @@
     <bean id="domainManagerImpl" class="com.cloud.user.DomainManagerImpl" />
 
     <bean id="downloadMonitorImpl" class="com.cloud.storage.download.DownloadMonitorImpl" />
-  
+
     <bean id="lBHealthCheckManagerImpl" class="com.cloud.network.lb.LBHealthCheckManagerImpl" />
 
     <bean id="volumeApiServiceImpl" class="com.cloud.storage.VolumeApiServiceImpl">
         <property name="storagePoolAllocators"
             value="#{storagePoolAllocatorsRegistry.registered}" />
     </bean>
-    
+
     <bean id="ApplicationLoadBalancerService" class="org.apache.cloudstack.network.lb.ApplicationLoadBalancerManagerImpl" />
 
     <bean id="vMSnapshotManagerImpl" class="com.cloud.vm.snapshot.VMSnapshotManagerImpl" />
@@ -344,4 +347,9 @@
 
     <bean id="resourceIconManager" class="com.cloud.resourceicon.ResourceIconManagerImpl" />
 
+    <bean id="VMScheduleManagerImpl" class="org.apache.cloudstack.vm.schedule.VMScheduleManagerImpl" />
+    <bean id="VMSchedulerImpl" class="org.apache.cloudstack.vm.schedule.VMSchedulerImpl">
+        <property name="asyncJobDispatcher" ref="ApiAsyncJobDispatcher" />
+    </bean>
+
 </beans>
diff --git a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-misc-context.xml b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-misc-context.xml
index 1900717..244c2d9 100644
--- a/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-misc-context.xml
+++ b/server/src/main/resources/META-INF/cloudstack/core/spring-server-core-misc-context.xml
@@ -81,4 +81,4 @@
 
     <bean id="DPDKHelper" class="com.cloud.hypervisor.kvm.dpdk.DpdkHelperImpl" />
     
-</beans>
\ No newline at end of file
+</beans>
diff --git a/server/src/main/resources/META-INF/cloudstack/server-alert-adapter-backend/module.properties b/server/src/main/resources/META-INF/cloudstack/server-alert-adapter-backend/module.properties
index 120c91d..765be37 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-alert-adapter-backend/module.properties
+++ b/server/src/main/resources/META-INF/cloudstack/server-alert-adapter-backend/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=server-alert-adapter-backend
-parent=backend
\ No newline at end of file
+parent=backend
diff --git a/server/src/main/resources/META-INF/cloudstack/server-alert-adapter-compute/module.properties b/server/src/main/resources/META-INF/cloudstack/server-alert-adapter-compute/module.properties
index 12213f4..9cd4878 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-alert-adapter-compute/module.properties
+++ b/server/src/main/resources/META-INF/cloudstack/server-alert-adapter-compute/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=server-alert-adapter-compute
-parent=compute
\ No newline at end of file
+parent=compute
diff --git a/server/src/main/resources/META-INF/cloudstack/server-alert-adapter-storage/module.properties b/server/src/main/resources/META-INF/cloudstack/server-alert-adapter-storage/module.properties
index c156009..2716ac7 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-alert-adapter-storage/module.properties
+++ b/server/src/main/resources/META-INF/cloudstack/server-alert-adapter-storage/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=server-alert-adapter-storage
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/server/src/main/resources/META-INF/cloudstack/server-allocator/module.properties b/server/src/main/resources/META-INF/cloudstack/server-allocator/module.properties
index f69c483..f0075d0 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-allocator/module.properties
+++ b/server/src/main/resources/META-INF/cloudstack/server-allocator/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=server-allocator
-parent=allocator
\ No newline at end of file
+parent=allocator
diff --git a/server/src/main/resources/META-INF/cloudstack/server-api/module.properties b/server/src/main/resources/META-INF/cloudstack/server-api/module.properties
index 74a9c50..034e81a 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-api/module.properties
+++ b/server/src/main/resources/META-INF/cloudstack/server-api/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=server-api
-parent=api
\ No newline at end of file
+parent=api
diff --git a/server/src/main/resources/META-INF/cloudstack/server-api/spring-server-api-context.xml b/server/src/main/resources/META-INF/cloudstack/server-api/spring-server-api-context.xml
index 30e7647..1f1b24e 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-api/spring-server-api-context.xml
+++ b/server/src/main/resources/META-INF/cloudstack/server-api/spring-server-api-context.xml
@@ -30,4 +30,4 @@
     <bean id="domainChecker" class="com.cloud.acl.DomainChecker" />
     <bean id="affinityGroupAccessChecker" class="com.cloud.acl.AffinityGroupAccessChecker" />
 
-</beans>
\ No newline at end of file
+</beans>
diff --git a/server/src/main/resources/META-INF/cloudstack/server-compute/module.properties b/server/src/main/resources/META-INF/cloudstack/server-compute/module.properties
index 7b42a91..6766e6d 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-compute/module.properties
+++ b/server/src/main/resources/META-INF/cloudstack/server-compute/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=server-compute
-parent=compute
\ No newline at end of file
+parent=compute
diff --git a/server/src/main/resources/META-INF/cloudstack/server-discoverer/module.properties b/server/src/main/resources/META-INF/cloudstack/server-discoverer/module.properties
index 0c4f5e1..9d49120 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-discoverer/module.properties
+++ b/server/src/main/resources/META-INF/cloudstack/server-discoverer/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=server-discoverer
-parent=discoverer
\ No newline at end of file
+parent=discoverer
diff --git a/server/src/main/resources/META-INF/cloudstack/server-fencer/module.properties b/server/src/main/resources/META-INF/cloudstack/server-fencer/module.properties
index b4a8684..b045d11 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-fencer/module.properties
+++ b/server/src/main/resources/META-INF/cloudstack/server-fencer/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=server-fencer
-parent=compute
\ No newline at end of file
+parent=compute
diff --git a/server/src/main/resources/META-INF/cloudstack/server-investigator/module.properties b/server/src/main/resources/META-INF/cloudstack/server-investigator/module.properties
index 85e6882..dffdb2f 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-investigator/module.properties
+++ b/server/src/main/resources/META-INF/cloudstack/server-investigator/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=server-investigator
-parent=compute
\ No newline at end of file
+parent=compute
diff --git a/server/src/main/resources/META-INF/cloudstack/server-network/module.properties b/server/src/main/resources/META-INF/cloudstack/server-network/module.properties
index 95a7d1b..5d99a31 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-network/module.properties
+++ b/server/src/main/resources/META-INF/cloudstack/server-network/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=server-network
-parent=network
\ No newline at end of file
+parent=network
diff --git a/server/src/main/resources/META-INF/cloudstack/server-planner/module.properties b/server/src/main/resources/META-INF/cloudstack/server-planner/module.properties
index 541b769..023afd7 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-planner/module.properties
+++ b/server/src/main/resources/META-INF/cloudstack/server-planner/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=server-planner
-parent=planner
\ No newline at end of file
+parent=planner
diff --git a/server/src/main/resources/META-INF/cloudstack/server-storage/module.properties b/server/src/main/resources/META-INF/cloudstack/server-storage/module.properties
index 9eaf2d0..5a427b2 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-storage/module.properties
+++ b/server/src/main/resources/META-INF/cloudstack/server-storage/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=server-storage
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/server/src/main/resources/META-INF/cloudstack/server-template-adapter/module.properties b/server/src/main/resources/META-INF/cloudstack/server-template-adapter/module.properties
index 85ba317..66721d3 100644
--- a/server/src/main/resources/META-INF/cloudstack/server-template-adapter/module.properties
+++ b/server/src/main/resources/META-INF/cloudstack/server-template-adapter/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=server-template-adapter
-parent=storage
\ No newline at end of file
+parent=storage
diff --git a/server/src/main/resources/META-INF/cloudstack/system/spring-server-system-context.xml b/server/src/main/resources/META-INF/cloudstack/system/spring-server-system-context.xml
index 9eb0a4c..d742c63 100644
--- a/server/src/main/resources/META-INF/cloudstack/system/spring-server-system-context.xml
+++ b/server/src/main/resources/META-INF/cloudstack/system/spring-server-system-context.xml
@@ -33,4 +33,4 @@
         </constructor-arg>
     </bean>
 
-</beans>
\ No newline at end of file
+</beans>
diff --git a/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java b/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java
index 715924d..5d1986e 100644
--- a/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java
+++ b/server/src/test/java/com/cloud/configuration/ConfigurationManagerTest.java
@@ -37,6 +37,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
+import java.util.Set;
 import java.util.UUID;
 
 import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd;
@@ -548,15 +549,67 @@
     }
 
     @Test
+    public void validateEmptySourceNatServiceCapablitiesTest() {
+        Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>();
+
+        configurationMgr.validateSourceNatServiceCapablities(sourceNatServiceCapabilityMap);
+    }
+
+    @Test
+    public void validateInvalidSourceNatTypeForSourceNatServiceCapablitiesTest() {
+        Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>();
+        sourceNatServiceCapabilityMap.put(Capability.SupportedSourceNatTypes, "perDomain");
+
+        boolean caught = false;
+        try {
+            configurationMgr.validateSourceNatServiceCapablities(sourceNatServiceCapabilityMap);
+        } catch (InvalidParameterValueException e) {
+            Assert.assertTrue(e.getMessage(), e.getMessage().contains("Either peraccount or perzone source NAT type can be specified for SupportedSourceNatTypes"));
+            caught = true;
+        }
+        Assert.assertTrue("should not be accepted", caught);
+    }
+
+    @Test
+    public void validateInvalidBooleanValueForSourceNatServiceCapablitiesTest() {
+        Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>();
+        sourceNatServiceCapabilityMap.put(Capability.RedundantRouter, "maybe");
+
+        boolean caught = false;
+        try {
+            configurationMgr.validateSourceNatServiceCapablities(sourceNatServiceCapabilityMap);
+        } catch (InvalidParameterValueException e) {
+            Assert.assertTrue(e.getMessage(), e.getMessage().contains("Unknown specified value for RedundantRouter"));
+            caught = true;
+        }
+        Assert.assertTrue("should not be accepted", caught);
+    }
+
+    @Test
+    public void validateInvalidCapabilityForSourceNatServiceCapablitiesTest() {
+        Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>();
+        sourceNatServiceCapabilityMap.put(Capability.ElasticIp, "perDomain");
+
+        boolean caught = false;
+        try {
+            configurationMgr.validateSourceNatServiceCapablities(sourceNatServiceCapabilityMap);
+        } catch (InvalidParameterValueException e) {
+            Assert.assertTrue(e.getMessage(), e.getMessage().contains("Only SupportedSourceNatTypes, Network.Capability[name=RedundantRouter] capabilities can be specified for source nat service"));
+            caught = true;
+        }
+        Assert.assertTrue("should not be accepted", caught);
+    }
+
+    @Test
     public void validateEmptyStaticNatServiceCapablitiesTest() {
-        Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>();
+        Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>();
 
         configurationMgr.validateStaticNatServiceCapablities(staticNatServiceCapabilityMap);
     }
 
     @Test
     public void validateInvalidStaticNatServiceCapablitiesTest() {
-        Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>();
+        Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>();
         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "Frue and Talse");
 
         boolean caught = false;
@@ -570,8 +623,42 @@
     }
 
     @Test
+    public void isRedundantRouter() {
+        Map<Network.Service, Set<Network.Provider>> serviceCapabilityMap = new HashMap<>();
+        Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>();
+        sourceNatServiceCapabilityMap.put(Capability.SupportedSourceNatTypes, "peraccount");
+        sourceNatServiceCapabilityMap.put(Capability.RedundantRouter, "true");
+        Assert.assertTrue(configurationMgr.isRedundantRouter(serviceCapabilityMap, sourceNatServiceCapabilityMap));
+    }
+
+    @Test
+    public void isSharedSourceNat() {
+        Map<Network.Service, Set<Network.Provider>> serviceCapabilityMap = new HashMap<>();
+        Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>();
+        sourceNatServiceCapabilityMap.put(Capability.SupportedSourceNatTypes, "perzone");
+        Assert.assertTrue(configurationMgr.isSharedSourceNat(serviceCapabilityMap, sourceNatServiceCapabilityMap));
+    }
+
+    @Test
+    public void isNotSharedSourceNat() {
+        Map<Network.Service, Set<Network.Provider>> serviceCapabilityMap = new HashMap<>();
+        Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>();
+        sourceNatServiceCapabilityMap.put(Capability.SupportedSourceNatTypes, "peraccount");
+        Assert.assertFalse(configurationMgr.isSharedSourceNat(serviceCapabilityMap, sourceNatServiceCapabilityMap));
+    }
+
+    @Test
+    public void sourceNatCapabilitiesContainValidValues() {
+        Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>();
+        sourceNatServiceCapabilityMap.put(Capability.SupportedSourceNatTypes, "peraccount");
+        sourceNatServiceCapabilityMap.put(Capability.RedundantRouter, "True");
+
+        Assert.assertTrue(configurationMgr.sourceNatCapabilitiesContainValidValues(sourceNatServiceCapabilityMap));
+    }
+
+    @Test
     public void validateTTStaticNatServiceCapablitiesTest() {
-        Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>();
+        Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>();
         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "true and Talse");
         staticNatServiceCapabilityMap.put(Capability.ElasticIp, "True");
 
@@ -580,7 +667,7 @@
 
     @Test
     public void validateFTStaticNatServiceCapablitiesTest() {
-        Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>();
+        Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>();
         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "false");
         staticNatServiceCapabilityMap.put(Capability.ElasticIp, "True");
 
@@ -589,7 +676,7 @@
 
     @Test
     public void validateTFStaticNatServiceCapablitiesTest() {
-        Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>();
+        Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>();
         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "true and Talse");
         staticNatServiceCapabilityMap.put(Capability.ElasticIp, "false");
 
@@ -608,7 +695,7 @@
 
     @Test
     public void validateFFStaticNatServiceCapablitiesTest() {
-        Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>();
+        Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>();
         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "false");
         staticNatServiceCapabilityMap.put(Capability.ElasticIp, "False");
 
diff --git a/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java b/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java
index d79010e..0b6004b 100644
--- a/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java
+++ b/server/src/test/java/com/cloud/deploy/DeploymentPlanningManagerImplTest.java
@@ -21,39 +21,31 @@
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
-import com.cloud.dc.ClusterDetailsVO;
-import com.cloud.dc.DataCenter;
-import com.cloud.gpu.GPU;
-import com.cloud.host.Host;
-import com.cloud.host.HostVO;
-import com.cloud.host.Status;
-import com.cloud.storage.DiskOfferingVO;
-import com.cloud.storage.Storage;
-import com.cloud.storage.StoragePool;
-import com.cloud.storage.VMTemplateVO;
-import com.cloud.storage.Volume;
-import com.cloud.storage.VolumeVO;
-import com.cloud.storage.dao.VMTemplateDao;
-import com.cloud.user.AccountVO;
-import com.cloud.user.dao.AccountDao;
-import com.cloud.utils.Pair;
-import com.cloud.vm.VMInstanceVO;
-import com.cloud.vm.VirtualMachine;
-import com.cloud.vm.VirtualMachine.Type;
-import com.cloud.vm.VirtualMachineProfile;
-import com.cloud.vm.VirtualMachineProfileImpl;
+import org.apache.cloudstack.affinity.AffinityGroupProcessor;
+import org.apache.cloudstack.affinity.AffinityGroupService;
+import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
 import org.apache.cloudstack.affinity.dao.AffinityGroupDomainMapDao;
+import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
+import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMReservationDao;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.messagebus.MessageBus;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+import org.apache.cloudstack.test.utils.SpringUtils;
 import org.apache.commons.collections.CollectionUtils;
 import org.junit.Assert;
 import org.junit.Before;
@@ -79,22 +71,14 @@
 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 import org.springframework.test.context.support.AnnotationConfigContextLoader;
 
-import org.apache.cloudstack.affinity.AffinityGroupProcessor;
-import org.apache.cloudstack.affinity.AffinityGroupService;
-import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
-import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
-import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMReservationDao;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
-import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
-import org.apache.cloudstack.framework.messagebus.MessageBus;
-import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
-import org.apache.cloudstack.test.utils.SpringUtils;
-
 import com.cloud.agent.AgentManager;
 import com.cloud.capacity.CapacityManager;
 import com.cloud.capacity.dao.CapacityDao;
+import com.cloud.configuration.ConfigurationManagerImpl;
 import com.cloud.dc.ClusterDetailsDao;
+import com.cloud.dc.ClusterDetailsVO;
 import com.cloud.dc.ClusterVO;
+import com.cloud.dc.DataCenter;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.dao.ClusterDao;
 import com.cloud.dc.dao.DataCenterDao;
@@ -105,26 +89,46 @@
 import com.cloud.deploy.dao.PlannerHostReservationDao;
 import com.cloud.exception.AffinityConflictException;
 import com.cloud.exception.InsufficientServerCapacityException;
+import com.cloud.gpu.GPU;
 import com.cloud.gpu.dao.HostGpuGroupsDao;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.host.Status;
 import com.cloud.host.dao.HostDao;
+import com.cloud.host.dao.HostDetailsDao;
 import com.cloud.host.dao.HostTagsDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
-import com.cloud.resource.ResourceManager;
 import com.cloud.org.Grouping.AllocationState;
+import com.cloud.resource.ResourceManager;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDetailsDao;
+import com.cloud.storage.DiskOfferingVO;
+import com.cloud.storage.ScopeType;
+import com.cloud.storage.Storage;
 import com.cloud.storage.StorageManager;
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.Volume;
+import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.storage.dao.GuestOSCategoryDao;
 import com.cloud.storage.dao.GuestOSDao;
 import com.cloud.storage.dao.StoragePoolHostDao;
+import com.cloud.storage.dao.VMTemplateDao;
 import com.cloud.storage.dao.VolumeDao;
 import com.cloud.user.AccountManager;
+import com.cloud.user.AccountVO;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.utils.Pair;
 import com.cloud.utils.component.ComponentContext;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.Type;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.VirtualMachineProfileImpl;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.UserVmDetailsDao;
 import com.cloud.vm.dao.VMInstanceDao;
-import com.cloud.host.dao.HostDetailsDao;
 
 @RunWith(SpringJUnit4ClassRunner.class)
 @ContextConfiguration(loader = AnnotationConfigContextLoader.class)
@@ -191,6 +195,9 @@
     @Inject
     ClusterDetailsDao clusterDetailsDao;
 
+    @Inject
+    PrimaryDataStoreDao primaryDataStoreDao;
+
     @Mock
     Host host;
 
@@ -1075,4 +1082,84 @@
         Assert.assertEquals(6, hosts.get(6).getId());
         Assert.assertEquals(2, hosts.get(7).getId());
     }
+
+    private List<Long> prepareMockForAvoidOtherClustersForDeploymentIfMigrationDisabled(boolean configValue, boolean mockVolumes, boolean mockClusterStoreVolume) {
+        try {
+            Field f = ConfigKey.class.getDeclaredField("_defaultValue");
+            f.setAccessible(true);
+            f.set(ConfigurationManagerImpl.MIGRATE_VM_ACROSS_CLUSTERS, String.valueOf(configValue));
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+        List<Long> allClusters = List.of(101L, 102L, 103L, 104L);
+        Mockito.when(_clusterDao.listAllClusters(Mockito.anyLong())).thenReturn(allClusters);
+        if (mockVolumes) {
+            VolumeVO vol1 = Mockito.mock(VolumeVO.class);
+            Mockito.when(vol1.getPoolId()).thenReturn(1L);
+            VolumeVO vol2 = Mockito.mock(VolumeVO.class);
+            Mockito.when(vol2.getPoolId()).thenReturn(2L);
+            StoragePoolVO pool1 = Mockito.mock(StoragePoolVO.class);
+            Mockito.when(pool1.getScope()).thenReturn(ScopeType.ZONE);
+            Mockito.when(primaryDataStoreDao.findById(1L)).thenReturn(pool1);
+            StoragePoolVO pool2 = Mockito.mock(StoragePoolVO.class);
+            Mockito.when(pool2.getScope()).thenReturn(mockClusterStoreVolume ? ScopeType.CLUSTER : ScopeType.GLOBAL);
+            Mockito.when(primaryDataStoreDao.findById(2L)).thenReturn(pool2);
+            Mockito.when(volDao.findUsableVolumesForInstance(1L)).thenReturn(List.of(vol1, vol2));
+        } else {
+            Mockito.when(volDao.findUsableVolumesForInstance(1L)).thenReturn(new ArrayList<>());
+        }
+        return allClusters;
+    }
+
+    @Test
+    public void avoidOtherClustersForDeploymentIfMigrationDisabledNonValidHost() {
+        prepareMockForAvoidOtherClustersForDeploymentIfMigrationDisabled(false, false, false);
+        VirtualMachine vm = Mockito.mock(VirtualMachine.class);
+        ExcludeList excludeList = new ExcludeList();
+        _dpm.avoidOtherClustersForDeploymentIfMigrationDisabled(vm, null, excludeList);
+        Assert.assertTrue(CollectionUtils.isEmpty(excludeList.getClustersToAvoid()));
+
+        Host lastHost = Mockito.mock(Host.class);
+        Mockito.when(lastHost.getClusterId()).thenReturn(null);
+        _dpm.avoidOtherClustersForDeploymentIfMigrationDisabled(vm, lastHost, excludeList);
+        Assert.assertTrue(CollectionUtils.isEmpty(excludeList.getClustersToAvoid()));
+    }
+
+    private Set<Long> runAvoidOtherClustersForDeploymentIfMigrationDisabledTest() {
+        VirtualMachine vm = Mockito.mock(VirtualMachine.class);
+        Mockito.when(vm.getId()).thenReturn(1L);
+        ExcludeList excludeList = new ExcludeList();
+        Host lastHost = Mockito.mock(Host.class);
+        Long sourceClusterId = 101L;
+        Mockito.when(lastHost.getClusterId()).thenReturn(sourceClusterId);
+        _dpm.avoidOtherClustersForDeploymentIfMigrationDisabled(vm, lastHost, excludeList);
+        return excludeList.getClustersToAvoid();
+    }
+
+    @Test
+    public void avoidOtherClustersForDeploymentIfMigrationDisabledConfigAllows() {
+        prepareMockForAvoidOtherClustersForDeploymentIfMigrationDisabled(true,false, false);
+        Assert.assertTrue(CollectionUtils.isEmpty(runAvoidOtherClustersForDeploymentIfMigrationDisabledTest()));
+    }
+
+    @Test
+    public void avoidOtherClustersForDeploymentIfMigrationDisabledNoVmVolumes() {
+        prepareMockForAvoidOtherClustersForDeploymentIfMigrationDisabled(false,false, false);
+        Assert.assertTrue(CollectionUtils.isEmpty(runAvoidOtherClustersForDeploymentIfMigrationDisabledTest()));
+    }
+
+    @Test
+    public void avoidOtherClustersForDeploymentIfMigrationDisabledVmVolumesNonValidScope() {
+        prepareMockForAvoidOtherClustersForDeploymentIfMigrationDisabled(false,true, false);
+        Assert.assertTrue(CollectionUtils.isEmpty(runAvoidOtherClustersForDeploymentIfMigrationDisabledTest()));
+    }
+
+    @Test
+    public void avoidOtherClustersForDeploymentIfMigrationDisabledValid() {
+        List<Long> allClusters = prepareMockForAvoidOtherClustersForDeploymentIfMigrationDisabled(false,true, true);
+        Set<Long> avoidedClusters = runAvoidOtherClustersForDeploymentIfMigrationDisabledTest();
+        Assert.assertTrue(CollectionUtils.isNotEmpty(avoidedClusters));
+        Assert.assertEquals(allClusters.size()-1, avoidedClusters.size());
+        Assert.assertFalse(avoidedClusters.contains(allClusters.get(0)));
+    }
 }
diff --git a/server/src/test/java/com/cloud/network/IpAddressManagerTest.java b/server/src/test/java/com/cloud/network/IpAddressManagerTest.java
index 50ad62e..ef5ad8c 100644
--- a/server/src/test/java/com/cloud/network/IpAddressManagerTest.java
+++ b/server/src/test/java/com/cloud/network/IpAddressManagerTest.java
@@ -23,11 +23,13 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.lenient;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Vector;
 
 import com.cloud.user.Account;
 import org.junit.Assert;
@@ -230,4 +232,14 @@
         return network;
     }
 
+    @Test
+    public void updateSourceNatIpAddress() throws Exception {
+        IPAddressVO requestedIp = Mockito.mock(IPAddressVO.class);
+        IPAddressVO oldIp = Mockito.mock(IPAddressVO.class);
+        List<IPAddressVO> userIps = new Vector<>();
+        userIps.add(oldIp);
+        ipAddressManager.updateSourceNatIpAddress(requestedIp, userIps);
+        verify(requestedIp).setSourceNat(true);
+        verify(oldIp).setSourceNat(false);
+    }
 }
diff --git a/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java b/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java
index fcf7ad3..8235395 100644
--- a/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java
+++ b/server/src/test/java/com/cloud/network/NetworkServiceImplTest.java
@@ -17,8 +17,10 @@
 package com.cloud.network;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.lenient;
 import static org.mockito.Mockito.mock;
@@ -34,6 +36,7 @@
 import java.util.Map;
 import java.util.UUID;
 
+import com.cloud.exception.InsufficientAddressCapacityException;
 import org.apache.cloudstack.alert.AlertService;
 import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd;
 import org.apache.cloudstack.api.command.user.network.UpdateNetworkCmd;
@@ -81,7 +84,6 @@
 import com.cloud.org.Grouping;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
-import com.cloud.user.AccountManagerImpl;
 import com.cloud.user.AccountService;
 import com.cloud.user.AccountVO;
 import com.cloud.user.User;
@@ -122,8 +124,6 @@
     @Mock
     NetworkOfferingServiceMapDao networkOfferingServiceMapDao;
     @Mock
-    AccountManager accountMgr;
-    @Mock
     EntityManager entityMgr;
     @Mock
     NetworkService networkService;
@@ -162,8 +162,8 @@
     @Mock
     ServiceOfferingVO serviceOfferingVoMock;
 
-    @InjectMocks
-    AccountManagerImpl accountManagerImpl;
+    @Mock
+    IpAddressManager ipAddressManager;
     @Mock
     ConfigKey<Integer> privateMtuKey;
     @Mock
@@ -223,7 +223,7 @@
         service._networkOfferingDao = networkOfferingDao;
         service._physicalNetworkDao = physicalNetworkDao;
         service._dcDao = dcDao;
-        service._accountMgr = accountMgr;
+        service._accountMgr = accountManager;
         service._networkMgr = networkManager;
         service.alertManager = alertManager;
         service._configMgr = configMgr;
@@ -236,6 +236,7 @@
         service.routerDao = routerDao;
         service.commandSetupHelper = commandSetupHelper;
         service.networkHelper = networkHelper;
+        service._ipAddrMgr = ipAddressManager;
         PowerMockito.mockStatic(CallContext.class);
         CallContext callContextMock = PowerMockito.mock(CallContext.class);
         PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
@@ -248,8 +249,8 @@
         Mockito.when(networkOfferingDao.findById(1L)).thenReturn(offering);
         Mockito.when(physicalNetworkDao.findById(Mockito.anyLong())).thenReturn(phyNet);
         Mockito.when(dcDao.findById(Mockito.anyLong())).thenReturn(dc);
-        Mockito.lenient().doNothing().when(accountMgr).checkAccess(accountMock, networkOffering, dc);
-        Mockito.when(accountMgr.isRootAdmin(accountMock.getId())).thenReturn(true);
+        Mockito.lenient().doNothing().when(accountManager).checkAccess(accountMock, networkOffering, dc);
+        Mockito.when(accountManager.isRootAdmin(accountMock.getId())).thenReturn(true);
     }
 
     @Test
@@ -352,6 +353,7 @@
         ReflectionTestUtils.setField(createNetworkCmd, "privateMtu", privateMtu);
         ReflectionTestUtils.setField(createNetworkCmd, "physicalNetworkId", null);
         Mockito.when(offering.isSystemOnly()).thenReturn(false);
+        Mockito.when(dc.getId()).thenReturn(1L);
         Mockito.when(dc.getAllocationState()).thenReturn(Grouping.AllocationState.Enabled);
         Map<String, String> networkProvidersMap = new HashMap<String, String>();
         Mockito.when(networkManager.finalizeServicesAndProvidersForNetwork(ArgumentMatchers.any(NetworkOffering.class), anyLong())).thenReturn(networkProvidersMap);
@@ -409,6 +411,7 @@
         ReflectionTestUtils.setField(createNetworkCmd, "privateMtu", privateMtu);
         ReflectionTestUtils.setField(createNetworkCmd, "physicalNetworkId", null);
         ReflectionTestUtils.setField(createNetworkCmd, "vpcId", 1L);
+        Mockito.when(dc.getId()).thenReturn(1L);
         Mockito.when(configMgr.isOfferingForVpc(offering)).thenReturn(true);
         Mockito.when(vpcDao.findById(anyLong())).thenReturn(vpc);
 
@@ -562,7 +565,7 @@
         }
     }
 
-    @Test(expected = InvalidParameterValueException.class)
+    @Test(expected = CloudRuntimeException.class)
     public void testCreateNetworkDnsOfferingServiceFailure() {
         registerCallContext();
         CreateNetworkCmd cmd = Mockito.mock(CreateNetworkCmd.class);
@@ -577,7 +580,7 @@
         }
     }
 
-    @Test(expected = InvalidParameterValueException.class)
+    @Test(expected = CloudRuntimeException.class)
     public void testCreateIp4NetworkIp6DnsFailure() {
         registerCallContext();
         CreateNetworkCmd cmd = Mockito.mock(CreateNetworkCmd.class);
@@ -770,4 +773,143 @@
 
         networkServiceImplMock.validateIfServiceOfferingIsActiveAndSystemVmTypeIsDomainRouter(1l);
     }
+
+    @Test
+    public void validateNotSharedNetworkRouterIPv4() {
+        NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class);
+        when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.L2);
+        service.validateSharedNetworkRouterIPs(null, null, null, null, null, null, null, null, null, ntwkOff);
+    }
+
+    @Test
+    public void validateSharedNetworkRouterIPs() {
+        String startIP = "10.0.16.2";
+        String endIP = "10.0.16.100";
+        String routerIPv4 = "10.0.16.100";
+        String routerPv6 = "fd17:ac56:1234:2000::fb";
+        String startIPv6 = "fd17:ac56:1234:2000::1";
+        String endIPv6 = "fd17:ac56:1234:2000::fc";
+        NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class);
+        when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.Shared);
+        service.validateSharedNetworkRouterIPs(IP4_GATEWAY, startIP, endIP, IP4_NETMASK, routerIPv4, routerPv6, startIPv6, endIPv6, IP6_CIDR, ntwkOff);
+    }
+
+    @Test
+    public void validateSharedNetworkWrongRouterIPv4() {
+        String startIP = "10.0.16.2";
+        String endIP = "10.0.16.100";
+        String routerIPv4 = "10.0.16.101";
+        String routerPv6 = "fd17:ac56:1234:2000::fb";
+        String startIPv6 = "fd17:ac56:1234:2000::1";
+        String endIPv6 = "fd17:ac56:1234:2000::fc";
+        NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class);
+        when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.Shared);
+        boolean passing = false;
+        try {
+            service.validateSharedNetworkRouterIPs(IP4_GATEWAY, startIP, endIP, IP4_NETMASK, routerIPv4, routerPv6, startIPv6, endIPv6, IP6_CIDR, ntwkOff);
+        } catch (CloudRuntimeException e) {
+            Assert.assertTrue(e.getMessage().contains("Router IPv4 IP provided is not within the specified range: "));
+            passing = true;
+        }
+        Assert.assertTrue(passing);
+    }
+
+    @Test
+    public void validateSharedNetworkNoEndOfIPv6Range() {
+        String startIP = null;
+        String endIP = null;
+        String routerIPv4 = null;
+        String routerPv6 = "fd17:ac56:1234:2000::1";
+        String startIPv6 = "fd17:ac56:1234:2000::1";
+        String endIPv6 = null;
+        NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class);
+        when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.Shared);
+        service.validateSharedNetworkRouterIPs(IP4_GATEWAY, startIP, endIP, IP4_NETMASK, routerIPv4, routerPv6, startIPv6, endIPv6, IP6_CIDR, ntwkOff);
+    }
+
+    @Test
+    public void validateSharedNetworkIPv6RouterNotInRange() {
+        String routerIPv4 = null;
+        String routerIPv6 = "fd17:ac56:1234:2001::1";
+        NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class);
+        when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.Shared);
+        boolean passing = true;
+        try {
+            service.validateSharedNetworkRouterIPs(IP4_GATEWAY, null, null, IP4_NETMASK, routerIPv4, routerIPv6, null, null, IP6_CIDR, ntwkOff);
+            passing = false;
+        } catch (CloudRuntimeException e) {
+            Assert.assertTrue(e.getMessage().contains("Router IPv6 address provided is not with the network range"));
+        }
+        Assert.assertTrue(passing);
+    }
+
+    @Test
+    public void invalidateSharedNetworkIPv6RouterAddress() {
+        String routerIPv6 = "fd17:ac56:1234:2000::fg";
+        NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class);
+        when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.Shared);
+        boolean passing = false;
+        try {
+            service.validateSharedNetworkRouterIPs(IP4_GATEWAY, null, null, IP4_NETMASK, null, routerIPv6, null, null, IP6_CIDR, ntwkOff);
+        } catch (CloudRuntimeException e) {
+            Assert.assertTrue(e.getMessage().contains("Router IPv6 address provided is of incorrect format"));
+            passing = true;
+        }
+        Assert.assertTrue(passing);
+    }
+
+    @Test
+    public void invalidateSharedNetworkIPv4RouterAddress() {
+        String routerIPv4 = "10.100.1000.1";
+        NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class);
+        when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.Shared);
+        boolean passing = false;
+        try {
+            service.validateSharedNetworkRouterIPs(IP4_GATEWAY, null, null, IP4_NETMASK, routerIPv4, null, null, null, IP6_CIDR, ntwkOff);
+        } catch (CloudRuntimeException e) {
+            Assert.assertTrue(e.getMessage().contains("Router IPv4 IP provided is of incorrect format"));
+            passing = true;
+        }
+        Assert.assertTrue(passing);
+    }
+
+    @Test
+    public void checkAndDontSetSourceNatIp() {
+        CreateNetworkCmd cmd = new CreateNetworkCmd();
+        try {
+            service.checkAndSetRouterSourceNatIp(account, cmd, null);
+        } catch (InsufficientAddressCapacityException | ResourceAllocationException e) {
+            Assert.fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void checkAndSetSourceNatIp() {
+        String srcNatIp = "10.100.1000.10000";
+        Long networkOfferingId = 2l;
+        Long zoneId = 3l;
+        registerCallContext();
+        ReflectionTestUtils.setField(createNetworkCmd, "networkOfferingId", networkOfferingId);
+        ReflectionTestUtils.setField(createNetworkCmd, "sourceNatIP", srcNatIp);
+        ReflectionTestUtils.setField(createNetworkCmd, "zoneId", zoneId);
+        ReflectionTestUtils.setField(createNetworkCmd, "physicalNetworkId", null);
+        NetworkVO networkVO = Mockito.spy(NetworkVO.class);
+        IpAddress ipAddress = Mockito.mock(IPAddressVO.class);
+        NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class);
+        Long networkId = 7l;
+        when(networkVO.getId()).thenReturn(networkId);
+        when(networkVO.getGuestType()).thenReturn(Network.GuestType.Isolated);
+        when(networkDao.findById(networkId)).thenReturn(networkVO);
+        when(entityMgr.findById(NetworkOffering.class, networkOfferingId)).thenReturn(ntwkOff);
+        when(entityMgr.findById(eq(DataCenter.class), anyLong())).thenReturn(dc);
+        when(ipAddress.getId()).thenReturn(5l);
+        when(networkVO.getId()).thenReturn(networkId);
+        when(networkVO.getGuestType()).thenReturn(Network.GuestType.Isolated);
+        try {
+            when(ipAddressManager.allocateIp(any(), anyBoolean(), any(), anyLong(), any(), any(), eq(srcNatIp))).thenReturn(ipAddress);
+            service.checkAndSetRouterSourceNatIp(account, createNetworkCmd, networkVO);
+        } catch (InsufficientAddressCapacityException | ResourceAllocationException e) {
+            Assert.fail(e.getMessage());
+        }
+    }
 }
diff --git a/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java b/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java
index c820026..13cee3a 100644
--- a/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java
+++ b/server/src/test/java/com/cloud/network/vpc/VpcManagerImplTest.java
@@ -42,8 +42,10 @@
 
 import com.cloud.alert.AlertManager;
 import com.cloud.network.NetworkService;
+import com.cloud.network.dao.FirewallRulesDao;
 import org.apache.cloudstack.acl.SecurityChecker;
 import org.apache.cloudstack.alert.AlertService;
+import org.apache.cloudstack.api.command.user.vpc.UpdateVPCCmd;
 import org.apache.cloudstack.context.CallContext;
 import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
 import org.junit.After;
@@ -149,6 +151,8 @@
     AlertManager alertManager;
     @Mock
     NetworkService networkServiceMock;
+    @Mock
+    FirewallRulesDao firewallDao;
 
     public static final long ACCOUNT_ID = 1;
     private AccountVO account;
@@ -200,6 +204,7 @@
         manager._vpcOffDao = vpcOfferingDao;
         manager._dcDao = dataCenterDao;
         manager._ntwkSvc = networkServiceMock;
+        manager._firewallDao = firewallDao;
         CallContext.register(Mockito.mock(User.class), Mockito.mock(Account.class));
         registerCallContext();
     }
@@ -354,9 +359,10 @@
     }
 
     @Test
-    public void testUpdateVpcNetwork() throws ResourceUnavailableException {
+    public void testUpdateVpcNetwork() throws ResourceUnavailableException, InsufficientCapacityException {
         long vpcId = 1L;
         Integer publicMtu = 1450;
+        String sourceNatIp = "1.2.3.4";
         Account accountMock = Mockito.mock(Account.class);
         VpcVO vpcVO = new VpcVO();
 
@@ -398,9 +404,31 @@
         Mockito.when(networkDao.update(anyLong(), any())).thenReturn(true);
         Mockito.when(vpcDao.update(vpcId, vpcVO)).thenReturn(true);
 
-        manager.updateVpc(vpcId, null, null, null, true, publicMtu);
-        Assert.assertEquals(publicMtu, vpcVO.getPublicMtu());
+        UpdateVPCCmd cmd = Mockito.mock(UpdateVPCCmd.class);
+        Mockito.when(cmd.getId()).thenReturn(vpcId);
+        Mockito.when(cmd.getVpcName()).thenReturn(null);
+        Mockito.when(cmd.getDisplayText()).thenReturn(null);
+        Mockito.when(cmd.getCustomId()).thenReturn(null);
+        Mockito.when(cmd.isDisplayVpc()).thenReturn(true);
+        Mockito.when(cmd.getPublicMtu()).thenReturn(publicMtu);
+        Mockito.when(cmd.getSourceNatIP()).thenReturn(sourceNatIp);
 
+        manager.updateVpc(cmd);
+        Assert.assertEquals(publicMtu, vpcVO.getPublicMtu());
+    }
+
+    @Test
+    public void verifySourceNatIp() {
+        String sourceNatIp = "1.2.3.4";
+        VpcVO vpcVO = Mockito.mock(VpcVO.class); //new VpcVO(1l, "vpc", null, 10l, 1l, 1l, "10.1.0.0/16", null, false, false, false, null, null, null, null);
+        Mockito.when(vpcVO.getId()).thenReturn(1l);
+        IPAddressVO requestedIp = Mockito.mock(IPAddressVO.class);//new IPAddressVO(new Ip(sourceNatIp), 1l, 1l, 1l, true);
+        Mockito.when(ipAddressDao.findByIp(sourceNatIp)).thenReturn(requestedIp);
+        Mockito.when(requestedIp.getVpcId()).thenReturn(1l);
+        Mockito.when(requestedIp.getVpcId()).thenReturn(1l);
+        Mockito.when(firewallDao.countRulesByIpId(1l)).thenReturn(0l);
+        Assert.assertNull(manager.validateSourceNatip(vpcVO, null));
+        Assert.assertEquals(requestedIp, manager.validateSourceNatip(vpcVO, sourceNatIp));
     }
 
     @Test
diff --git a/server/src/test/java/com/cloud/projects/MockProjectManagerImpl.java b/server/src/test/java/com/cloud/projects/MockProjectManagerImpl.java
index 988d675..4aa50fe 100644
--- a/server/src/test/java/com/cloud/projects/MockProjectManagerImpl.java
+++ b/server/src/test/java/com/cloud/projects/MockProjectManagerImpl.java
@@ -85,12 +85,12 @@
     }
 
     @Override
-    public Project updateProject(long id, String displayText, String newOwnerName) throws ResourceAllocationException {
+    public Project updateProject(long id, String name, String displayText, String newOwnerName) throws ResourceAllocationException {
         return null;
     }
 
     @Override
-    public Project updateProject(long id, String displayText, String newOwnerName, Long userId, Role newRole) throws ResourceAllocationException {
+    public Project updateProject(long id, String name, String displayText, String newOwnerName, Long userId, Role newRole) throws ResourceAllocationException {
         // TODO Auto-generated method stub
         return null;
     }
diff --git a/server/src/test/java/com/cloud/projects/ProjectManagerImplTest.java b/server/src/test/java/com/cloud/projects/ProjectManagerImplTest.java
new file mode 100644
index 0000000..90bc2b4
--- /dev/null
+++ b/server/src/test/java/com/cloud/projects/ProjectManagerImplTest.java
@@ -0,0 +1,98 @@
+// 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.projects;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+
+import com.cloud.projects.dao.ProjectDao;
+
+
+@RunWith(MockitoJUnitRunner.class)
+public class ProjectManagerImplTest {
+
+    @Spy
+    @InjectMocks
+    ProjectManagerImpl projectManager;
+
+    @Mock
+    ProjectDao projectDao;
+
+    List<ProjectVO> updateProjects;
+
+    @Before
+    public void setUp() throws Exception {
+        updateProjects = new ArrayList<>();
+        Mockito.when(projectDao.update(Mockito.anyLong(), Mockito.any(ProjectVO.class))).thenAnswer((Answer<Boolean>) invocation -> {
+            ProjectVO project = (ProjectVO)invocation.getArguments()[1];
+            updateProjects.add(project);
+            return true;
+        });
+    }
+
+    private void runUpdateProjectNameAndDisplayTextTest(boolean nonNullName, boolean nonNullDisplayText) {
+        ProjectVO projectVO = new ProjectVO();
+        String newName = nonNullName ? "NewName" : null;
+        String newDisplayText = nonNullDisplayText ? "NewDisplayText" : null;
+        projectManager.updateProjectNameAndDisplayText(projectVO, newName, newDisplayText);
+        if (!nonNullName && !nonNullDisplayText) {
+            Assert.assertTrue(updateProjects.isEmpty());
+        } else {
+            Assert.assertFalse(updateProjects.isEmpty());
+            Assert.assertEquals(1, updateProjects.size());
+            ProjectVO updatedProject = updateProjects.get(0);
+            Assert.assertNotNull(updatedProject);
+            if (nonNullName) {
+                Assert.assertEquals(newName, updatedProject.getName());
+            }
+            if (nonNullDisplayText) {
+                Assert.assertEquals(newDisplayText, updatedProject.getDisplayText());
+            }
+        }
+    }
+
+    @Test
+    public void testUpdateProjectNameAndDisplayTextNoUpdate() {
+        runUpdateProjectNameAndDisplayTextTest(false, false);
+    }
+
+    @Test
+    public void testUpdateProjectNameAndDisplayTextUpdateName() {
+        runUpdateProjectNameAndDisplayTextTest(true, false);
+    }
+
+    @Test
+    public void testUpdateProjectNameAndDisplayTextUpdateDisplayText() {
+        runUpdateProjectNameAndDisplayTextTest(false, true);
+    }
+
+    @Test
+    public void testUpdateProjectNameAndDisplayTextUpdateNameDisplayText() {
+        runUpdateProjectNameAndDisplayTextTest(true, true);
+    }
+}
diff --git a/server/src/test/java/com/cloud/resource/MockResourceManagerImpl.java b/server/src/test/java/com/cloud/resource/MockResourceManagerImpl.java
index 4d5b5ba..73d4adf 100755
--- a/server/src/test/java/com/cloud/resource/MockResourceManagerImpl.java
+++ b/server/src/test/java/com/cloud/resource/MockResourceManagerImpl.java
@@ -73,6 +73,11 @@
         return null;
     }
 
+    @Override
+    public Host autoUpdateHostAllocationState(Long hostId, ResourceState.Event resourceEvent) throws NoTransitionException {
+        return null;
+    }
+
     /* (non-Javadoc)
      * @see com.cloud.resource.ResourceService#cancelMaintenance(com.cloud.api.commands.CancelMaintenanceCmd)
      */
diff --git a/server/src/test/java/com/cloud/server/ManagementServerImplTest.java b/server/src/test/java/com/cloud/server/ManagementServerImplTest.java
index cf8df1a..1de5b25 100644
--- a/server/src/test/java/com/cloud/server/ManagementServerImplTest.java
+++ b/server/src/test/java/com/cloud/server/ManagementServerImplTest.java
@@ -22,6 +22,35 @@
 import static org.mockito.Mockito.lenient;
 import static org.mockito.Mockito.when;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cloudstack.annotation.dao.AnnotationDao;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.command.user.address.ListPublicIpAddressesCmd;
+import org.apache.cloudstack.api.command.user.ssh.RegisterSSHKeyPairCmd;
+import org.apache.cloudstack.api.command.user.userdata.DeleteUserDataCmd;
+import org.apache.cloudstack.api.command.user.userdata.ListUserDataCmd;
+import org.apache.cloudstack.api.command.user.userdata.RegisterUserDataCmd;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.userdata.UserDataManager;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+import org.springframework.test.util.ReflectionTestUtils;
+
 import com.cloud.dc.Vlan.VlanType;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.host.DetailVO;
@@ -49,37 +78,8 @@
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.UserVmDetailVO;
 import com.cloud.vm.UserVmVO;
-import com.cloud.vm.dao.UserVmDetailsDao;
 import com.cloud.vm.dao.UserVmDao;
-
-import org.apache.cloudstack.annotation.dao.AnnotationDao;
-import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.BaseCmd;
-import org.apache.cloudstack.api.command.user.address.ListPublicIpAddressesCmd;
-import org.apache.cloudstack.api.command.user.ssh.RegisterSSHKeyPairCmd;
-import org.apache.cloudstack.api.command.user.userdata.DeleteUserDataCmd;
-import org.apache.cloudstack.api.command.user.userdata.ListUserDataCmd;
-import org.apache.cloudstack.api.command.user.userdata.RegisterUserDataCmd;
-import org.apache.cloudstack.context.CallContext;
-import org.apache.cloudstack.framework.config.ConfigKey;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.reflect.Whitebox;
-import org.springframework.test.util.ReflectionTestUtils;
-
-import java.util.ArrayList;
-import java.util.List;
+import com.cloud.vm.dao.UserVmDetailsDao;
 
 @RunWith(PowerMockRunner.class)
 @PrepareForTest(CallContext.class)
@@ -121,6 +121,9 @@
     @Mock
     UserVmDao _userVmDao;
 
+    @Mock
+    UserDataManager userDataManager;
+
     @Spy
     ManagementServerImpl spy = new ManagementServerImpl();
 
@@ -145,6 +148,7 @@
         spy.annotationDao = annotationDao;
         spy._UserVmDetailsDao = userVmDetailsDao;
         spy._detailsDao = hostDetailsDao;
+        spy.userDataManager = userDataManager;
     }
 
     @After
@@ -304,13 +308,15 @@
         when(callContextMock.getCallingAccount()).thenReturn(account);
         when(_accountMgr.finalizeOwner(nullable(Account.class), nullable(String.class), nullable(Long.class), nullable(Long.class))).thenReturn(account);
 
+        String testUserData = "testUserdata";
         RegisterUserDataCmd cmd = Mockito.mock(RegisterUserDataCmd.class);
-        when(cmd.getUserData()).thenReturn("testUserdata");
+        when(cmd.getUserData()).thenReturn(testUserData);
         when(cmd.getName()).thenReturn("testName");
         when(cmd.getHttpMethod()).thenReturn(BaseCmd.HTTPMethod.GET);
 
         when(_userDataDao.findByName(account.getAccountId(), account.getDomainId(), "testName")).thenReturn(null);
-        when(_userDataDao.findByUserData(account.getAccountId(), account.getDomainId(), "testUserdata")).thenReturn(null);
+        when(_userDataDao.findByUserData(account.getAccountId(), account.getDomainId(), testUserData)).thenReturn(null);
+        when(userDataManager.validateUserData(testUserData,BaseCmd.HTTPMethod.GET)).thenReturn(testUserData);
 
         UserData userData = spy.registerUserData(cmd);
         Assert.assertEquals("testName", userData.getName());
diff --git a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java
index 18b4a89..ef00190 100644
--- a/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java
+++ b/server/src/test/java/com/cloud/vm/UserVmManagerImplTest.java
@@ -16,8 +16,6 @@
 // under the License.
 package com.cloud.vm;
 
-import com.cloud.storage.Volume;
-import com.cloud.storage.dao.VolumeDao;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -38,18 +36,16 @@
 import java.util.List;
 import java.util.Map;
 
-import com.cloud.template.VirtualMachineTemplate;
-import com.cloud.user.UserData;
-import com.cloud.user.UserDataVO;
-import com.cloud.user.dao.UserDataDao;
-import com.cloud.utils.exception.CloudRuntimeException;
 import org.apache.cloudstack.api.BaseCmd.HTTPMethod;
-import org.apache.cloudstack.api.command.user.vm.ResetVMUserDataCmd;
 import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
+import org.apache.cloudstack.api.command.user.vm.ResetVMUserDataCmd;
 import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
 import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
 import org.apache.cloudstack.context.CallContext;
 import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
+import org.apache.cloudstack.userdata.UserDataManager;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -67,11 +63,19 @@
 import com.cloud.dc.DataCenter;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.deploy.DataCenterDeployment;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.deploy.DeploymentPlanner;
+import com.cloud.deploy.DeploymentPlanningManager;
 import com.cloud.exception.InsufficientAddressCapacityException;
 import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InsufficientServerCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor;
 import com.cloud.network.NetworkModel;
 import com.cloud.network.dao.NetworkDao;
@@ -81,21 +85,30 @@
 import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.storage.DiskOfferingVO;
 import com.cloud.storage.GuestOSVO;
+import com.cloud.storage.ScopeType;
 import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.Volume;
 import com.cloud.storage.VolumeApiService;
 import com.cloud.storage.VolumeVO;
 import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.storage.dao.GuestOSDao;
 import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.template.VirtualMachineTemplate;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
 import com.cloud.user.AccountService;
 import com.cloud.user.AccountVO;
 import com.cloud.user.ResourceLimitService;
+import com.cloud.user.UserData;
+import com.cloud.user.UserDataVO;
 import com.cloud.user.UserVO;
 import com.cloud.user.dao.AccountDao;
+import com.cloud.user.dao.UserDataDao;
 import com.cloud.uservm.UserVm;
+import com.cloud.utils.Pair;
 import com.cloud.utils.db.EntityManager;
+import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.dao.NicDao;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.UserVmDetailsDao;
@@ -182,6 +195,18 @@
     UserDataDao userDataDao;
 
     @Mock
+    PrimaryDataStoreDao primaryDataStoreDao;
+
+    @Mock
+    VirtualMachineManager virtualMachineManager;
+
+    @Mock
+    DeploymentPlanningManager planningManager;
+
+    @Mock
+    HostDao hostDao;
+
+    @Mock
     private VolumeVO volumeVOMock;
 
     @Mock
@@ -193,6 +218,9 @@
     @Mock
     private ServiceOfferingVO serviceOffering;
 
+    @Mock
+    UserDataManager userDataManager;
+
     private static final long vmId = 1l;
     private static final long zoneId = 2L;
     private static final long accountId = 3L;
@@ -690,29 +718,6 @@
     }
 
     @Test
-    public void testUserDataAppend() {
-        String userData = "testUserdata";
-        String templateUserData = "testTemplateUserdata";
-        Long userDataId = 1L;
-
-        VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
-        when(template.getUserDataId()).thenReturn(2L);
-        when(template.getUserDataOverridePolicy()).thenReturn(UserData.UserDataOverridePolicy.APPEND);
-
-        UserDataVO templateUserDataVO = Mockito.mock(UserDataVO.class);
-        doReturn(templateUserDataVO).when(userDataDao).findById(2L);
-        when(templateUserDataVO.getUserData()).thenReturn(templateUserData);
-
-        UserDataVO apiUserDataVO = Mockito.mock(UserDataVO.class);
-        doReturn(apiUserDataVO).when(userDataDao).findById(userDataId);
-        when(apiUserDataVO.getUserData()).thenReturn(userData);
-
-        String finalUserdata = userVmManagerImpl.finalizeUserData(null, userDataId, template);
-
-        Assert.assertEquals(finalUserdata, templateUserData+userData);
-    }
-
-    @Test
     public void testUserDataWithoutTemplate() {
         String userData = "testUserdata";
         Long userDataId = 1L;
@@ -831,10 +836,13 @@
         when(templateDao.findByIdIncludingRemoved(2L)).thenReturn(template);
         when(template.getUserDataId()).thenReturn(null);
 
-        when(cmd.getUserData()).thenReturn("testUserdata");
+        String testUserData = "testUserdata";
+        when(cmd.getUserData()).thenReturn(testUserData);
         when(cmd.getUserdataId()).thenReturn(null);
         when(cmd.getHttpMethod()).thenReturn(HTTPMethod.GET);
 
+        when(userDataManager.validateUserData(testUserData, HTTPMethod.GET)).thenReturn(testUserData);
+
         try {
             doNothing().when(userVmManagerImpl).updateUserData(userVmVO);
             userVmManagerImpl.resetVMUserData(cmd);
@@ -868,12 +876,15 @@
         when(templateDao.findByIdIncludingRemoved(2L)).thenReturn(template);
         when(template.getUserDataId()).thenReturn(null);
 
+        String testUserData = "testUserdata";
         when(cmd.getUserdataId()).thenReturn(1L);
         UserDataVO apiUserDataVO = Mockito.mock(UserDataVO.class);
         when(userDataDao.findById(1L)).thenReturn(apiUserDataVO);
-        when(apiUserDataVO.getUserData()).thenReturn("testUserdata");
+        when(apiUserDataVO.getUserData()).thenReturn(testUserData);
         when(cmd.getHttpMethod()).thenReturn(HTTPMethod.GET);
 
+        when(userDataManager.validateUserData(testUserData, HTTPMethod.GET)).thenReturn(testUserData);
+
         try {
             doNothing().when(userVmManagerImpl).updateUserData(userVmVO);
             userVmManagerImpl.resetVMUserData(cmd);
@@ -912,4 +923,122 @@
 
         userVmManagerImpl.createVirtualMachine(deployVMCmd);
     }
+
+    private List<VolumeVO> mockVolumesForIsAnyVmVolumeUsingLocalStorageTest(int localVolumes, int nonLocalVolumes) {
+        List<VolumeVO> volumes = new ArrayList<>();
+        for (int i=0; i< localVolumes + nonLocalVolumes; ++i) {
+            VolumeVO vol = Mockito.mock(VolumeVO.class);
+            long index = i + 1;
+            Mockito.when(vol.getDiskOfferingId()).thenReturn(index);
+            Mockito.when(vol.getPoolId()).thenReturn(index);
+            DiskOfferingVO diskOffering = Mockito.mock(DiskOfferingVO.class);
+            Mockito.when(diskOfferingDao.findById(index)).thenReturn(diskOffering);
+            StoragePoolVO storagePool = Mockito.mock(StoragePoolVO.class);
+            Mockito.when(primaryDataStoreDao.findById(index)).thenReturn(storagePool);
+            if (i < localVolumes) {
+                if ((localVolumes + nonLocalVolumes) % 2 == 0) {
+                    Mockito.when(diskOffering.isUseLocalStorage()).thenReturn(true);
+                } else {
+
+                    Mockito.when(diskOffering.isUseLocalStorage()).thenReturn(false);
+                    Mockito.when(storagePool.isLocal()).thenReturn(true);
+                }
+            } else {
+                Mockito.when(diskOffering.isUseLocalStorage()).thenReturn(false);
+                Mockito.when(storagePool.isLocal()).thenReturn(false);
+            }
+            volumes.add(vol);
+        }
+        return volumes;
+    }
+
+    @Test
+    public void testIsAnyVmVolumeUsingLocalStorage() {
+        Assert.assertTrue(userVmManagerImpl.isAnyVmVolumeUsingLocalStorage(mockVolumesForIsAnyVmVolumeUsingLocalStorageTest(1, 0)));
+        Assert.assertTrue(userVmManagerImpl.isAnyVmVolumeUsingLocalStorage(mockVolumesForIsAnyVmVolumeUsingLocalStorageTest(2, 0)));
+        Assert.assertTrue(userVmManagerImpl.isAnyVmVolumeUsingLocalStorage(mockVolumesForIsAnyVmVolumeUsingLocalStorageTest(1, 1)));
+        Assert.assertFalse(userVmManagerImpl.isAnyVmVolumeUsingLocalStorage(mockVolumesForIsAnyVmVolumeUsingLocalStorageTest(0, 2)));
+        Assert.assertFalse(userVmManagerImpl.isAnyVmVolumeUsingLocalStorage(mockVolumesForIsAnyVmVolumeUsingLocalStorageTest(0, 0)));
+    }
+
+    private List<VolumeVO> mockVolumesForIsAllVmVolumesOnZoneWideStore(int nullPoolIdVolumes, int nullPoolVolumes, int zoneVolumes, int nonZoneVolumes) {
+        List<VolumeVO> volumes = new ArrayList<>();
+        for (int i=0; i< nullPoolIdVolumes + nullPoolVolumes + zoneVolumes + nonZoneVolumes; ++i) {
+            VolumeVO vol = Mockito.mock(VolumeVO.class);
+            volumes.add(vol);
+            if (i < nullPoolIdVolumes) {
+                Mockito.when(vol.getPoolId()).thenReturn(null);
+                continue;
+            }
+            long index = i + 1;
+            Mockito.when(vol.getPoolId()).thenReturn(index);
+            if (i < nullPoolVolumes) {
+                Mockito.when(primaryDataStoreDao.findById(index)).thenReturn(null);
+                continue;
+            }
+            StoragePoolVO storagePool = Mockito.mock(StoragePoolVO.class);
+            Mockito.when(primaryDataStoreDao.findById(index)).thenReturn(storagePool);
+            if (i < zoneVolumes) {
+                Mockito.when(storagePool.getScope()).thenReturn(ScopeType.ZONE);
+            } else {
+                Mockito.when(storagePool.getScope()).thenReturn(ScopeType.CLUSTER);
+            }
+        }
+        return volumes;
+    }
+
+    @Test
+    public void testIsAllVmVolumesOnZoneWideStoreCombinations() {
+        Assert.assertTrue(userVmManagerImpl.isAllVmVolumesOnZoneWideStore(mockVolumesForIsAllVmVolumesOnZoneWideStore(0, 0, 1, 0)));
+        Assert.assertTrue(userVmManagerImpl.isAllVmVolumesOnZoneWideStore(mockVolumesForIsAllVmVolumesOnZoneWideStore(0, 0, 2, 0)));
+        Assert.assertFalse(userVmManagerImpl.isAllVmVolumesOnZoneWideStore(mockVolumesForIsAllVmVolumesOnZoneWideStore(0, 0, 1, 1)));
+        Assert.assertFalse(userVmManagerImpl.isAllVmVolumesOnZoneWideStore(mockVolumesForIsAllVmVolumesOnZoneWideStore(0, 0, 0, 0)));
+        Assert.assertFalse(userVmManagerImpl.isAllVmVolumesOnZoneWideStore(mockVolumesForIsAllVmVolumesOnZoneWideStore(1, 0, 1, 1)));
+        Assert.assertFalse(userVmManagerImpl.isAllVmVolumesOnZoneWideStore(mockVolumesForIsAllVmVolumesOnZoneWideStore(0, 1, 1, 1)));
+    }
+
+    private Pair<VMInstanceVO, Host> mockObjectsForChooseVmMigrationDestinationUsingVolumePoolMapTest(boolean nullPlan, Host destinationHost) {
+        VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
+        Mockito.when(vm.getId()).thenReturn(1L);
+        Mockito.when(vm.getServiceOfferingId()).thenReturn(1L);
+        Host host = Mockito.mock(Host.class);
+        Mockito.when(host.getId()).thenReturn(1L);
+        Mockito.when(hostDao.findById(1L)).thenReturn(Mockito.mock(HostVO.class));
+        Mockito.when(virtualMachineManager.getMigrationDeployment(Mockito.any(VirtualMachine.class),
+                        Mockito.any(Host.class), Mockito.nullable(Long.class),
+                        Mockito.any(DeploymentPlanner.ExcludeList.class)))
+                .thenReturn(Mockito.mock(DataCenterDeployment.class));
+        if (!nullPlan) {
+            try {
+                DeployDestination destination = Mockito.mock(DeployDestination.class);
+                Mockito.when(destination.getHost()).thenReturn(destinationHost);
+                Mockito.when(planningManager.planDeployment(Mockito.any(VirtualMachineProfile.class),
+                                Mockito.any(DataCenterDeployment.class), Mockito.any(DeploymentPlanner.ExcludeList.class),
+                                Mockito.nullable(DeploymentPlanner.class)))
+                        .thenReturn(destination);
+            } catch (InsufficientServerCapacityException e) {
+                Assert.fail("Failed to mock DeployDestination");
+            }
+        }
+        return new Pair<>(vm, host);
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void testChooseVmMigrationDestinationUsingVolumePoolMapNullDestination() {
+        Pair<VMInstanceVO, Host> pair = mockObjectsForChooseVmMigrationDestinationUsingVolumePoolMapTest(true, null);
+        userVmManagerImpl.chooseVmMigrationDestinationUsingVolumePoolMap(pair.first(), pair.second(), null);
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void testChooseVmMigrationDestinationUsingVolumePoolMapNullHost() {
+        Pair<VMInstanceVO, Host> pair = mockObjectsForChooseVmMigrationDestinationUsingVolumePoolMapTest(false, null);
+        userVmManagerImpl.chooseVmMigrationDestinationUsingVolumePoolMap(pair.first(), pair.second(), null);
+    }
+
+    @Test
+    public void testChooseVmMigrationDestinationUsingVolumePoolMapValid() {
+        Host destinationHost = Mockito.mock(Host.class);
+        Pair<VMInstanceVO, Host> pair = mockObjectsForChooseVmMigrationDestinationUsingVolumePoolMapTest(false, destinationHost);
+        Assert.assertEquals(destinationHost, userVmManagerImpl.chooseVmMigrationDestinationUsingVolumePoolMap(pair.first(), pair.second(), null));
+    }
 }
diff --git a/server/src/test/java/com/cloud/vm/UserVmManagerTest.java b/server/src/test/java/com/cloud/vm/UserVmManagerTest.java
index 7cc2c8a..a0ad321 100644
--- a/server/src/test/java/com/cloud/vm/UserVmManagerTest.java
+++ b/server/src/test/java/com/cloud/vm/UserVmManagerTest.java
@@ -18,7 +18,6 @@
 package com.cloud.vm;
 
 import static org.hamcrest.Matchers.instanceOf;
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
@@ -38,7 +37,6 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -48,7 +46,6 @@
 
 import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
-import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
 import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
 import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
@@ -841,26 +838,4 @@
         _userVmMgr.persistDeviceBusInfo(_vmMock, "lsilogic");
         verify(_vmDao, times(1)).saveDetails(any(UserVmVO.class));
     }
-
-    @Test
-    public void testValideBase64WithoutPadding() {
-        // fo should be encoded in base64 either as Zm8 or Zm8=
-        String encodedUserdata = "Zm8";
-        String encodedUserdataWithPadding = "Zm8=";
-
-        // Verify that we accept both but return the padded version
-        assertTrue("validate return the value with padding", encodedUserdataWithPadding.equals(_userVmMgr.validateUserData(encodedUserdata, BaseCmd.HTTPMethod.GET)));
-        assertTrue("validate return the value with padding", encodedUserdataWithPadding.equals(_userVmMgr.validateUserData(encodedUserdataWithPadding, BaseCmd.HTTPMethod.GET)));
-    }
-
-    @Test
-    public void testValidateUrlEncodedBase64() throws UnsupportedEncodingException {
-        // fo should be encoded in base64 either as Zm8 or Zm8=
-        String encodedUserdata = "Zm+8/w8=";
-        String urlEncodedUserdata = java.net.URLEncoder.encode(encodedUserdata, "UTF-8");
-
-        // Verify that we accept both but return the padded version
-        assertEquals("validate return the value with padding", encodedUserdata, _userVmMgr.validateUserData(encodedUserdata, BaseCmd.HTTPMethod.GET));
-        assertEquals("validate return the value with padding", encodedUserdata, _userVmMgr.validateUserData(urlEncodedUserdata, BaseCmd.HTTPMethod.GET));
-    }
 }
diff --git a/server/src/test/java/org/apache/cloudstack/acl/RoleManagerImplTest.java b/server/src/test/java/org/apache/cloudstack/acl/RoleManagerImplTest.java
index 049bc17..9f0d40a 100644
--- a/server/src/test/java/org/apache/cloudstack/acl/RoleManagerImplTest.java
+++ b/server/src/test/java/org/apache/cloudstack/acl/RoleManagerImplTest.java
@@ -166,7 +166,7 @@
         String roleName = "roleName";
         List<Role> roles = new ArrayList<>();
         Pair<ArrayList<RoleVO>, Integer> toBeReturned = new Pair(roles, 0);
-        Mockito.doReturn(toBeReturned).when(roleDaoMock).findAllByName(roleName, null, null, null);
+        Mockito.doReturn(toBeReturned).when(roleDaoMock).findAllByName(roleName, null, null, null, false);
 
         roleManagerImpl.findRolesByName(roleName);
         Mockito.verify(roleManagerImpl).removeRootAdminRolesIfNeeded(roles);
@@ -239,7 +239,7 @@
 
         Assert.assertEquals(0, returnedRoles.size());
         Mockito.verify(accountManagerMock, Mockito.times(1)).isRootAdmin(Mockito.anyLong());
-        Mockito.verify(roleDaoMock, Mockito.times(0)).findAllByRoleType(Mockito.any(RoleType.class));
+        Mockito.verify(roleDaoMock, Mockito.times(0)).findAllByRoleType(Mockito.any(RoleType.class), Mockito.anyBoolean());
     }
 
     @Test
@@ -250,11 +250,11 @@
         List<Role> roles = new ArrayList<>();
         roles.add(Mockito.mock(Role.class));
         Pair<ArrayList<RoleVO>, Integer> toBeReturned = new Pair(roles, 1);
-        Mockito.doReturn(toBeReturned).when(roleDaoMock).findAllByRoleType(RoleType.Admin, null, null);
+        Mockito.doReturn(toBeReturned).when(roleDaoMock).findAllByRoleType(RoleType.Admin, null, null, true);
         List<Role> returnedRoles = roleManagerImpl.findRolesByType(RoleType.Admin);
 
         Assert.assertEquals(1, returnedRoles.size());
-        Mockito.verify(accountManagerMock, Mockito.times(1)).isRootAdmin(Mockito.anyLong());
+        Mockito.verify(accountManagerMock, Mockito.times(2)).isRootAdmin(Mockito.anyLong());
     }
 
     @Test
@@ -265,11 +265,11 @@
         List<Role> roles = new ArrayList<>();
         roles.add(Mockito.mock(Role.class));
         Pair<ArrayList<RoleVO>, Integer> toBeReturned = new Pair(roles, 1);
-        Mockito.doReturn(toBeReturned).when(roleDaoMock).findAllByRoleType(RoleType.User, null, null);
+        Mockito.doReturn(toBeReturned).when(roleDaoMock).findAllByRoleType(RoleType.User, null, null, true);
         List<Role> returnedRoles = roleManagerImpl.findRolesByType(RoleType.User);
 
         Assert.assertEquals(1, returnedRoles.size());
-        Mockito.verify(accountManagerMock, Mockito.times(0)).isRootAdmin(Mockito.anyLong());
+        Mockito.verify(accountManagerMock, Mockito.times(1)).isRootAdmin(Mockito.anyLong());
     }
 
     @Test
diff --git a/server/src/test/java/org/apache/cloudstack/backup/BackupManagerTest.java b/server/src/test/java/org/apache/cloudstack/backup/BackupManagerTest.java
index 077518c..ce95f4d 100644
--- a/server/src/test/java/org/apache/cloudstack/backup/BackupManagerTest.java
+++ b/server/src/test/java/org/apache/cloudstack/backup/BackupManagerTest.java
@@ -16,9 +16,19 @@
 // under the License.
 package org.apache.cloudstack.backup;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
 
+import com.cloud.storage.Volume;
+import com.cloud.storage.VolumeApiService;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineManager;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.command.admin.backup.UpdateBackupOfferingCmd;
 import org.apache.cloudstack.backup.dao.BackupOfferingDao;
@@ -33,6 +43,8 @@
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.utils.Pair;
 
+import java.util.Collections;
+
 public class BackupManagerTest {
     @Spy
     @InjectMocks
@@ -44,6 +56,15 @@
     @Mock
     BackupProvider backupProvider;
 
+    @Mock
+    VirtualMachineManager virtualMachineManager;
+
+    @Mock
+    VolumeApiService volumeApiService;
+
+    @Mock
+    VolumeDao volumeDao;
+
     private String[] hostPossibleValues = {"127.0.0.1", "hostname"};
     private String[] datastoresPossibleValues = {"e9804933-8609-4de3-bccc-6278072a496c", "datastore-name"};
 
@@ -189,4 +210,50 @@
         Mockito.verify(backupProvider, times(4)).restoreBackedUpVolume(Mockito.any(), Mockito.anyString(),
                 Mockito.anyString(), Mockito.anyString());
     }
+
+    @Test
+    public void tryRestoreVMTestRestoreSucceeded() throws NoTransitionException {
+        BackupOffering offering = Mockito.mock(BackupOffering.class);
+        VolumeVO volumeVO = Mockito.mock(VolumeVO.class);
+        VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
+        BackupVO backup = Mockito.mock(BackupVO.class);
+
+        Mockito.when(volumeDao.findIncludingRemovedByInstanceAndType(1L, null)).thenReturn(Collections.singletonList(volumeVO));
+        Mockito.when(virtualMachineManager.stateTransitTo(Mockito.eq(vm), Mockito.eq(VirtualMachine.Event.RestoringRequested), Mockito.any())).thenReturn(true);
+        Mockito.when(volumeApiService.stateTransitTo(Mockito.eq(volumeVO), Mockito.eq(Volume.Event.RestoreRequested))).thenReturn(true);
+
+
+
+        Mockito.when(vm.getId()).thenReturn(1L);
+        Mockito.when(offering.getProvider()).thenReturn("veeam");
+        Mockito.doReturn(backupProvider).when(backupManager).getBackupProvider("veeam");
+        Mockito.when(backupProvider.restoreVMFromBackup(vm, backup)).thenReturn(true);
+
+        backupManager.tryRestoreVM(backup, vm, offering, "Nothing to write here.");
+    }
+
+    @Test
+    public void tryRestoreVMTestRestoreFails() throws NoTransitionException {
+        BackupOffering offering = Mockito.mock(BackupOffering.class);
+        VolumeVO volumeVO = Mockito.mock(VolumeVO.class);
+        VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
+        BackupVO backup = Mockito.mock(BackupVO.class);
+
+        Mockito.when(volumeDao.findIncludingRemovedByInstanceAndType(1L, null)).thenReturn(Collections.singletonList(volumeVO));
+        Mockito.when(virtualMachineManager.stateTransitTo(Mockito.eq(vm), Mockito.eq(VirtualMachine.Event.RestoringRequested), Mockito.any())).thenReturn(true);
+        Mockito.when(volumeApiService.stateTransitTo(Mockito.eq(volumeVO), Mockito.eq(Volume.Event.RestoreRequested))).thenReturn(true);
+        Mockito.when(virtualMachineManager.stateTransitTo(Mockito.eq(vm), Mockito.eq(VirtualMachine.Event.RestoringFailed), Mockito.any())).thenReturn(true);
+        Mockito.when(volumeApiService.stateTransitTo(Mockito.eq(volumeVO), Mockito.eq(Volume.Event.RestoreFailed))).thenReturn(true);
+
+        Mockito.when(vm.getId()).thenReturn(1L);
+        Mockito.when(offering.getProvider()).thenReturn("veeam");
+        Mockito.doReturn(backupProvider).when(backupManager).getBackupProvider("veeam");
+        Mockito.when(backupProvider.restoreVMFromBackup(vm, backup)).thenReturn(false);
+        try {
+            backupManager.tryRestoreVM(backup, vm, offering, "Checking message error.");
+            fail("An exception is needed.");
+        } catch (CloudRuntimeException e) {
+            assertEquals("Error restoring VM from backup [Checking message error.].", e.getMessage());
+        }
+    }
 }
diff --git a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java
index 72bd7bb..a37b3af 100644
--- a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java
+++ b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java
@@ -249,5 +249,4 @@
         // System.out.println("Creating Vpc Network Offering");
         assertNotNull("Vpc Isolated network offering with Vpc and Netscaler provider ", off);
     }
-
 }
diff --git a/server/src/test/java/org/apache/cloudstack/vm/schedule/VMScheduleManagerImplTest.java b/server/src/test/java/org/apache/cloudstack/vm/schedule/VMScheduleManagerImplTest.java
new file mode 100644
index 0000000..3d21be5
--- /dev/null
+++ b/server/src/test/java/org/apache/cloudstack/vm/schedule/VMScheduleManagerImplTest.java
@@ -0,0 +1,274 @@
+/*
+ * 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.vm.schedule;
+
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.User;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.vm.UserVmManager;
+import com.cloud.vm.VirtualMachine;
+import org.apache.cloudstack.api.command.user.vm.CreateVMScheduleCmd;
+import org.apache.cloudstack.api.command.user.vm.DeleteVMScheduleCmd;
+import org.apache.cloudstack.api.command.user.vm.ListVMScheduleCmd;
+import org.apache.cloudstack.api.command.user.vm.UpdateVMScheduleCmd;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.VMScheduleResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.vm.schedule.dao.VMScheduleDao;
+import org.apache.commons.lang.time.DateUtils;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+import java.util.UUID;
+
+import static org.junit.Assert.assertNotNull;
+
+public class VMScheduleManagerImplTest {
+
+    @Spy
+    @InjectMocks
+    VMScheduleManagerImpl vmScheduleManager = new VMScheduleManagerImpl();
+
+    @Mock
+    VMScheduleDao vmScheduleDao;
+
+    @Mock
+    VMScheduler vmScheduler;
+
+    @Mock
+    UserVmManager userVmManager;
+
+    @Mock
+    AccountManager accountManager;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        Account callingAccount = Mockito.mock(Account.class);
+        User callingUser = Mockito.mock(User.class);
+        CallContext.register(callingUser, callingAccount);
+    }
+
+    private void validateResponse(VMScheduleResponse response, VMSchedule vmSchedule, VirtualMachine vm) {
+        assertNotNull(response);
+        Assert.assertEquals(ReflectionTestUtils.getField(response, "id"), vmSchedule.getUuid());
+        Assert.assertEquals(ReflectionTestUtils.getField(response, "vmId"), vm.getUuid());
+        Assert.assertEquals(ReflectionTestUtils.getField(response, "schedule"), vmSchedule.getSchedule());
+        Assert.assertEquals(ReflectionTestUtils.getField(response, "timeZone"), vmSchedule.getTimeZone());
+        Assert.assertEquals(ReflectionTestUtils.getField(response, "action"), vmSchedule.getAction());
+        Assert.assertEquals(ReflectionTestUtils.getField(response, "startDate"), vmSchedule.getStartDate());
+        Assert.assertEquals(ReflectionTestUtils.getField(response, "endDate"), vmSchedule.getEndDate());
+    }
+
+    @Test
+    public void createSchedule() {
+        UserVm vm = Mockito.mock(UserVm.class);
+        VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class);
+        CreateVMScheduleCmd cmd = Mockito.mock(CreateVMScheduleCmd.class);
+
+        Mockito.when(cmd.getVmId()).thenReturn(1L);
+        Mockito.when(cmd.getSchedule()).thenReturn("0 0 * * *");
+        Mockito.when(cmd.getTimeZone()).thenReturn("UTC");
+        Mockito.when(cmd.getAction()).thenReturn("start");
+        Mockito.when(cmd.getStartDate()).thenReturn(DateUtils.addDays(new Date(), 1));
+        Mockito.when(cmd.getEndDate()).thenReturn(DateUtils.addDays(new Date(), 2));
+        Mockito.when(vm.getUuid()).thenReturn(UUID.randomUUID().toString());
+        Mockito.when(vmScheduleDao.persist(Mockito.any(VMScheduleVO.class))).thenReturn(vmSchedule);
+        Mockito.when(userVmManager.getUserVm(Mockito.anyLong())).thenReturn(vm);
+        Mockito.doNothing().when(accountManager).checkAccess(Mockito.any(Account.class), Mockito.isNull(), Mockito.eq(false), Mockito.eq(vm));
+        VMScheduleResponse response = vmScheduleManager.createSchedule(cmd);
+        Mockito.verify(vmScheduleDao, Mockito.times(1)).persist(Mockito.any(VMScheduleVO.class));
+
+        validateResponse(response, vmSchedule, vm);
+    }
+
+    @Test
+    public void createResponse() {
+        VMSchedule vmSchedule = Mockito.mock(VMSchedule.class);
+        UserVm vm = Mockito.mock(UserVm.class);
+        Mockito.when(vmSchedule.getVmId()).thenReturn(1L);
+        Mockito.when(userVmManager.getUserVm(vmSchedule.getVmId())).thenReturn(vm);
+
+        VMScheduleResponse response = vmScheduleManager.createResponse(vmSchedule);
+        validateResponse(response, vmSchedule, vm);
+    }
+
+    @Test
+    public void listSchedule() {
+        UserVm vm = Mockito.mock(UserVm.class);
+        VMScheduleVO vmSchedule1 = Mockito.mock(VMScheduleVO.class);
+        VMScheduleVO vmSchedule2 = Mockito.mock(VMScheduleVO.class);
+        List<VMScheduleVO> vmScheduleList = new ArrayList<>();
+        vmScheduleList.add(vmSchedule1);
+        vmScheduleList.add(vmSchedule2);
+
+        Mockito.when(vm.getUuid()).thenReturn(UUID.randomUUID().toString());
+        Mockito.when(userVmManager.getUserVm(1L)).thenReturn(vm);
+        Mockito.when(
+                vmScheduleDao.searchAndCount(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(),
+                        Mockito.anyBoolean(), Mockito.anyLong(), Mockito.anyLong())
+        ).thenReturn(new Pair<>(vmScheduleList, vmScheduleList.size()));
+        Mockito.when(vmSchedule1.getVmId()).thenReturn(1L);
+        Mockito.when(vmSchedule2.getVmId()).thenReturn(1L);
+
+        ListVMScheduleCmd cmd = Mockito.mock(ListVMScheduleCmd.class);
+        Mockito.when(cmd.getVmId()).thenReturn(1L);
+
+        ListResponse<VMScheduleResponse> responseList = vmScheduleManager.listSchedule(cmd);
+        Mockito.verify(vmScheduleDao, Mockito.times(1)).searchAndCount(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(),
+                Mockito.anyBoolean(), Mockito.anyLong(), Mockito.anyLong());
+        assertNotNull(responseList);
+        Assert.assertEquals(2, (int) responseList.getCount());
+        Assert.assertEquals(2, responseList.getResponses().size());
+
+        for (int i = 0; i < responseList.getResponses().size(); i++) {
+            VMScheduleResponse response = responseList.getResponses().get(i);
+            VMScheduleVO vmSchedule = vmScheduleList.get(i);
+            validateResponse(response, vmSchedule, vm);
+        }
+    }
+
+    @Test
+    public void updateSchedule() {
+        VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class);
+        UpdateVMScheduleCmd cmd = Mockito.mock(UpdateVMScheduleCmd.class);
+        UserVm vm = Mockito.mock(UserVm.class);
+        Mockito.when(cmd.getId()).thenReturn(1L);
+        Mockito.when(cmd.getSchedule()).thenReturn("0 0 * * *");
+        Mockito.when(cmd.getTimeZone()).thenReturn("UTC");
+        Mockito.when(cmd.getStartDate()).thenReturn(DateUtils.addDays(new Date(), 1));
+        Mockito.when(cmd.getEndDate()).thenReturn(DateUtils.addDays(new Date(), 2));
+        Mockito.when(vmScheduleDao.findById(Mockito.anyLong())).thenReturn(vmSchedule);
+        Mockito.when(vmScheduleDao.update(Mockito.eq(cmd.getId()), Mockito.any(VMScheduleVO.class))).thenReturn(true);
+        Mockito.when(vmSchedule.getVmId()).thenReturn(1L);
+        Mockito.when(vmSchedule.getStartDate()).thenReturn(DateUtils.addDays(new Date(), 1));
+        Mockito.when(userVmManager.getUserVm(vmSchedule.getVmId())).thenReturn(vm);
+
+        VMScheduleResponse response = vmScheduleManager.updateSchedule(cmd);
+        Mockito.verify(vmScheduleDao, Mockito.times(1)).update(Mockito.eq(cmd.getId()), Mockito.any(VMScheduleVO.class));
+
+        validateResponse(response, vmSchedule, vm);
+    }
+
+    @Test
+    public void removeScheduleByVmId() {
+        UserVm vm = Mockito.mock(UserVm.class);
+        VMScheduleVO vmSchedule1 = Mockito.mock(VMScheduleVO.class);
+        VMScheduleVO vmSchedule2 = Mockito.mock(VMScheduleVO.class);
+        List<VMScheduleVO> vmScheduleList = new ArrayList<>();
+        vmScheduleList.add(vmSchedule1);
+        vmScheduleList.add(vmSchedule2);
+        SearchCriteria<VMScheduleVO> sc = Mockito.mock(SearchCriteria.class);
+
+        Mockito.when(vm.getId()).thenReturn(1L);
+        Mockito.when(vmScheduleDao.getSearchCriteriaForVMId(vm.getId())).thenReturn(sc);
+        Mockito.when(vmScheduleDao.search(sc, null)).thenReturn(vmScheduleList);
+        Mockito.when(vmSchedule1.getId()).thenReturn(1L);
+        Mockito.when(vmSchedule2.getId()).thenReturn(2L);
+        Mockito.when(vmScheduleDao.remove(sc)).thenReturn(2);
+
+        long rowsRemoved = vmScheduleManager.removeScheduleByVmId(vm.getId(), false);
+
+        Mockito.verify(vmScheduleDao, Mockito.times(1)).remove(sc);
+        Assert.assertEquals(2, rowsRemoved);
+    }
+
+    @Test
+    public void removeSchedule() {
+        VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class);
+        UserVm vm = Mockito.mock(UserVm.class);
+        DeleteVMScheduleCmd cmd = Mockito.mock(DeleteVMScheduleCmd.class);
+
+        Mockito.when(cmd.getId()).thenReturn(1L);
+        Mockito.when(cmd.getVmId()).thenReturn(1L);
+        Mockito.when(vmSchedule.getVmId()).thenReturn(1L);
+        Mockito.when(userVmManager.getUserVm(cmd.getVmId())).thenReturn(vm);
+        Mockito.when(vmScheduleDao.findById(Mockito.anyLong())).thenReturn(vmSchedule);
+        Mockito.when(vmScheduleDao.removeSchedulesForVmIdAndIds(Mockito.anyLong(), Mockito.anyList())).thenReturn(1L);
+
+        Long rowsRemoved = vmScheduleManager.removeSchedule(cmd);
+
+        Mockito.verify(vmScheduleDao, Mockito.times(1)).removeSchedulesForVmIdAndIds(Mockito.anyLong(), Mockito.anyList());
+        Assert.assertEquals(1L, (long) rowsRemoved);
+    }
+
+    @Test
+    public void validateStartDateEndDate() {
+        // Valid scenario 1
+        // Start date is before end date
+        Date startDate = DateUtils.addDays(new Date(), 1);
+        Date endDate = DateUtils.addDays(new Date(), 2);
+        vmScheduleManager.validateStartDateEndDate(startDate, endDate, TimeZone.getDefault());
+
+        // Valid Scenario 2
+        // Start date is before current date and end date is null
+        endDate = null;
+        vmScheduleManager.validateStartDateEndDate(startDate, endDate, TimeZone.getDefault());
+
+        // Invalid Scenario 2
+        // Start date is before current date
+        startDate = DateUtils.addDays(new Date(), -1);
+        try {
+            vmScheduleManager.validateStartDateEndDate(startDate, endDate, TimeZone.getDefault());
+            Assert.fail("Should have thrown InvalidParameterValueException");
+        } catch (InvalidParameterValueException e) {
+            Assert.assertTrue(e.getMessage().contains("Invalid value for start date. Start date") &&
+                    e.getMessage().contains("can't be before current time"));
+        }
+
+        // Invalid Scenario 2
+        // Start date is after end date
+        startDate = DateUtils.addDays(new Date(), 2);
+        endDate = DateUtils.addDays(new Date(), 1);
+        try {
+            vmScheduleManager.validateStartDateEndDate(startDate, endDate, TimeZone.getDefault());
+            Assert.fail("Should have thrown InvalidParameterValueException");
+        } catch (InvalidParameterValueException e) {
+            Assert.assertTrue(e.getMessage().contains("Invalid value for end date. End date") &&
+                    e.getMessage().contains("can't be before start date"));
+        }
+
+        // Invalid Scenario 3
+        // End date is before current date
+        startDate = DateUtils.addDays(new Date(), 1);
+        endDate = DateUtils.addDays(new Date(), -1);
+        try {
+            vmScheduleManager.validateStartDateEndDate(startDate, endDate, TimeZone.getDefault());
+            Assert.fail("Should have thrown InvalidParameterValueException");
+        } catch (InvalidParameterValueException e) {
+            Assert.assertTrue(e.getMessage().contains("Invalid value for end date. End date") &&
+                    e.getMessage().contains("can't be before current time"));
+        }
+    }
+}
diff --git a/server/src/test/java/org/apache/cloudstack/vm/schedule/VMSchedulerImplTest.java b/server/src/test/java/org/apache/cloudstack/vm/schedule/VMSchedulerImplTest.java
new file mode 100644
index 0000000..bb622f5
--- /dev/null
+++ b/server/src/test/java/org/apache/cloudstack/vm/schedule/VMSchedulerImplTest.java
@@ -0,0 +1,397 @@
+/*
+ * 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.vm.schedule;
+
+import com.cloud.event.ActionEventUtils;
+import com.cloud.user.User;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.component.ComponentContext;
+import com.cloud.vm.UserVmManager;
+import com.cloud.vm.VirtualMachine;
+import org.apache.cloudstack.api.ApiCommandResourceType;
+import org.apache.cloudstack.api.command.user.vm.RebootVMCmd;
+import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
+import org.apache.cloudstack.api.command.user.vm.StopVMCmd;
+import org.apache.cloudstack.framework.jobs.AsyncJobDispatcher;
+import org.apache.cloudstack.framework.jobs.AsyncJobManager;
+import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
+import org.apache.cloudstack.vm.schedule.dao.VMScheduleDao;
+import org.apache.cloudstack.vm.schedule.dao.VMScheduledJobDao;
+import org.apache.commons.lang.time.DateUtils;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import javax.persistence.EntityExistsException;
+import java.time.ZonedDateTime;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+import static org.mockito.Mockito.when;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ActionEventUtils.class, ComponentContext.class})
+public class VMSchedulerImplTest {
+    @Spy
+    @InjectMocks
+    private VMSchedulerImpl vmScheduler = new VMSchedulerImpl();
+
+    @Mock
+    private UserVmManager userVmManager;
+
+    @Mock
+    private VMScheduleDao vmScheduleDao;
+
+    @Mock
+    private VMScheduledJobDao vmScheduledJobDao;
+
+    @Mock
+    private EnumMap<VMSchedule.Action, String> actionEventMap;
+
+    @Mock
+    private AsyncJobManager asyncJobManager;
+
+    @Mock
+    private AsyncJobDispatcher asyncJobDispatcher;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        PowerMockito.mockStatic(ActionEventUtils.class);
+        Mockito.when(ActionEventUtils.onScheduledActionEvent(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString(),
+                Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyLong())).thenReturn(1L);
+        Mockito.when(ActionEventUtils.onCompletedActionEvent(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(),
+                Mockito.anyString(), Mockito.anyBoolean(),
+                Mockito.anyString(),
+                Mockito.anyLong(), Mockito.anyString(), Mockito.anyLong())).thenReturn(1L);
+    }
+
+    private void prepareMocksForProcessJob(VirtualMachine vm, VMScheduledJob vmScheduledJob, VirtualMachine.State vmState, VMSchedule.Action action, Long executeJobReturnValue) {
+        Mockito.when(vm.getState()).thenReturn(vmState);
+        Mockito.when(vmScheduledJob.getAction()).thenReturn(action);
+
+        if (executeJobReturnValue != null) {
+            Mockito.doReturn(executeJobReturnValue).when(vmScheduler).executeStartVMJob(Mockito.any(VirtualMachine.class), Mockito.anyLong());
+            Mockito.doReturn(executeJobReturnValue).when(vmScheduler).executeStopVMJob(Mockito.any(VirtualMachine.class), Mockito.anyBoolean(), Mockito.anyLong());
+            Mockito.doReturn(executeJobReturnValue).when(vmScheduler).executeRebootVMJob(Mockito.any(VirtualMachine.class), Mockito.anyBoolean(), Mockito.anyLong());
+        }
+    }
+
+    private void executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State state, VMSchedule.Action action) {
+        VMScheduledJob vmScheduledJob = Mockito.mock(VMScheduledJob.class);
+        VirtualMachine vm = Mockito.mock(VirtualMachine.class);
+
+        Long expectedValue = 1L;
+
+        prepareMocksForProcessJob(vm, vmScheduledJob, state, action, expectedValue);
+
+        Long jobId = vmScheduler.processJob(vmScheduledJob, vm);
+
+        PowerMockito.verifyStatic(ActionEventUtils.class);
+        ActionEventUtils.onCompletedActionEvent(User.UID_SYSTEM, vm.getAccountId(), null,
+                actionEventMap.get(action), true,
+                String.format("Executing action (%s) for VM Id:%s", vmScheduledJob.getAction(), vm.getUuid()),
+                vm.getId(), ApiCommandResourceType.VirtualMachine.toString(), 0);
+        Assert.assertEquals(expectedValue, jobId);
+    }
+
+    @Test
+    public void testProcessJobRunning() {
+        executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Running, VMSchedule.Action.STOP);
+        executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Running, VMSchedule.Action.FORCE_STOP);
+        executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Running, VMSchedule.Action.REBOOT);
+        executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Running, VMSchedule.Action.FORCE_REBOOT);
+        executeProcessJobWithVMStateAndActionNonSkipped(VirtualMachine.State.Stopped, VMSchedule.Action.START);
+    }
+
+    @Test
+    public void testProcessJobInvalidAction() {
+        VMScheduledJob vmScheduledJob = Mockito.mock(VMScheduledJob.class);
+        VirtualMachine vm = Mockito.mock(VirtualMachine.class);
+
+        prepareMocksForProcessJob(vm, vmScheduledJob, VirtualMachine.State.Running, VMSchedule.Action.START, null);
+
+        Long jobId = vmScheduler.processJob(vmScheduledJob, vm);
+
+        Assert.assertNull(jobId);
+    }
+
+    @Test
+    public void testProcessJobVMInInvalidState() {
+        VMScheduledJob vmScheduledJob = Mockito.mock(VMScheduledJob.class);
+        VirtualMachine vm = Mockito.mock(VirtualMachine.class);
+
+        prepareMocksForProcessJob(vm, vmScheduledJob, VirtualMachine.State.Unknown, VMSchedule.Action.START, null);
+
+        Long jobId = vmScheduler.processJob(vmScheduledJob, vm);
+
+        Assert.assertNull(jobId);
+    }
+
+    @Test
+    public void testScheduleNextJobScheduleScheduleExists() {
+        Date now = DateUtils.setSeconds(new Date(), 0);
+        Date startDate = DateUtils.addDays(now, 1);
+        Date expectedScheduledTime = DateUtils.round(DateUtils.addMinutes(startDate, 1), Calendar.MINUTE);
+        UserVm vm = Mockito.mock(UserVm.class);
+
+        VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class);
+        Mockito.when(vmSchedule.getEnabled()).thenReturn(true);
+        Mockito.when(vmSchedule.getSchedule()).thenReturn("* * * * *");
+        Mockito.when(vmSchedule.getTimeZoneId()).thenReturn(TimeZone.getTimeZone("UTC").toZoneId());
+        Mockito.when(vmSchedule.getStartDate()).thenReturn(startDate);
+        Mockito.when(userVmManager.getUserVm(Mockito.anyLong())).thenReturn(vm);
+        Mockito.when(vmScheduledJobDao.persist(Mockito.any())).thenThrow(EntityExistsException.class);
+        Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule);
+
+        Assert.assertEquals(expectedScheduledTime, actualScheduledTime);
+    }
+
+    @Test
+    public void testScheduleNextJobScheduleFutureSchedule() {
+        Date now = DateUtils.setSeconds(new Date(), 0);
+        Date startDate = DateUtils.addDays(now, 1);
+        Date expectedScheduledTime = DateUtils.round(DateUtils.addMinutes(startDate, 1), Calendar.MINUTE);
+        UserVm vm = Mockito.mock(UserVm.class);
+
+        VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class);
+        Mockito.when(vmSchedule.getEnabled()).thenReturn(true);
+        Mockito.when(vmSchedule.getSchedule()).thenReturn("* * * * *");
+        Mockito.when(vmSchedule.getTimeZoneId()).thenReturn(TimeZone.getTimeZone("UTC").toZoneId());
+        Mockito.when(vmSchedule.getStartDate()).thenReturn(startDate);
+        Mockito.when(userVmManager.getUserVm(Mockito.anyLong())).thenReturn(vm);
+        Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule);
+
+        Assert.assertEquals(expectedScheduledTime, actualScheduledTime);
+    }
+
+    @Test
+    public void testScheduleNextJobScheduleFutureScheduleWithTimeZoneChecks() throws Exception {
+        // Ensure that Date vmSchedulerImpl.scheduleNextJob(VMScheduleVO vmSchedule) generates
+        // the correct scheduled time on basis of schedule(cron), start date
+        // and the timezone of the user. The system running the test can have any timezone.
+        String cron = "30 5 * * *";
+
+        Date now = DateUtils.setSeconds(new Date(), 0);
+        Date startDate = DateUtils.addDays(now, 1);
+
+        UserVm vm = Mockito.mock(UserVm.class);
+
+        VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class);
+        Mockito.when(vmSchedule.getEnabled()).thenReturn(true);
+        Mockito.when(vmSchedule.getSchedule()).thenReturn(cron);
+        Mockito.when(vmSchedule.getTimeZoneId()).thenReturn(TimeZone.getTimeZone("EST").toZoneId());
+        Mockito.when(vmSchedule.getStartDate()).thenReturn(startDate);
+        Mockito.when(userVmManager.getUserVm(Mockito.anyLong())).thenReturn(vm);
+
+        // The timezone of the user is EST. The cron expression is 30 5 * * *.
+        // The start date is 1 day from now. The expected scheduled time is 5:30 AM EST.
+        // The actual scheduled time is 10:30 AM UTC.
+        // The actual scheduled time is 5:30 AM EST.
+        ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(startDate.toInstant(), vmSchedule.getTimeZoneId());
+        zonedDateTime = zonedDateTime.withHour(5).withMinute(30).withSecond(0).withNano(0);
+        Date expectedScheduledTime = Date.from(zonedDateTime.toInstant());
+
+        if (expectedScheduledTime.before(startDate)) {
+            expectedScheduledTime = DateUtils.addDays(expectedScheduledTime, 1);
+        }
+
+        Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule);
+        Assert.assertEquals(expectedScheduledTime, actualScheduledTime);
+    }
+
+    @Test
+    public void testScheduleNextJobScheduleCurrentSchedule() {
+        Date now = DateUtils.setSeconds(new Date(), 0);
+        Date expectedScheduledTime = DateUtils.round(DateUtils.addMinutes(now, 1), Calendar.MINUTE);
+        UserVm vm = Mockito.mock(UserVm.class);
+
+        VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class);
+        Mockito.when(vmSchedule.getEnabled()).thenReturn(true);
+        Mockito.when(vmSchedule.getSchedule()).thenReturn("* * * * *");
+        Mockito.when(vmSchedule.getTimeZoneId()).thenReturn(TimeZone.getTimeZone("UTC").toZoneId());
+        Mockito.when(vmSchedule.getStartDate()).thenReturn(DateUtils.addDays(now, -1));
+        Mockito.when(userVmManager.getUserVm(Mockito.anyLong())).thenReturn(vm);
+        Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule);
+
+        Assert.assertEquals(expectedScheduledTime, actualScheduledTime);
+    }
+
+    @Test
+    public void testScheduleNextJobScheduleCurrentScheduleWithTimeZoneChecks() throws Exception {
+        // Ensure that Date vmSchedulerImpl.scheduleNextJob(VMScheduleVO vmSchedule) generates
+        // the correct scheduled time on basis of schedule(cron), start date
+        // and the timezone of the user. The system running the test can have any timezone.
+        String cron = "30 5 * * *";
+
+        Date now = DateUtils.setSeconds(new Date(), 0);
+
+        UserVm vm = Mockito.mock(UserVm.class);
+
+        VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class);
+        Mockito.when(vmSchedule.getEnabled()).thenReturn(true);
+        Mockito.when(vmSchedule.getSchedule()).thenReturn(cron);
+        Mockito.when(vmSchedule.getTimeZoneId()).thenReturn(TimeZone.getTimeZone("EST").toZoneId());
+        Mockito.when(vmSchedule.getStartDate()).thenReturn(DateUtils.addDays(now, -1));
+        Mockito.when(userVmManager.getUserVm(Mockito.anyLong())).thenReturn(vm);
+
+        // The timezone of the user is EST. The cron expression is 30 5 * * *.
+        // The start date is 1 day ago. The expected scheduled time is 5:30 AM EST.
+        // The actual scheduled time is 10:30 AM UTC.
+        // The actual scheduled time is 5:30 AM EST.
+        ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(now.toInstant(), vmSchedule.getTimeZoneId());
+        zonedDateTime = zonedDateTime.withHour(5).withMinute(30).withSecond(0).withNano(0);
+        Date expectedScheduledTime = Date.from(zonedDateTime.toInstant());
+
+        if (expectedScheduledTime.before(now)) {
+            expectedScheduledTime = DateUtils.addDays(expectedScheduledTime, 1);
+        }
+
+        Date actualScheduledTime = vmScheduler.scheduleNextJob(vmSchedule);
+        Assert.assertEquals(expectedScheduledTime, actualScheduledTime);
+    }
+
+    @Test
+    public void testScheduleNextJobScheduleExpired() {
+        VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class);
+        Mockito.when(vmSchedule.getEndDate()).thenReturn(DateUtils.addMinutes(new Date(), -5));
+        Mockito.when(vmSchedule.getEnabled()).thenReturn(true);
+        Date actualDate = vmScheduler.scheduleNextJob(vmSchedule);
+        Assert.assertNull(actualDate);
+    }
+
+    @Test
+    public void testScheduleNextJobScheduleDisabled() {
+        VMScheduleVO vmSchedule = Mockito.mock(VMScheduleVO.class);
+        Mockito.when(vmSchedule.getEnabled()).thenReturn(false);
+        Date actualDate = vmScheduler.scheduleNextJob(vmSchedule);
+        Assert.assertNull(actualDate);
+    }
+
+    @Test
+    public void testScheduleNextJobScheduleIdNotExists() {
+        long vmScheduleId = 1;
+        Mockito.when(vmScheduleDao.findById(vmScheduleId)).thenReturn(null);
+        Date actualDate = vmScheduler.scheduleNextJob(vmScheduleId);
+        Assert.assertNull(actualDate);
+    }
+
+    @Test
+    public void testScheduleNextJobScheduleIdExists() {
+        long vmScheduleId = 1;
+        VMScheduleVO vmScheduleVO = Mockito.mock(VMScheduleVO.class);
+        Date date = Mockito.mock(Date.class);
+        Mockito.when(vmScheduleDao.findById(vmScheduleId)).thenReturn(vmScheduleVO);
+        Mockito.doReturn(date).when(vmScheduler).scheduleNextJob(vmScheduleVO);
+        Date actualDate = vmScheduler.scheduleNextJob(vmScheduleId);
+        Assert.assertEquals(date, actualDate);
+    }
+
+    @Test
+    public void testExecuteJobs() {
+        /*
+         Test VMSchedulerImpl.executeJobs() method with a map of VMScheduledJob objects
+         covering all the possible scenarios
+         1. When the job is executed successfully
+         2. When the job is skipped (processJob returns null)
+        */
+
+        VMScheduledJobVO job1 = Mockito.mock(VMScheduledJobVO.class);
+        VMScheduledJobVO job2 = Mockito.mock(VMScheduledJobVO.class);
+
+        UserVm vm1 = Mockito.mock(UserVm.class);
+        UserVm vm2 = Mockito.mock(UserVm.class);
+
+        Mockito.when(job1.getVmId()).thenReturn(1L);
+        Mockito.when(job1.getScheduledTime()).thenReturn(new Date());
+        Mockito.when(job1.getAction()).thenReturn(VMSchedule.Action.START);
+        Mockito.when(job1.getVmScheduleId()).thenReturn(1L);
+        Mockito.when(job2.getVmId()).thenReturn(2L);
+        Mockito.when(job2.getScheduledTime()).thenReturn(new Date());
+        Mockito.when(job2.getAction()).thenReturn(VMSchedule.Action.STOP);
+        Mockito.when(job2.getVmScheduleId()).thenReturn(2L);
+
+        Mockito.when(userVmManager.getUserVm(1L)).thenReturn(vm1);
+        Mockito.when(userVmManager.getUserVm(2L)).thenReturn(vm2);
+
+        Mockito.doReturn(1L).when(vmScheduler).processJob(job1, vm1);
+        Mockito.doReturn(null).when(vmScheduler).processJob(job2, vm2);
+
+        Mockito.when(vmScheduledJobDao.acquireInLockTable(job1.getId())).thenReturn(job1);
+        Mockito.when(vmScheduledJobDao.acquireInLockTable(job2.getId())).thenReturn(job2);
+
+        Map<Long, VMScheduledJob> jobs = new HashMap<>();
+        jobs.put(1L, job1);
+        jobs.put(2L, job2);
+
+        ReflectionTestUtils.setField(vmScheduler, "currentTimestamp", new Date());
+
+        vmScheduler.executeJobs(jobs);
+
+        Mockito.verify(vmScheduler, Mockito.times(2)).processJob(Mockito.any(), Mockito.any());
+        Mockito.verify(vmScheduledJobDao, Mockito.times(2)).acquireInLockTable(Mockito.anyLong());
+    }
+
+    @Test
+    public void testExecuteStopVMJob() {
+        VirtualMachine vm = Mockito.mock(VirtualMachine.class);
+        Mockito.when(asyncJobManager.submitAsyncJob(Mockito.any(AsyncJobVO.class))).thenReturn(1L);
+        PowerMockito.mockStatic(ComponentContext.class);
+        when(ComponentContext.inject(StopVMCmd.class)).thenReturn(Mockito.mock(StopVMCmd.class));
+        long jobId = vmScheduler.executeStopVMJob(vm, false, 1L);
+
+        Assert.assertEquals(1L, jobId);
+    }
+
+    @Test
+    public void testExecuteRebootVMJob() {
+        VirtualMachine vm = Mockito.mock(VirtualMachine.class);
+        Mockito.when(asyncJobManager.submitAsyncJob(Mockito.any(AsyncJobVO.class))).thenReturn(1L);
+        PowerMockito.mockStatic(ComponentContext.class);
+        when(ComponentContext.inject(RebootVMCmd.class)).thenReturn(Mockito.mock(RebootVMCmd.class));
+        long jobId = vmScheduler.executeRebootVMJob(vm, false, 1L);
+
+        Assert.assertEquals(1L, jobId);
+    }
+
+    @Test
+    public void testExecuteStartVMJob() {
+        VirtualMachine vm = Mockito.mock(VirtualMachine.class);
+        Mockito.when(asyncJobManager.submitAsyncJob(Mockito.any(AsyncJobVO.class))).thenReturn(1L);
+        PowerMockito.mockStatic(ComponentContext.class);
+        when(ComponentContext.inject(StartVMCmd.class)).thenReturn(Mockito.mock(StartVMCmd.class));
+        long jobId = vmScheduler.executeStartVMJob(vm, 1L);
+
+        Assert.assertEquals(1L, jobId);
+    }
+}
diff --git a/server/src/test/resources/db.properties b/server/src/test/resources/db.properties
index 5eefc45..e1cc048 100644
--- a/server/src/test/resources/db.properties
+++ b/server/src/test/resources/db.properties
@@ -17,7 +17,7 @@
 

 

 # management server clustering parameters, change cluster.node.IP to the machine IP address

-# in which the management server is running
+# in which the management server is running

 cluster.node.IP=127.0.0.1

 cluster.servlet.port=9090

 

diff --git a/services/console-proxy/pom.xml b/services/console-proxy/pom.xml
index d561900..80a04e0 100644
--- a/services/console-proxy/pom.xml
+++ b/services/console-proxy/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-services</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <build>
diff --git a/services/console-proxy/rdpconsole/pom.xml b/services/console-proxy/rdpconsole/pom.xml
index a48bff2..d3d79d9 100644
--- a/services/console-proxy/rdpconsole/pom.xml
+++ b/services/console-proxy/rdpconsole/pom.xml
@@ -26,7 +26,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-service-console-proxy</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/services/console-proxy/rdpconsole/rdp-config.bat b/services/console-proxy/rdpconsole/rdp-config.bat
index f19b00d..614ee23 100755
--- a/services/console-proxy/rdpconsole/rdp-config.bat
+++ b/services/console-proxy/rdpconsole/rdp-config.bat
@@ -39,4 +39,3 @@
 rem Start TS service
 
 net start Termservice
-
diff --git a/services/console-proxy/rdpconsole/src/main/java/streamer/debug/MockServer.java b/services/console-proxy/rdpconsole/src/main/java/streamer/debug/MockServer.java
index c8f08b4..d4e48c6 100644
--- a/services/console-proxy/rdpconsole/src/main/java/streamer/debug/MockServer.java
+++ b/services/console-proxy/rdpconsole/src/main/java/streamer/debug/MockServer.java
@@ -198,8 +198,8 @@
         return shutdowned;
     }
 
-    public void waitUntilShutdowned(long timeToWaitMiliseconds) throws InterruptedException {
-        long deadline = System.currentTimeMillis() + timeToWaitMiliseconds;
+    public void waitUntilShutdowned(long timeToWaitMilliseconds) throws InterruptedException {
+        long deadline = System.currentTimeMillis() + timeToWaitMilliseconds;
         while (!shutdowned && System.currentTimeMillis() < deadline) {
             Thread.sleep(10);
         }
diff --git a/services/console-proxy/rdpconsole/src/test/doc/dev-rdp-config.bat b/services/console-proxy/rdpconsole/src/test/doc/dev-rdp-config.bat
index 4e19157..f5afc0c 100755
--- a/services/console-proxy/rdpconsole/src/test/doc/dev-rdp-config.bat
+++ b/services/console-proxy/rdpconsole/src/test/doc/dev-rdp-config.bat
@@ -136,4 +136,3 @@
 rem Don't forget to set Windows profile as active in Network Monitor, so SSL traffic branch will appear under
 rem svnchost.exe, so you will be able to decrypt it (don't forget to save and reopen captured traffic to file first).
 rem 
-
diff --git a/services/console-proxy/server/pom.xml b/services/console-proxy/server/pom.xml
index 491afc9..1e5217a 100644
--- a/services/console-proxy/server/pom.xml
+++ b/services/console-proxy/server/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-service-console-proxy</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/services/pom.xml b/services/pom.xml
index 9977949..5491892 100644
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <build>
diff --git a/services/secondary-storage/controller/pom.xml b/services/secondary-storage/controller/pom.xml
index a9f1caa..65d3a23 100644
--- a/services/secondary-storage/controller/pom.xml
+++ b/services/secondary-storage/controller/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-service-secondary-storage</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/services/secondary-storage/pom.xml b/services/secondary-storage/pom.xml
index ad6aa86..b086125 100644
--- a/services/secondary-storage/pom.xml
+++ b/services/secondary-storage/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-services</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <build>
diff --git a/services/secondary-storage/server/pom.xml b/services/secondary-storage/server/pom.xml
index 9c24622..ae0e147 100644
--- a/services/secondary-storage/server/pom.xml
+++ b/services/secondary-storage/server/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack-service-secondary-storage</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/services/secondary-storage/server/src/main/resources/META-INF/cloudstack/secondary-storage-discoverer/module.properties b/services/secondary-storage/server/src/main/resources/META-INF/cloudstack/secondary-storage-discoverer/module.properties
index 7ff8a3a..637b639 100644
--- a/services/secondary-storage/server/src/main/resources/META-INF/cloudstack/secondary-storage-discoverer/module.properties
+++ b/services/secondary-storage/server/src/main/resources/META-INF/cloudstack/secondary-storage-discoverer/module.properties
@@ -15,4 +15,4 @@
 # specific language governing permissions and limitations
 # under the License.
 name=secondary-storage-discoverer
-parent=discoverer
\ No newline at end of file
+parent=discoverer
diff --git a/setup/bindir/cloud-sysvmadm.in b/setup/bindir/cloud-sysvmadm.in
index e826dea..a5bb9b3 100755
--- a/setup/bindir/cloud-sysvmadm.in
+++ b/setup/bindir/cloud-sysvmadm.in
@@ -498,5 +498,3 @@
 then
       restart_vpcs
 fi
-
-
diff --git a/setup/db/221to222upgrade.sh b/setup/db/221to222upgrade.sh
index 8fb1e75..5113c51 100644
--- a/setup/db/221to222upgrade.sh
+++ b/setup/db/221to222upgrade.sh
@@ -46,5 +46,3 @@
 exit 1
 fi
 echo Finished upgrade for database: cloud_usage from 2.2.1 to 2.2.2
-
-
diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql
index a241d9a..a319dc3 100755
--- a/setup/db/create-schema.sql
+++ b/setup/db/create-schema.sql
@@ -2475,4 +2475,3 @@
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 SET foreign_key_checks = 1;
-
diff --git a/setup/db/index-20to21.sql b/setup/db/index-20to21.sql
index d259f79..43210e5 100644
--- a/setup/db/index-20to21.sql
+++ b/setup/db/index-20to21.sql
@@ -57,4 +57,3 @@
 
 -- drop foreign key constraits temporarily to allow data update in migration process
 ALTER TABLE `cloud`.`user_vm` DROP FOREIGN KEY `fk_user_vm__service_offering_id`;
-
diff --git a/setup/db/index-212to213.sql b/setup/db/index-212to213.sql
index d03b29a..348c513 100644
--- a/setup/db/index-212to213.sql
+++ b/setup/db/index-212to213.sql
@@ -17,4 +17,3 @@
 
 
 ALTER TABLE `cloud`.`user` DROP KEY `i_user__username__removed`;
-
diff --git a/setup/db/templates.sql b/setup/db/templates.sql
index ba51489..aa0bd1d 100755
--- a/setup/db/templates.sql
+++ b/setup/db/templates.sql
@@ -596,4 +596,3 @@
 INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ('KVM', 'DOS', 102);
 INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ('KVM', 'Other', 60);
 INSERT INTO `cloud`.`guest_os_hypervisor` (hypervisor_type, guest_os_name, guest_os_id) VALUES ('KVM', 'Other', 103);
-
diff --git a/systemvm/agent/certs/realhostip.key b/systemvm/agent/certs/realhostip.key
index 53bdc86..47031f4 100644
--- a/systemvm/agent/certs/realhostip.key
+++ b/systemvm/agent/certs/realhostip.key
@@ -21,4 +21,4 @@
 Vo1lAoGAb1gCoyBCzvi7sqFxm4V5oapnJeiQQJFjhoYWqGa26rQ+AvXXNuBcigIeDXNJPctSF0Uc
 p11KbbCgiruBbckvM1vGsk6Sx4leRk+IFHRpJktFUek4o0eUg0shOsyyvyet48Dfg0a8FvcxROs0
 gD+IYds5doiob/hcm1hnNB/3vk4=
------END PRIVATE KEY-----
\ No newline at end of file
+-----END PRIVATE KEY-----
diff --git a/systemvm/agent/js/jquery.js b/systemvm/agent/js/jquery.js
index b1ae21d..a0fb883 100644
--- a/systemvm/agent/js/jquery.js
+++ b/systemvm/agent/js/jquery.js
@@ -16,4 +16,4 @@
  *  Released under the MIT, BSD, and GPL Licenses.
  *  More information: http://sizzlejs.com/
  */
-(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML='   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})();
\ No newline at end of file
+(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML='   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})();
diff --git a/systemvm/agent/noVNC/app/locale/cs.json b/systemvm/agent/noVNC/app/locale/cs.json
index 589145e..eba5ee3 100644
--- a/systemvm/agent/noVNC/app/locale/cs.json
+++ b/systemvm/agent/noVNC/app/locale/cs.json
@@ -68,4 +68,4 @@
     "Password:": "Heslo",
     "Send Password": "Odeslat heslo",
     "Cancel": "Zrušit"
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/de.json b/systemvm/agent/noVNC/app/locale/de.json
index 62e7336..15099d7 100644
--- a/systemvm/agent/noVNC/app/locale/de.json
+++ b/systemvm/agent/noVNC/app/locale/de.json
@@ -66,4 +66,4 @@
     "Password:": "Passwort:",
     "Cancel": "Abbrechen",
     "Canvas not supported.": "Canvas nicht unterstützt."
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/el.json b/systemvm/agent/noVNC/app/locale/el.json
index f801251..19cdb58 100644
--- a/systemvm/agent/noVNC/app/locale/el.json
+++ b/systemvm/agent/noVNC/app/locale/el.json
@@ -66,4 +66,4 @@
     "Password:": "Κωδικός Πρόσβασης:",
     "Cancel": "Ακύρωση",
     "Canvas not supported.": "Δεν υποστηρίζεται το στοιχείο Canvas"
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/es.json b/systemvm/agent/noVNC/app/locale/es.json
index b9e663a..61365e2 100644
--- a/systemvm/agent/noVNC/app/locale/es.json
+++ b/systemvm/agent/noVNC/app/locale/es.json
@@ -65,4 +65,4 @@
     "Password:": "Contraseña:",
     "Cancel": "Cancelar",
     "Canvas not supported.": "Canvas no soportado."
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/fr.json b/systemvm/agent/noVNC/app/locale/fr.json
index 22531f7..51e4589 100644
--- a/systemvm/agent/noVNC/app/locale/fr.json
+++ b/systemvm/agent/noVNC/app/locale/fr.json
@@ -75,4 +75,4 @@
     "Password:": "Mot de passe :",
     "Send Credentials": "Envoyer les identifiants",
     "Cancel": "Annuler"
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/it.json b/systemvm/agent/noVNC/app/locale/it.json
index 6fd2570..552018d 100644
--- a/systemvm/agent/noVNC/app/locale/it.json
+++ b/systemvm/agent/noVNC/app/locale/it.json
@@ -69,4 +69,4 @@
     "Password:": "Password:",
     "Send Credentials": "Invia Credenziale",
     "Cancel": "Annulla"
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/ja.json b/systemvm/agent/noVNC/app/locale/ja.json
index 43fc5bf..e85edf9 100644
--- a/systemvm/agent/noVNC/app/locale/ja.json
+++ b/systemvm/agent/noVNC/app/locale/ja.json
@@ -69,4 +69,4 @@
     "Password:": "パスワード:",
     "Send Credentials": "資格情報を送信",
     "Cancel": "キャンセル"
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/ko.json b/systemvm/agent/noVNC/app/locale/ko.json
index e4ecddc..aa9c110 100644
--- a/systemvm/agent/noVNC/app/locale/ko.json
+++ b/systemvm/agent/noVNC/app/locale/ko.json
@@ -67,4 +67,4 @@
     "Password:": "비밀번호:",
     "Send Password": "비밀번호 전송",
     "Cancel": "취소"
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/nl.json b/systemvm/agent/noVNC/app/locale/nl.json
index 0cdcc92..1ad7564 100644
--- a/systemvm/agent/noVNC/app/locale/nl.json
+++ b/systemvm/agent/noVNC/app/locale/nl.json
@@ -70,4 +70,4 @@
     "Password:": "Wachtwoord:",
     "Send Password": "Verzend Wachtwoord:",
     "Cancel": "Annuleren"
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/pl.json b/systemvm/agent/noVNC/app/locale/pl.json
index 006ac7a..12a4656 100644
--- a/systemvm/agent/noVNC/app/locale/pl.json
+++ b/systemvm/agent/noVNC/app/locale/pl.json
@@ -66,4 +66,4 @@
     "Password:": "Hasło:",
     "Cancel": "Anuluj",
     "Canvas not supported.": "Element Canvas nie jest wspierany."
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/pt_BR.json b/systemvm/agent/noVNC/app/locale/pt_BR.json
index aa130f7..42b16b6 100644
--- a/systemvm/agent/noVNC/app/locale/pt_BR.json
+++ b/systemvm/agent/noVNC/app/locale/pt_BR.json
@@ -69,4 +69,4 @@
     "Password:": "Senha:",
     "Send Credentials": "Enviar credenciais",
     "Cancel": "Cancelar"
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/ru.json b/systemvm/agent/noVNC/app/locale/ru.json
index cab9739..72bde71 100644
--- a/systemvm/agent/noVNC/app/locale/ru.json
+++ b/systemvm/agent/noVNC/app/locale/ru.json
@@ -69,4 +69,4 @@
     "Password:": "Пароль:",
     "Send Credentials": "Передача Учетных Данных",
     "Cancel": "Выход"
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/sv.json b/systemvm/agent/noVNC/app/locale/sv.json
index 077ef42..91dff9e 100644
--- a/systemvm/agent/noVNC/app/locale/sv.json
+++ b/systemvm/agent/noVNC/app/locale/sv.json
@@ -77,4 +77,4 @@
     "Password:": "Lösenord:",
     "Send Credentials": "Skicka Användaruppgifter",
     "Cancel": "Avbryt"
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/tr.json b/systemvm/agent/noVNC/app/locale/tr.json
index 451c1b8..b92b416 100644
--- a/systemvm/agent/noVNC/app/locale/tr.json
+++ b/systemvm/agent/noVNC/app/locale/tr.json
@@ -66,4 +66,4 @@
     "Password:": "Parola:",
     "Cancel": "Vazgeç",
     "Canvas not supported.": "Tuval desteklenmiyor."
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/zh_CN.json b/systemvm/agent/noVNC/app/locale/zh_CN.json
index f0aea9a..ee73eba 100644
--- a/systemvm/agent/noVNC/app/locale/zh_CN.json
+++ b/systemvm/agent/noVNC/app/locale/zh_CN.json
@@ -66,4 +66,4 @@
     "Connect": "连接",
     "Password:": "密码:",
     "Cancel": "取消"
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/app/locale/zh_TW.json b/systemvm/agent/noVNC/app/locale/zh_TW.json
index 8ddf813..b0368ce 100644
--- a/systemvm/agent/noVNC/app/locale/zh_TW.json
+++ b/systemvm/agent/noVNC/app/locale/zh_TW.json
@@ -66,4 +66,4 @@
     "Connect": "連線",
     "Password:": "密碼:",
     "Cancel": "取消"
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/core/input/uskeysym.js b/systemvm/agent/noVNC/core/input/uskeysym.js
index 97c5ae4..7eda9a6 100644
--- a/systemvm/agent/noVNC/core/input/uskeysym.js
+++ b/systemvm/agent/noVNC/core/input/uskeysym.js
@@ -54,4 +54,4 @@
 
     ' ': 0x0020, /* U+0020 SPACE */
     '\n': 0xff0d
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/core/ra2.js b/systemvm/agent/noVNC/core/ra2.js
index 81a8a89..d038608 100644
--- a/systemvm/agent/noVNC/core/ra2.js
+++ b/systemvm/agent/noVNC/core/ra2.js
@@ -564,4 +564,4 @@
     set hasStarted(s) {
         this._hasStarted = s;
     }
-}
\ No newline at end of file
+}
diff --git a/systemvm/agent/noVNC/core/util/md5.js b/systemvm/agent/noVNC/core/util/md5.js
index 49762ef..3834916 100644
--- a/systemvm/agent/noVNC/core/util/md5.js
+++ b/systemvm/agent/noVNC/core/util/md5.js
@@ -76,4 +76,4 @@
 
 function rol(d, g) {
     return d << g | d >>> 32 - g;
-}
\ No newline at end of file
+}
diff --git a/systemvm/debian/etc/modprobe.d/pcspkr.conf b/systemvm/debian/etc/modprobe.d/pcspkr.conf
index 892b51f..433368f 100644
--- a/systemvm/debian/etc/modprobe.d/pcspkr.conf
+++ b/systemvm/debian/etc/modprobe.d/pcspkr.conf
@@ -14,4 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-blacklist pcspkr
\ No newline at end of file
+blacklist pcspkr
diff --git a/systemvm/debian/etc/systemd/system/hyperv-daemons.hv-fcopy-daemon.service b/systemvm/debian/etc/systemd/system/hyperv-daemons.hv-fcopy-daemon.service
index 12a0b63..c249a3a 100644
--- a/systemvm/debian/etc/systemd/system/hyperv-daemons.hv-fcopy-daemon.service
+++ b/systemvm/debian/etc/systemd/system/hyperv-daemons.hv-fcopy-daemon.service
@@ -6,4 +6,4 @@
 ExecStart=/usr/sbin/hv_fcopy_daemon -n
 
 [Install]
-WantedBy=multi-user.target
\ No newline at end of file
+WantedBy=multi-user.target
diff --git a/systemvm/debian/etc/systemd/system/hyperv-daemons.hv-kvp-daemon.service b/systemvm/debian/etc/systemd/system/hyperv-daemons.hv-kvp-daemon.service
index 534a25a..47e6834 100644
--- a/systemvm/debian/etc/systemd/system/hyperv-daemons.hv-kvp-daemon.service
+++ b/systemvm/debian/etc/systemd/system/hyperv-daemons.hv-kvp-daemon.service
@@ -5,4 +5,4 @@
 ExecStart=/usr/sbin/hv_kvp_daemon -n
 
 [Install]
-WantedBy=multi-user.target
\ No newline at end of file
+WantedBy=multi-user.target
diff --git a/systemvm/debian/opt/cloud/bin/getRouterAlerts.sh b/systemvm/debian/opt/cloud/bin/getRouterAlerts.sh
index 3f5f4a3..f48478e 100755
--- a/systemvm/debian/opt/cloud/bin/getRouterAlerts.sh
+++ b/systemvm/debian/opt/cloud/bin/getRouterAlerts.sh
@@ -52,4 +52,4 @@
        echo $alerts
 else
        echo "No Alerts"
-fi
\ No newline at end of file
+fi
diff --git a/systemvm/debian/opt/cloud/bin/patched.sh b/systemvm/debian/opt/cloud/bin/patched.sh
index bfe0f64..8ebc1af 100644
--- a/systemvm/debian/opt/cloud/bin/patched.sh
+++ b/systemvm/debian/opt/cloud/bin/patched.sh
@@ -16,4 +16,4 @@
 # specific language governing permissions and limitations
 # under the License.
 
-ls -lrt $1
\ No newline at end of file
+ls -lrt $1
diff --git a/systemvm/debian/opt/cloud/bin/setup/cksnode.sh b/systemvm/debian/opt/cloud/bin/setup/cksnode.sh
index 0b5df04..55bd4ea 100755
--- a/systemvm/debian/opt/cloud/bin/setup/cksnode.sh
+++ b/systemvm/debian/opt/cloud/bin/setup/cksnode.sh
@@ -71,4 +71,4 @@
     fi
 }
 
-setup_k8s_node
\ No newline at end of file
+setup_k8s_node
diff --git a/systemvm/debian/opt/cloud/bin/update_interface_config.sh b/systemvm/debian/opt/cloud/bin/update_interface_config.sh
index 4b1e96b..53d81f7 100644
--- a/systemvm/debian/opt/cloud/bin/update_interface_config.sh
+++ b/systemvm/debian/opt/cloud/bin/update_interface_config.sh
@@ -60,4 +60,4 @@
 fi
 
 echo "Interface with IP ${ip} not found"
-exit 1
\ No newline at end of file
+exit 1
diff --git a/systemvm/debian/opt/cloud/testdata/vmp0001.json b/systemvm/debian/opt/cloud/testdata/vmp0001.json
index 39ee78d..de3db3b 100644
--- a/systemvm/debian/opt/cloud/testdata/vmp0001.json
+++ b/systemvm/debian/opt/cloud/testdata/vmp0001.json
@@ -1 +1 @@
-{"ip_address":"172.16.1.102","password":"fnirq_cnffjbeq","type":"vmpassword"}
\ No newline at end of file
+{"ip_address":"172.16.1.102","password":"fnirq_cnffjbeq","type":"vmpassword"}
diff --git a/systemvm/pom.xml b/systemvm/pom.xml
index 6a185dd..f51505e 100644
--- a/systemvm/pom.xml
+++ b/systemvm/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <properties>
diff --git a/test/integration/broken/maint/test_zone_level_local_storage_setting.py b/test/integration/broken/maint/test_zone_level_local_storage_setting.py
index 19d3ed5..c8e1946 100644
--- a/test/integration/broken/maint/test_zone_level_local_storage_setting.py
+++ b/test/integration/broken/maint/test_zone_level_local_storage_setting.py
@@ -576,7 +576,7 @@
             ispersistent='true'
         )
 
-        # 3-list netwrok offerings
+        # 3-list network offerings
         list_nw_of = NetworkOffering.list(self.apiclient,
                                           id=self.network_offering.id)
         self.assertEqual(
diff --git a/test/integration/component/test_add_remove_network.py b/test/integration/component/test_add_remove_network.py
index 1562507..716ffa3 100644
--- a/test/integration/component/test_add_remove_network.py
+++ b/test/integration/component/test_add_remove_network.py
@@ -721,7 +721,7 @@
 
         self.debug("Created network %s" % network_2.name)
 
-        self.debug("Trying to add netwrok %s to VM %s, this should fail" %
+        self.debug("Trying to add network %s to VM %s, this should fail" %
                    (network_2.name, virtual_machine.id))
 
         with self.assertRaises(Exception) as e:
diff --git a/test/integration/component/test_escalations_instances.py b/test/integration/component/test_escalations_instances.py
index d2ff9b5..0004cce 100644
--- a/test/integration/component/test_escalations_instances.py
+++ b/test/integration/component/test_escalations_instances.py
@@ -4194,7 +4194,7 @@
             "Isolated Network Offerings with sourceNat enabled are not found"
         )
         """
-        Create Isolated netwrok with ip range
+        Create Isolated network with ip range
         """
         self.services["network"]["startip"] = "10.1.1.2"
         self.services["network"]["endip"] = "10.1.1.254"
@@ -4312,7 +4312,7 @@
             "Isolated Network Offerings with sourceNat enabled are not found"
         )
         """
-        Create Isolated netwrok with ip range
+        Create Isolated network with ip range
         """
         self.services["network"]["startip"] = "10.1.1.2"
         self.services["network"]["endip"] = "10.1.1.254"
diff --git a/test/integration/component/test_multiple_ips_per_nic.py b/test/integration/component/test_multiple_ips_per_nic.py
index 85cbd43..6c24ec1 100644
--- a/test/integration/component/test_multiple_ips_per_nic.py
+++ b/test/integration/component/test_multiple_ips_per_nic.py
@@ -340,7 +340,7 @@
                 self.apiclient, id=(
                     virtual_machine.nic[0].id + random_gen()))
             self.fail(
-                "Adding secondary IP with wrong NIC id succeeded, it shoud have failed")
+                "Adding secondary IP with wrong NIC id succeeded, it should have failed")
         except Exception as e:
             self.debug("Failed while adding secondary IP to wrong NIC")
 
diff --git a/test/integration/component/test_multiple_nic_support.py b/test/integration/component/test_multiple_nic_support.py
index d9ae681..cba1c4e 100644
--- a/test/integration/component/test_multiple_nic_support.py
+++ b/test/integration/component/test_multiple_nic_support.py
@@ -52,11 +52,11 @@
 import random
 import time
 
-class TestMulipleNicSupport(cloudstackTestCase):
+class TestMultipleNicSupport(cloudstackTestCase):
     @classmethod
     def setUpClass(cls):
         cls.testClient = super(
-            TestMulipleNicSupport,
+            TestMultipleNicSupport,
             cls).getClsTestClient()
         cls.apiclient = cls.testClient.getApiClient()
         cls.testdata = cls.testClient.getParsedTestDataConfig()
@@ -70,7 +70,7 @@
             cls.skip = True
             return
 
-        cls.logger = logging.getLogger("TestMulipleNicSupport")
+        cls.logger = logging.getLogger("TestMultipleNicSupport")
         cls.stream_handler = logging.StreamHandler()
         cls.logger.setLevel(logging.DEBUG)
         cls.logger.addHandler(cls.stream_handler)
@@ -255,7 +255,7 @@
 
     @classmethod
     def tearDownClass(self):
-        super(TestMulipleNicSupport, self).tearDownClass()
+        super(TestMultipleNicSupport, self).tearDownClass()
 
     def setUp(self):
         if self.skip:
@@ -265,7 +265,7 @@
         return
 
     def tearDown(self):
-        super(TestMulipleNicSupport, self).tearDown()
+        super(TestMultipleNicSupport, self).tearDown()
 
     def verify_network_rules(self, vm_id):
         virtual_machine = VirtualMachine.list(
diff --git a/test/integration/component/test_multiple_physical_network_creation.py b/test/integration/component/test_multiple_physical_network_creation.py
index 7f6117f..09127b9 100644
--- a/test/integration/component/test_multiple_physical_network_creation.py
+++ b/test/integration/component/test_multiple_physical_network_creation.py
@@ -39,11 +39,11 @@
 
 import logging
 
-class TestMulipleNetworkCreation(cloudstackTestCase):
+class TestMultipleNetworkCreation(cloudstackTestCase):
     @classmethod
     def setUpClass(cls):
         cls.testClient = super(
-            TestMulipleNetworkCreation,
+            TestMultipleNetworkCreation,
             cls).getClsTestClient()
         cls.apiclient = cls.testClient.getApiClient()
         cls.testdata = cls.testClient.getParsedTestDataConfig()
@@ -54,7 +54,7 @@
         cls.template = get_template(cls.apiclient, cls.zone.id)
         cls._cleanup = []
 
-        cls.logger = logging.getLogger("TestMulipleNetworkCreation")
+        cls.logger = logging.getLogger("TestMultipleNetworkCreation")
         cls.stream_handler = logging.StreamHandler()
         cls.logger.setLevel(logging.DEBUG)
         cls.logger.addHandler(cls.stream_handler)
@@ -127,7 +127,7 @@
                 allocationstate="Enabled"
             )
             # Cleanup resources used
-            super(TestMulipleNetworkCreation, cls).tearDownClass()
+            super(TestMultipleNetworkCreation, cls).tearDownClass()
         except Exception as e:
             raise Exception("Warning: Exception during cleanup : %s" % e)
         return
@@ -139,7 +139,7 @@
         return
 
     def tearDown(self):
-        super(TestMulipleNetworkCreation, self).tearDown()
+        super(TestMultipleNetworkCreation, self).tearDown()
 
     @attr(tags=["advanced"], required_hardware="false")
     def test_01_add_traffictype_for_untagged_networks(self):
diff --git a/test/integration/component/test_region_vpc.py b/test/integration/component/test_region_vpc.py
index 6866e48..0bfe112 100644
--- a/test/integration/component/test_region_vpc.py
+++ b/test/integration/component/test_region_vpc.py
@@ -490,7 +490,7 @@
                                   vpcid=vpc.id
                                   )
 
-        self.debug("Adding NetwrokACl rules to make PF and LB accessible")
+        self.debug("Adding NetworkACl rules to make PF and LB accessible")
         NetworkACL.create(
                 self.apiclient,
                 networkid=network.id,
diff --git a/test/integration/component/test_shared_networks.py b/test/integration/component/test_shared_networks.py
index c7e2656..be6d663 100644
--- a/test/integration/component/test_shared_networks.py
+++ b/test/integration/component/test_shared_networks.py
@@ -584,7 +584,7 @@
         #  6. No checks reqd
         #  7. a. listVirtualMachines should show both VMs in running state
         #     in the user account and the admin account
-        #     b. VM's IPs shoud be in the range of the shared network ip ranges
+        #     b. VM's IPs should be in the range of the shared network ip ranges
 
         # Create admin account
         self.admin_account = Account.create(
@@ -1974,7 +1974,7 @@
         #     enabled offering
         #  4. listPhysicalNetworks should return at least one active
         #     physical network
-        #  5. network creation shoud PASS
+        #  5. network creation should PASS
         #  6. network creation should FAIL since VLAN is already used by
         #     previously created network
 
diff --git a/test/integration/component/test_vpc.py b/test/integration/component/test_vpc.py
index 2587d78..5870769 100644
--- a/test/integration/component/test_vpc.py
+++ b/test/integration/component/test_vpc.py
@@ -1004,7 +1004,7 @@
             vpcid=vpc.id
         )
 
-        self.debug("Adding NetwrokACl rules to make NAT rule accessible")
+        self.debug("Adding NetworkACl rules to make NAT rule accessible")
         NetworkACL.create(
             self.apiclient,
             networkid=network_1.id,
@@ -1090,7 +1090,7 @@
             vm_3.name, vm_4.name))
         lb_rule.assign(self.apiclient, [vm_3, vm_4])
 
-        self.debug("Adding NetwrokACl rules to make PF and LB accessible")
+        self.debug("Adding NetworkACl rules to make PF and LB accessible")
         NetworkACL.create(
             self.apiclient,
             networkid=network_2.id,
@@ -1350,7 +1350,7 @@
             vpcid=vpc.id
         )
 
-        self.debug("Adding NetwrokACl rules to make NAT rule accessible")
+        self.debug("Adding NetworkACl rules to make NAT rule accessible")
         NetworkACL.create(
             self.apiclient,
             networkid=network_1.id,
@@ -1436,7 +1436,7 @@
             vm_3.name, vm_4.name))
         lb_rule.assign(self.apiclient, [vm_3, vm_4])
 
-        self.debug("Adding NetwrokACl rules to make PF and LB accessible")
+        self.debug("Adding NetworkACl rules to make PF and LB accessible")
         NetworkACL.create(
             self.apiclient,
             networkid=network_2.id,
diff --git a/test/integration/component/test_vpc_distributed_routing_offering.py b/test/integration/component/test_vpc_distributed_routing_offering.py
index baa8f9b..97fcb80 100644
--- a/test/integration/component/test_vpc_distributed_routing_offering.py
+++ b/test/integration/component/test_vpc_distributed_routing_offering.py
@@ -481,7 +481,7 @@
                                   vpcid=vpc.id
                                   )
 
-        self.debug("Adding NetwrokACl rules to make PF and LB accessible")
+        self.debug("Adding NetworkACl rules to make PF and LB accessible")
         NetworkACL.create(
                 self.apiclient,
                 networkid=network.id,
diff --git a/test/integration/component/test_vpc_network.py b/test/integration/component/test_vpc_network.py
index bf3f368..9a313e2 100644
--- a/test/integration/component/test_vpc_network.py
+++ b/test/integration/component/test_vpc_network.py
@@ -1864,7 +1864,7 @@
             "List public Ip for network should list the Ip addr"
         )
 
-        self.debug("Adding NetwrokACl rules to make PF and LB accessible")
+        self.debug("Adding NetworkACl rules to make PF and LB accessible")
         nw_acl = NetworkACL.create(
             self.apiclient,
             networkid=network_1.id,
@@ -2023,7 +2023,7 @@
         )
         self.cleanup.append(nat_rule)
 
-        self.debug("Adding NetwrokACl rules to make NAT rule accessible")
+        self.debug("Adding NetworkACl rules to make NAT rule accessible")
         nat_acl = NetworkACL.create(
             self.apiclient,
             networkid=network_1.id,
diff --git a/test/integration/component/test_vpc_offerings.py b/test/integration/component/test_vpc_offerings.py
index fbfb61f..25206cf 100644
--- a/test/integration/component/test_vpc_offerings.py
+++ b/test/integration/component/test_vpc_offerings.py
@@ -416,7 +416,7 @@
         )
         self.cleanup.append(nat_rule)
 
-        self.logger.debug("Adding NetwrokACl rules to make PF and LB accessible")
+        self.logger.debug("Adding NetworkACl rules to make PF and LB accessible")
         networkacl_1 = NetworkACL.create(
             self.apiclient,
             networkid=network.id,
diff --git a/test/integration/component/test_vpc_vms_deployment.py b/test/integration/component/test_vpc_vms_deployment.py
index ded3374..4d3f934 100644
--- a/test/integration/component/test_vpc_vms_deployment.py
+++ b/test/integration/component/test_vpc_vms_deployment.py
@@ -2046,7 +2046,7 @@
             self.fail("Failed to enable static NAT on IP: %s - %s" % (
                                         public_ip_4.ipaddress.ipaddress, e))
 
-        self.debug("Adding NetwrokACl rules to make NAT rule accessible with network %s" % network_1.id)
+        self.debug("Adding NetworkACl rules to make NAT rule accessible with network %s" % network_1.id)
         NetworkACL.create(
                                          self.apiclient,
                                          networkid=network_1.id,
diff --git a/test/integration/smoke/test_annotations.py b/test/integration/smoke/test_annotations.py
index 812b3dc..e527b96 100644
--- a/test/integration/smoke/test_annotations.py
+++ b/test/integration/smoke/test_annotations.py
@@ -83,6 +83,7 @@
         cls.host = list_hosts(cls.apiclient,
                                zoneid=cls.zone.id,
                                type='Routing')[0]
+        cls.mgmt_server = list_mgmt_servers(cls.apiclient)[0]
 
     @classmethod
     def tearDownClass(cls):
@@ -136,6 +137,12 @@
         self.assertEqual(self.added_annotations[-1].annotation.annotation, "annotation1")
 
     @attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
+    def test_01_add_ms_annotation(self):
+        """Testing the addAnnotations API ability to add an annoatation per management server"""
+        self.addAnnotation("mgmt-server-annotation1", self.mgmt_server.id, "MANAGEMENT_SERVER")
+        self.assertEqual(self.added_annotations[-1].annotation.annotation, "mgmt-server-annotation1")
+
+    @attr(tags=["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"], required_hardware="false")
     def test_02_add_multiple_annotations(self):
         """Testing the addAnnotations API ability to add an annoatation per host
         when there are annotations already.
diff --git a/test/integration/smoke/test_guest_os.py b/test/integration/smoke/test_guest_os.py
new file mode 100644
index 0000000..01fe343
--- /dev/null
+++ b/test/integration/smoke/test_guest_os.py
@@ -0,0 +1,260 @@
+# 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.
+#All tests inherit from cloudstackTestCase
+import unittest
+
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.cloudstackAPI import listHosts
+from marvin.cloudstackException import CloudstackAPIException
+from marvin.lib.base import (VirtualMachine,
+                             Account,
+                             GuestOSCategory,
+                             GuestOS,
+                             GuestOsMapping,
+                             NetworkOffering,
+                             Network)
+from marvin.lib.common import get_test_template, get_zone, list_virtual_machines
+from marvin.lib.utils import (validateList, cleanup_resources)
+from nose.plugins.attrib import attr
+from marvin.codes import PASS,FAIL
+
+class Services:
+    def __init__(self):
+        self.services = {
+        }
+
+class TestGuestOS(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestGuestOS, cls)
+        cls.api_client = cls.testClient.getApiClient()
+        cls.services = Services().services
+
+        cls.hypervisor = cls.get_hypervisor_type()
+
+    @classmethod
+    def setUp(self):
+        self.apiclient = self.testClient.getApiClient()
+
+        #build cleanup list
+        self.cleanup = []
+
+    @classmethod
+    def tearDown(self):
+        try:
+            cleanup_resources(self.apiclient, self.cleanup)
+        except Exception as e:
+            self.debug("Warning! Exception in tearDown: %s" % e)
+
+    @classmethod
+    def get_hypervisor_type(cls):
+
+        """Return the hypervisor available in setup"""
+
+        cmd = listHosts.listHostsCmd()
+        cmd.type = 'Routing'
+        cmd.listall = True
+        hosts = cls.api_client.listHosts(cmd)
+        hosts_list_validation_result = validateList(hosts)
+        assert hosts_list_validation_result[0] == PASS, "host list validation failed"
+        return hosts_list_validation_result[1]
+
+
+    @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+    def test_CRUD_operations_guest_OS(self):
+        """Test add, list, update operations on guest OS
+            1. Add a guest OS
+            2. List the guest OS
+            3. Delete the added guest OS
+        """
+        list_os_categories = GuestOSCategory.list(self.apiclient, name="CentOS", listall=True)
+        self.assertNotEqual(
+            len(list_os_categories),
+            0,
+            "List OS categories was empty"
+        )
+        os_category = list_os_categories[0]
+
+        self.guestos1 = GuestOS.add(
+            self.apiclient,
+            osdisplayname="testCentOS",
+            oscategoryid=os_category.id
+        )
+        list_guestos = GuestOS.list(self.apiclient, id=self.guestos1.id, listall=True)
+        self.assertNotEqual(
+            len(list_guestos),
+            0,
+            "List guest OS was empty"
+        )
+        guestos = list_guestos[0]
+        self.assertEqual(
+            guestos.id,
+            self.guestos1.id,
+            "Guest os ids do not match"
+        )
+
+        GuestOS.remove(
+            self.apiclient,
+            id=self.guestos1.id
+        )
+
+    @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+    def test_CRUD_operations_guest_OS_mapping(self):
+        """Test add, list, update operations on guest OS mapping
+            1. Add a guest OS
+            2. Add a guest OS mapping
+            3. Delete the added guest OS and mappings
+        """
+        list_os_categories = GuestOSCategory.list(self.apiclient, name="CentOS", listall=True)
+        os_category = list_os_categories[0]
+        self.guestos1 = GuestOS.add(
+            self.apiclient,
+            osdisplayname="testCentOS",
+            oscategoryid=os_category.id
+        )
+
+        if self.hypervisor.hypervisor.lower() not in ["xenserver", "vmware"]:
+            raise unittest.SkipTest("OS name check with hypervisor is supported only on XenServer and VMware")
+
+        self.guestosmapping1 = GuestOsMapping.add(
+            self.apiclient,
+            ostypeid=self.guestos1.id,
+            hypervisor=self.hypervisor.hypervisor,
+            hypervisorversion=self.hypervisor.hypervisorversion,
+            osnameforhypervisor="testOSMappingName"
+        )
+
+        list_guestos_mapping = GuestOsMapping.list(self.apiclient, id=self.guestosmapping1.id, listall=True)
+        self.assertNotEqual(
+            len(list_guestos_mapping),
+            0,
+            "List guest OS mapping was empty"
+        )
+        guestosmapping = list_guestos_mapping[0]
+        self.assertEqual(
+            guestosmapping.id,
+            self.guestosmapping1.id,
+            "Guest os mapping ids do not match"
+        )
+
+        GuestOsMapping.remove(
+            self.apiclient,
+            id=self.guestosmapping1.id
+        )
+
+        GuestOS.remove(
+            self.apiclient,
+            id=self.guestos1.id
+        )
+
+    @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+    def test_guest_OS_mapping_check_with_hypervisor(self):
+        """Test add, list, update operations on guest OS mapping
+            1. Add a guest OS
+            2. Add a guest OS mapping with osmappingcheckenabled true
+            3. Delete the added guest OS and mappings
+        """
+        list_os_categories = GuestOSCategory.list(self.apiclient, name="CentOS", listall=True)
+        os_category = list_os_categories[0]
+        self.guestos1 = GuestOS.add(
+            self.apiclient,
+            osdisplayname="testOSname1",
+            oscategoryid=os_category.id
+        )
+
+        if self.hypervisor.hypervisor.lower() not in ["xenserver", "vmware"]:
+            raise unittest.SkipTest("OS name check with hypervisor is supported only on XenServer and VMware")
+
+        if self.hypervisor.hypervisor.lower() == "xenserver":
+            testosname="Debian Squeeze 6.0 (32-bit)"
+        else:
+            testosname="debian4_64Guest"
+
+        self.guestosmapping1 = GuestOsMapping.add(
+            self.apiclient,
+            ostypeid=self.guestos1.id,
+            hypervisor=self.hypervisor.hypervisor,
+            hypervisorversion=self.hypervisor.hypervisorversion,
+            osnameforhypervisor=testosname,
+            osmappingcheckenabled=True
+        )
+
+        list_guestos_mapping = GuestOsMapping.list(self.apiclient, id=self.guestosmapping1.id, listall=True)
+        self.assertNotEqual(
+            len(list_guestos_mapping),
+            0,
+            "List guest OS mapping was empty"
+        )
+        guestosmapping = list_guestos_mapping[0]
+        self.assertEqual(
+            guestosmapping.id,
+            self.guestosmapping1.id,
+            "Guest os mapping ids do not match"
+        )
+
+        GuestOsMapping.remove(
+            self.apiclient,
+            id=self.guestosmapping1.id
+        )
+
+        GuestOS.remove(
+            self.apiclient,
+            id=self.guestos1.id
+        )
+
+    @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False)
+    def test_guest_OS_mapping_check_with_hypervisor_failure(self):
+        """Test add, list, update operations on guest OS mapping
+            1. Add a guest OS
+            2. Add a guest OS mapping with osmappingcheckenabled true
+            3. Delete the added guest OS and mappings
+        """
+        list_os_categories = GuestOSCategory.list(self.apiclient, name="CentOS", listall=True)
+        os_category = list_os_categories[0]
+        self.guestos1 = GuestOS.add(
+            self.apiclient,
+            osdisplayname="testOSname2",
+            oscategoryid=os_category.id
+        )
+
+        if self.hypervisor.hypervisor.lower() not in ["xenserver", "vmware"]:
+            raise unittest.SkipTest("OS name check with hypervisor is supported only on XenServer and VMware")
+
+        testosname = "incorrectOSname"
+
+        try:
+            self.guestosmapping1 = GuestOsMapping.add(
+                self.apiclient,
+                ostypeid=self.guestos1.id,
+                hypervisor=self.hypervisor.hypervisor,
+                hypervisorversion=self.hypervisor.hypervisorversion,
+                osnameforhypervisor=testosname,
+                osmappingcheckenabled=True
+            )
+            GuestOsMapping.remove(
+                self.apiclient,
+                id=self.guestosmapping1.id
+            )
+            self.fail("Since os mapping name is wrong, this API should fail")
+        except CloudstackAPIException as e:
+            self.debug("Addition guest OS mapping failed as expected %s " % e)
+        GuestOS.remove(
+            self.apiclient,
+            id=self.guestos1.id
+        )
+        return
diff --git a/test/integration/smoke/test_host_control_state.py b/test/integration/smoke/test_host_control_state.py
index 809af7d..4b8409e 100644
--- a/test/integration/smoke/test_host_control_state.py
+++ b/test/integration/smoke/test_host_control_state.py
@@ -20,7 +20,7 @@
 Tests for host control state
 """
 
-from marvin.cloudstackAPI import updateHost
+from marvin.cloudstackAPI import (updateHost, updateConfiguration)
 from nose.plugins.attrib import attr
 from marvin.cloudstackTestCase import cloudstackTestCase
 from marvin.lib.common import (get_domain,
@@ -28,13 +28,18 @@
                                get_template,
                                list_hosts,
                                list_routers,
-                               list_ssvms)
+                               list_ssvms,
+                               list_clusters,
+                               list_hosts)
 from marvin.lib.base import (Account,
                              Domain,
                              Host,
                              ServiceOffering,
                              VirtualMachine)
 from marvin.sshClient import SshClient
+from marvin.lib.decoratorGenerators import skipTestIf
+from marvin.lib.utils import wait_until
+import logging
 import time
 
 
@@ -250,3 +255,220 @@
 
         self.enable_host(host_id)
         self.verify_router_host_control_state(router.id, "Enabled")
+
+
+class TestAutoEnableDisableHost(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.testClient = super(TestAutoEnableDisableHost, cls).getClsTestClient()
+        cls.apiclient = cls.testClient.getApiClient()
+        cls.services = cls.testClient.getParsedTestDataConfig()
+        # Get Zone, Domain and templates
+        cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
+        cls.hypervisor = cls.testClient.getHypervisorInfo()
+        cls.hostConfig = cls.config.__dict__["zones"][0].__dict__["pods"][0].__dict__["clusters"][0].__dict__["hosts"][0].__dict__
+        if cls.hypervisor.lower() not in ['kvm']:
+            cls.hypervisorNotSupported = True
+            return
+
+        cls.logger = logging.getLogger('TestAutoEnableDisableHost')
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestAutoEnableDisableHost, cls).tearDownClass()
+
+    def tearDown(self):
+        super(TestAutoEnableDisableHost, self).tearDown()
+
+    def get_ssh_client(self, ip, username, password, retries=10):
+        """ Setup ssh client connection and return connection """
+        try:
+            ssh_client = SshClient(ip, 22, username, password, retries)
+        except Exception as e:
+            raise unittest.SkipTest("Unable to create ssh connection: " % e)
+
+        self.assertIsNotNone(
+            ssh_client, "Failed to setup ssh connection to ip=%s" % ip)
+
+        return ssh_client
+
+    def wait_until_host_is_in_state(self, hostid, resourcestate, interval=3, retries=20):
+        def check_resource_state():
+            response = Host.list(
+                self.apiclient,
+                id=hostid
+            )
+            if isinstance(response, list):
+                if response[0].resourcestate == resourcestate:
+                    self.logger.debug('Host with id %s is in resource state = %s' % (hostid, resourcestate))
+                    return True, None
+                else:
+                    self.logger.debug("Waiting for host " + hostid +
+                                      " to reach state " + resourcestate +
+                                      ", with current state " + response[0].resourcestate)
+            return False, None
+
+        done, _ = wait_until(interval, retries, check_resource_state)
+        if not done:
+            raise Exception("Failed to wait for host %s to be on resource state %s" % (hostid, resourcestate))
+        return True
+
+    def update_config(self, enable_feature):
+        cmd = updateConfiguration.updateConfigurationCmd()
+        cmd.name = "enable.kvm.host.auto.enable.disable"
+        cmd.value = enable_feature
+
+        response = self.apiclient.updateConfiguration(cmd)
+        self.debug("updated the parameter %s with value %s" % (response.name, response.value))
+
+    def update_health_check_script(self, ip_address, username, password, exit_code):
+        health_check_script_path = "/etc/cloudstack/agent/healthcheck.sh"
+        health_check_agent_property = "agent.health.check.script.path"
+        agent_properties_file_path = "/etc/cloudstack/agent/agent.properties"
+
+        ssh_client = self.get_ssh_client(ip_address, username, password)
+        ssh_client.execute("echo 'exit %s' > %s" % (exit_code, health_check_script_path))
+        ssh_client.execute("chmod +x %s" % health_check_script_path)
+        ssh_client.execute("echo '%s=%s' >> %s" % (health_check_agent_property, health_check_script_path,
+                                                   agent_properties_file_path))
+        ssh_client.execute("service cloudstack-agent restart")
+
+    def remove_host_health_check(self, ip_address, username, password):
+        health_check_script_path = "/etc/cloudstack/agent/healthcheck.sh"
+        ssh_client = self.get_ssh_client(ip_address, username, password)
+        ssh_client.execute("rm -f %s" % health_check_script_path)
+
+    def select_host_for_health_checks(self):
+        clusters = list_clusters(
+            self.apiclient,
+            zoneid=self.zone.id
+        )
+        if not clusters:
+            return None
+
+        for cluster in clusters:
+            list_hosts_response = list_hosts(
+                self.apiclient,
+                clusterid=cluster.id,
+                type="Routing",
+                resourcestate="Enabled"
+            )
+            assert isinstance(list_hosts_response, list)
+            if not list_hosts_response or len(list_hosts_response) < 1:
+                continue
+            return list_hosts_response[0]
+        return None
+
+    def update_host_allocation_state(self, id, enable):
+        cmd = updateHost.updateHostCmd()
+        cmd.id = id
+        cmd.allocationstate = "Enable" if enable else "Disable"
+        response = self.apiclient.updateHost(cmd)
+        self.assertEqual(response.resourcestate, "Enabled" if enable else "Disabled")
+
+    @attr(tags=["basic", "advanced"], required_hardware="false")
+    @skipTestIf("hypervisorNotSupported")
+    def test_01_auto_enable_disable_kvm_host(self):
+        """Test to auto-enable and auto-disable a KVM host based on health check results
+
+        # Validate the following:
+        # 1. Enable the KVM Auto Enable/Disable Feature
+        # 2. Set a health check script that fails and observe the host is Disabled
+        # 3. Make the health check script succeed and observe the host is Enabled
+        """
+
+        selected_host = self.select_host_for_health_checks()
+        if not selected_host:
+            self.skipTest("Cannot find a KVM host to test the auto-enable-disable feature")
+
+        username = self.hostConfig["username"]
+        password = self.hostConfig["password"]
+
+        # Enable the Auto Enable/Disable Configuration
+        self.update_config("true")
+
+        # Set health check script for failure
+        self.update_health_check_script(selected_host.ipaddress, username, password, 1)
+        self.wait_until_host_is_in_state(selected_host.id, "Disabled", 5, 200)
+
+        # Set health check script for success
+        self.update_health_check_script(selected_host.ipaddress, username, password, 0)
+
+        self.wait_until_host_is_in_state(selected_host.id, "Enabled", 5, 200)
+
+    @attr(tags=["basic", "advanced"], required_hardware="false")
+    @skipTestIf("hypervisorNotSupported")
+    def test_02_disable_host_overrides_auto_enable_kvm_host(self):
+        """Test to override the auto-enabling of a KVM host by an administrator
+
+        # Validate the following:
+        # 1. Enable the KVM Auto Enable/Disable Feature
+        # 2. Set a health check script that succeeds and observe the host is Enabled
+        # 3. Make the host Disabled
+        # 4. Verify the host does not get auto-enabled after the previous step
+        """
+
+        selected_host = self.select_host_for_health_checks()
+        if not selected_host:
+            self.skipTest("Cannot find a KVM host to test the auto-enable-disable feature")
+
+        username = self.hostConfig["username"]
+        password = self.hostConfig["password"]
+
+        # Enable the Auto Enable/Disable Configuration
+        self.update_config("true")
+
+        # Set health check script for failure
+        self.update_health_check_script(selected_host.ipaddress, username, password, 0)
+        self.wait_until_host_is_in_state(selected_host.id, "Enabled", 5, 200)
+
+        # Manually disable the host
+        self.update_host_allocation_state(selected_host.id, False)
+
+        # Wait for more than the ping interval
+        time.sleep(70)
+
+        # Verify the host continues on Disabled state
+        self.wait_until_host_is_in_state(selected_host.id, "Disabled", 5, 200)
+
+        # Restore the host to Enabled state
+        self.remove_host_health_check(selected_host.ipaddress, username, password)
+        self.update_host_allocation_state(selected_host.id, True)
+
+    @attr(tags=["basic", "advanced"], required_hardware="false")
+    @skipTestIf("hypervisorNotSupported")
+    def test_03_enable_host_does_not_override_auto_disable_kvm_host(self):
+        """Test to override the auto-disabling of a KVM host by an administrator
+
+        # Validate the following:
+        # 1. Enable the KVM Auto Enable/Disable Feature
+        # 2. Set a health check script that fails and observe the host is Disabled
+        # 3. Make the host Enabled
+        # 4. Verify the host does get auto-disabled after the previous step
+        """
+
+        selected_host = self.select_host_for_health_checks()
+        if not selected_host:
+            self.skipTest("Cannot find a KVM host to test the auto-enable-disable feature")
+
+        username = self.hostConfig["username"]
+        password = self.hostConfig["password"]
+
+        # Enable the Auto Enable/Disable Configuration
+        self.update_config("true")
+
+        # Set health check script for failure
+        self.update_health_check_script(selected_host.ipaddress, username, password, 1)
+        self.wait_until_host_is_in_state(selected_host.id, "Disabled", 5, 200)
+
+        # Manually enable the host
+        self.update_host_allocation_state(selected_host.id, True)
+
+        # Verify the host goes back to Disabled state
+        self.wait_until_host_is_in_state(selected_host.id, "Disabled", 5, 200)
+
+        # Restore the host to Enabled state
+        self.remove_host_health_check(selected_host.ipaddress, username, password)
+        self.update_host_allocation_state(selected_host.id, True)
diff --git a/test/integration/smoke/test_kubernetes_clusters.py b/test/integration/smoke/test_kubernetes_clusters.py
index c227e7f..3b45347 100644
--- a/test/integration/smoke/test_kubernetes_clusters.py
+++ b/test/integration/smoke/test_kubernetes_clusters.py
@@ -33,7 +33,9 @@
                                   scaleKubernetesCluster,
                                   getKubernetesClusterConfig,
                                   destroyVirtualMachine,
-                                  deleteNetwork)
+                                  deleteNetwork,
+                                  addVirtualMachinesToKubernetesCluster,
+                                  removeVirtualMachinesFromKubernetesCluster)
 from marvin.cloudstackException import CloudstackAPIException
 from marvin.codes import PASS, FAILED
 from marvin.lib.base import (Template,
@@ -46,12 +48,14 @@
                              VpcOffering,
                              VPC,
                              NetworkACLList,
-                             NetworkACL)
+                             NetworkACL,
+                             VirtualMachine)
 from marvin.lib.utils import (cleanup_resources,
                               validateList,
                               random_gen)
 from marvin.lib.common import (get_zone,
-                               get_domain)
+                               get_domain,
+                               get_template)
 from marvin.sshClient import SshClient
 from nose.plugins.attrib import attr
 from marvin.lib.decoratorGenerators import skipTestIf
@@ -86,6 +90,7 @@
         cls._cleanup = []
         cls.kubernetes_version_ids = []
         cls.vpcAllowAllAclDetailsMap = {}
+        cls.initial_configuration_cks_enabled = None
 
         if cls.hypervisorNotSupported == False:
             cls.endpoint_url = Configurations.list(cls.apiclient, name="endpoint.url")[0].value
@@ -610,7 +615,82 @@
         k8s_cluster = None
         return
 
-    def createKubernetesCluster(self, name, version_id, size=1, control_nodes=1):
+    @attr(tags=["advanced", "smoke"], required_hardware="true")
+    def test_11_test_unmanaged_cluster_lifecycle(self):
+        """Test all operations on unmanaged Kubernetes cluster
+
+        # Validate the following:
+        # 1. createKubernetesCluster should return valid info for new cluster
+        # 2. The Cloud Database contains the valid information
+        # 3. stopKubernetesCluster doesn't work
+        # 4. startKubernetesCluster doesn't work
+        # 5. upgradeKubernetesCluster doesn't work
+        # 6. Adding & removing vm from cluster works
+        # 7. deleteKubernetesCluster should delete an existing HA Kubernetes cluster
+        """
+        cluster = self.createKubernetesCluster("test-unmanaged-cluster", None,
+                                               cluster_type="ExternalManaged")
+        self.verifyKubernetesClusterState(cluster, 'Running')
+        self.debug("Stopping unmanaged Kubernetes cluster with ID: %s" % cluster.id)
+        try:
+            self.stopKubernetesCluster(cluster.id)
+            self.fail("Should not be able to stop unmanaged cluster")
+        except Exception as e:
+            self.debug("Expected exception: %s" % e)
+
+        self.debug("Starting unmanaged Kubernetes cluster with ID: %s" % cluster.id)
+        try:
+            self.startKubernetesCluster(cluster.id)
+            self.fail("Should not be able to start unmanaged cluster")
+        except Exception as e:
+            self.debug("Expected exception: %s" % e)
+
+        self.debug("Upgrading unmanaged Kubernetes cluster with ID: %s" % cluster.id)
+        try:
+            self.upgradeKubernetesCluster(cluster.id, self.kubernetes_version_1_24_0.id)
+            self.fail("Should not be able to upgrade unmanaged cluster")
+        except Exception as e:
+            self.debug("Expected exception: %s" % e)
+
+        template = get_template(self.apiclient,
+                                    self.zone.id,
+                                    self.services["ostype"])
+
+        self.services["virtual_machine"]["template"] = template.id
+        virtualMachine = VirtualMachine.create(self.apiclient, self.services["virtual_machine"], zoneid=self.zone.id,
+                                                            accountid=self.account.name, domainid=self.account.domainid,
+                                                            serviceofferingid=self.cks_service_offering.id)
+        self.debug("Adding VM %s to unmanaged Kubernetes cluster with ID: %s" % (virtualMachine.id, cluster.id))
+        self.addVirtualMachinesToKubernetesCluster(cluster.id, [virtualMachine.id])
+        cluster = self.listKubernetesCluster(cluster.id)
+        self.assertEqual(virtualMachine.id, cluster.virtualmachines[0].id, "VM should be part of the kubernetes cluster")
+        self.assertEqual(1, len(cluster.virtualmachines), "Only one VM should be part of the kubernetes cluster")
+
+        self.debug("Removing VM %s from unmanaged Kubernetes cluster with ID: %s" % (virtualMachine.id, cluster.id))
+        self.removeVirtualMachinesFromKubernetesCluster(cluster.id, [virtualMachine.id])
+        cluster = self.listKubernetesCluster(cluster.id)
+        self.assertEqual(0, len(cluster.virtualmachines), "No VM should be part of the kubernetes cluster")
+
+        self.debug("Deleting unmanaged Kubernetes cluster with ID: %s" % cluster.id)
+        self.deleteKubernetesClusterAndVerify(cluster.id)
+        return
+
+    def addVirtualMachinesToKubernetesCluster(self, cluster_id, vm_list):
+        cmd = addVirtualMachinesToKubernetesCluster.addVirtualMachinesToKubernetesClusterCmd()
+        cmd.id = cluster_id
+        cmd.virtualmachineids = vm_list
+
+        return self.apiclient.addVirtualMachinesToKubernetesCluster(cmd)
+
+    def removeVirtualMachinesFromKubernetesCluster(self, cluster_id, vm_list):
+        cmd = removeVirtualMachinesFromKubernetesCluster.removeVirtualMachinesFromKubernetesClusterCmd()
+        cmd.id = cluster_id
+        cmd.virtualmachineids = vm_list
+
+        return self.apiclient.removeVirtualMachinesFromKubernetesCluster(cmd)
+
+
+    def createKubernetesCluster(self, name, version_id, size=1, control_nodes=1, cluster_type='CloudManaged'):
         createKubernetesClusterCmd = createKubernetesCluster.createKubernetesClusterCmd()
         createKubernetesClusterCmd.name = name
         createKubernetesClusterCmd.description = name + "-description"
@@ -622,11 +702,10 @@
         createKubernetesClusterCmd.noderootdisksize = 10
         createKubernetesClusterCmd.account = self.account.name
         createKubernetesClusterCmd.domainid = self.domain.id
+        createKubernetesClusterCmd.clustertype = cluster_type
         if self.default_network:
             createKubernetesClusterCmd.networkid = self.default_network.id
         clusterResponse = self.apiclient.createKubernetesCluster(createKubernetesClusterCmd)
-        if not clusterResponse:
-            self.cleanup.append(clusterResponse)
         return clusterResponse
 
     def startKubernetesCluster(self, cluster_id):
diff --git a/test/integration/smoke/test_network.py b/test/integration/smoke/test_network.py
index 0c37c08..56b434f 100644
--- a/test/integration/smoke/test_network.py
+++ b/test/integration/smoke/test_network.py
@@ -72,9 +72,6 @@
 
 class TestPublicIP(cloudstackTestCase):
 
-    def setUp(self):
-        self.apiclient = self.testClient.getApiClient()
-
     @classmethod
     def setUpClass(cls):
         testClient = super(TestPublicIP, cls).getClsTestClient()
@@ -85,6 +82,7 @@
         cls.domain = get_domain(cls.apiclient)
         cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
         cls.services['mode'] = cls.zone.networktype
+        cls._cleanup = []
         # Create Accounts & networks
         cls.account = Account.create(
             cls.apiclient,
@@ -92,18 +90,21 @@
             admin=True,
             domainid=cls.domain.id
         )
+        cls._cleanup.append(cls.account)
 
         cls.user = Account.create(
             cls.apiclient,
             cls.services["account"],
             domainid=cls.domain.id
         )
+        cls._cleanup.append(cls.user)
         cls.services["network"]["zoneid"] = cls.zone.id
 
         cls.network_offering = NetworkOffering.create(
             cls.apiclient,
             cls.services["network_offering"],
         )
+        cls._cleanup.append(cls.network_offering)
         # Enable Network offering
         cls.network_offering.update(cls.apiclient, state='Enabled')
 
@@ -114,17 +115,20 @@
             cls.account.name,
             cls.account.domainid
         )
+        cls._cleanup.append(cls.account_network)
         cls.user_network = Network.create(
             cls.apiclient,
             cls.services["network"],
             cls.user.name,
             cls.user.domainid
         )
+        cls._cleanup.append(cls.user_network)
 
         cls.service_offering = ServiceOffering.create(
             cls.apiclient,
             cls.services["service_offerings"]["tiny"],
         )
+        cls._cleanup.append(cls.service_offering)
 
         cls.hypervisor = testClient.getHypervisorInfo()
         cls.template = get_test_template(
@@ -146,6 +150,7 @@
             networkids=cls.account_network.id,
             serviceofferingid=cls.service_offering.id
         )
+        cls._cleanup.append(cls.account_vm)
 
         cls.user_vm = VirtualMachine.create(
             cls.apiclient,
@@ -156,6 +161,7 @@
             networkids=cls.user_network.id,
             serviceofferingid=cls.service_offering.id
         )
+        cls._cleanup.append(cls.user_vm)
 
         # Create Source NAT IP addresses
         PublicIPAddress.create(
@@ -170,25 +176,11 @@
             cls.zone.id,
             cls.user.domainid
         )
-        cls._cleanup = [
-            cls.account_vm,
-            cls.user_vm,
-            cls.account_network,
-            cls.user_network,
-            cls.account,
-            cls.user,
-            cls.network_offering
-        ]
         return
 
     @classmethod
     def tearDownClass(cls):
-        try:
-            # Cleanup resources used
-            cleanup_resources(cls.apiclient, cls._cleanup)
-        except Exception as e:
-            raise Exception("Warning: Exception during cleanup : %s" % e)
-        return
+        super(TestPublicIP, cls).tearDownClass()
 
     @attr(tags=["advanced", "advancedns", "smoke", "dvs"], required_hardware="false")
     def test_public_ip_admin_account(self):
diff --git a/test/integration/smoke/test_private_roles.py b/test/integration/smoke/test_private_roles.py
new file mode 100644
index 0000000..32d4883
--- /dev/null
+++ b/test/integration/smoke/test_private_roles.py
@@ -0,0 +1,275 @@
+# 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.
+
+from marvin.cloudstackAPI import *
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.base import Account, Role, User
+from marvin.lib.utils import cleanup_resources
+from nose.plugins.attrib import attr
+
+import random
+
+
+class TestData(object):
+    """Test data object that is required to create resources
+    """
+    def __init__(self):
+        self.testdata = {
+            "accountadmin": {
+                "email": "mtu@test.cloud",
+                "firstname": "Marvin",
+                "lastname": "TestAdminAccount",
+                "username": "TestAdminAccount",
+                "password": "password"
+            },
+            "accountdomainadmin": {
+                "email": "mtu@test.cloud",
+                "firstname": "Marvin",
+                "lastname": "TestDomainAdminAccount",
+                "username": "TestDomainAdminAccount",
+                "password": "password"
+            },
+            "accountroleuser": {
+                "email": "mtu@test.cloud",
+                "firstname": "Marvin",
+                "lastname": "TestUserAccount",
+                "username": "TestUserAccount",
+                "password": "password"
+            },
+            "roleadmin": {
+                "name": "MarvinFake Admin Role ",
+                "type": "Admin",
+                "description": "Fake Admin Role created by Marvin test"
+            },
+            "roleuser": {
+                "name": "MarvinFake User Role ",
+                "type": "User",
+                "description": "Fake User Role created by Marvin test",
+                "ispublic": False
+            },
+            "publicrole": {
+                "name": "MarvinFake Public Role ",
+                "type": "User",
+                "description": "Fake Public Role created by Marvin test"
+            },
+            "importrole": {
+                "name": "MarvinFake Import Role ",
+                "type": "User",
+                "description": "Fake Import User Role created by Marvin test",
+                "ispublic": True,
+                "rules": [{"rule":"list*", "permission":"allow","description":"Listing apis"},
+                           {"rule":"get*", "permission":"allow","description":"Get apis"},
+                           {"rule":"update*", "permission":"deny","description":"Update apis"}]
+            },
+            "roledomainadmin": {
+                "name": "MarvinFake DomainAdmin Role ",
+                "type": "DomainAdmin",
+                "description": "Fake Domain-Admin Role created by Marvin test",
+                "ispublic": False
+            },
+            "apiConfig": {
+                "listApis": "allow",
+                "listAccounts": "allow",
+                "listClusters": "deny",
+                "*VM*": "allow",
+                "*Host*": "deny"
+            }
+        }
+
+
+class TestPrivateRoles(cloudstackTestCase):
+    """Tests Visibility of private and public roles
+    """
+
+    def setUp(self):
+        self.apiclient = self.testClient.getApiClient()
+        self.testdata = TestData().testdata
+
+        self.testdata["roleadmin"]["name"] += self.getRandomString()
+        self.testdata["roledomainadmin"]["name"] += self.getRandomString()
+        self.testdata["roleuser"]["name"] += self.getRandomString()
+        self.cleanup = []
+
+        self.role_admin = Role.create(
+            self.apiclient,
+            self.testdata["roleadmin"]
+        )
+        self.cleanup.append(self.role_admin)
+
+        self.role_domain_admin = Role.create(
+            self.apiclient,
+            self.testdata["roledomainadmin"]
+        )
+        self.cleanup.append(self.role_domain_admin)
+
+        self.private_role = Role.create(
+            self.apiclient,
+            self.testdata["roleuser"]
+        )
+        self.cleanup.append(self.private_role)
+
+        self.account_admin = Account.create(
+            self.apiclient,
+            self.testdata["accountadmin"],
+            roleid=self.role_admin.id
+        )
+        self.cleanup.append(self.account_admin)
+
+        self.account_domain_admin = Account.create(
+            self.apiclient,
+            self.testdata["accountdomainadmin"],
+            roleid=self.role_domain_admin.id
+        )
+        self.cleanup.append(self.account_domain_admin)
+
+        self.admin_apiclient = self.testClient.getUserApiClient(
+            UserName=self.account_admin.name,
+            DomainName='ROOT',
+            type=1
+        )
+
+        self.domain_admin_apiclient = self.testClient.getUserApiClient(
+            UserName=self.account_domain_admin.name,
+            DomainName='ROOT',
+            type=2
+        )
+
+    def tearDown(self):
+        super(TestPrivateRoles, self).tearDown()
+
+    def getRandomString(self):
+        return "".join(random.choice("abcdefghijklmnopqrstuvwxyz0123456789") for _ in range(10))
+
+    def asserts_visibility_of_private_role(self, role_id):
+        list_roles_domain_admin = Role.list(self.domain_admin_apiclient, id=role_id)
+        self.assertEqual(
+            list_roles_domain_admin,
+            None,
+            "Domain Admins should not be able to list private roles"
+        )
+
+        list_roles_admin = Role.list(self.admin_apiclient, id=role_id)
+        self.assertNotEqual(
+            list_roles_admin,
+            None,
+            "Admins should be able to list private roles"
+        )
+
+    def asserts_visibility_of_public_role(self, role_id):
+        list_roles_domain_admin = Role.list(self.domain_admin_apiclient, id=role_id)
+        self.assertNotEqual(
+            list_roles_domain_admin,
+            None,
+            "Domain Admins should be able to list public roles"
+        )
+
+        list_roles_admin = Role.list(self.admin_apiclient, id=role_id)
+        self.assertNotEqual(
+            list_roles_admin,
+            None,
+            "Admins should be able to list public roles"
+        )
+
+    @attr(tags=['simulator', 'basic'], required_hardware=False)
+    def test_create_role(self):
+        """
+            1. Create a private role
+            2. Create a public role
+            3. Verify whether their visibility is as expected
+        """
+        self.testdata["roleuser"]["name"] += self.getRandomString()
+        self.testdata["publicrole"]["name"] += self.getRandomString()
+        private_role = Role.create(
+            self.apiclient,
+            self.testdata["roleuser"]
+        )
+        self.cleanup.append(self.private_role)
+        public_role = Role.create(
+            self.apiclient,
+            self.testdata["publicrole"]
+        )
+        self.cleanup.append(self.public_role)
+        self.asserts_visibility_of_private_role(private_role.id)
+        self.asserts_visibility_of_public_role(public_role.id)
+
+    @attr(tags=['simulator', 'basic'], required_hardware=False)
+    def test_update_role(self):
+        """
+            1. Create a public role
+            2. Check if its visibility is public
+            3. Update it to make it private
+            4. Verify if its visibility is private
+        """
+        self.testdata["publicrole"]["name"] += self.getRandomString()
+        role = Role.create(
+            self.apiclient,
+            self.testdata["publicrole"]
+        )
+        self.cleanup.append(role)
+        self.asserts_visibility_of_public_role(role.id)
+        role.update(self.apiclient, id=role.id, ispublic=False)
+        self.asserts_visibility_of_private_role(role.id)
+
+    @attr(tags=['simulator', 'basic'], required_hardware=False)
+    def test_import_role(self):
+        """
+            1. Import a public role
+            2. Import a private role
+            3. Verify their visibility
+        """
+        self.testdata["importrole"]["name"] += self.getRandomString()
+        imported_public_role = Role.importRole(
+            self.apiclient,
+            self.testdata["importrole"]
+        )
+        self.cleanup.append(imported_public_role)
+        self.testdata["importrole"]["name"] += self.getRandomString()
+        self.testdata["importrole"]["ispublic"] = False
+        imported_private_role = Role.importRole(
+            self.apiclient,
+            self.testdata["importrole"]
+        )
+        self.cleanup.append(imported_private_role)
+
+        self.asserts_visibility_of_public_role(imported_public_role.id)
+        self.asserts_visibility_of_private_role(imported_private_role.id)
+
+    @attr(tags=['simulator', 'basic'], required_hardware=False)
+    def test_login_private_role(self):
+        """
+            1. Crate a User account with a private role
+            2. Login with the created account
+            3. Verify that the login was successful
+        """
+        account_private_role = Account.create(
+            self.apiclient,
+            self.testdata["accountroleuser"],
+            roleid=self.private_role.id
+        )
+        self.cleanup.append(account_private_role)
+
+        response = User.login(
+            self.apiclient,
+            username=account_private_role.name,
+            password=self.testdata["accountroleuser"]["password"]
+        )
+
+        self.assertNotEqual(
+            response.sessionkey,
+            None,
+            "Accounts using private roles should be able to login."
+        )
diff --git a/test/integration/smoke/test_projects.py b/test/integration/smoke/test_projects.py
index 79d364f..f0696b4 100644
--- a/test/integration/smoke/test_projects.py
+++ b/test/integration/smoke/test_projects.py
@@ -1820,3 +1820,116 @@
                 "VM should be in Running state after project activation"
             )
         return
+
+class TestProjectWithNameDisplayTextAction(cloudstackTestCase):
+    @classmethod
+    def setUpClass(cls):
+        cls.testClient = super(
+            TestProjectWithNameDisplayTextAction,
+            cls).getClsTestClient()
+        cls.api_client = cls.testClient.getApiClient()
+        cls.services = Services().services
+        # Get Zone
+        cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+        cls.domain = get_domain(cls.api_client)
+        cls.services['mode'] = cls.zone.networktype
+        cls._cleanup = []
+
+        cls.account = Account.create(
+            cls.api_client,
+            cls.services["account"],
+            admin=True,
+            domainid=cls.domain.id
+        )
+        cls._cleanup.append(cls.account)
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestProjectWithNameDisplayTextAction, cls).tearDownClass()
+
+    def setUp(self):
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+
+    def tearDown(self):
+        super(TestProjectWithNameDisplayTextAction, self).tearDown()
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "sg",
+            "eip",
+            "advancedns",
+            "simulator"],
+        required_hardware="false")
+    def test_11_create_project_with_empty_displayText(self):
+        """ create Project with Empty DisplayText
+        """
+        # Validate the following
+        # 1. Create a project while giving empty displayText
+        # 2. Verify displayText takes content of Project name.
+
+        self.services["project"]["displaytext"] = ""
+
+        project = Project.create(
+            self.apiclient,
+            self.services["project"],
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        self.cleanup.append(project)
+
+        self.assertEqual(
+            project.displaytext,
+            project.name,
+            "displayText does not matches project name"
+        )
+        return
+
+    @attr(
+        tags=[
+            "advanced",
+            "basic",
+            "sg",
+            "eip",
+            "advancedns",
+            "simulator"],
+        required_hardware="false")
+    def test_12_update_project_name_display_text(self):
+        """ Create Project and update its name
+        """
+        # Validate the following
+        # 1. Create a project
+        # 2. Update project name and display text
+        # 2. Verify name and display text for the project are updated
+
+        project = Project.create(
+            self.apiclient,
+            self.services["project"],
+            account=self.account.name,
+            domainid=self.account.domainid
+        )
+        self.cleanup.append(project)
+
+        new_name = "NewName"
+        new_display_text = "NewDisplayText"
+        project.update(self.apiclient, name=new_name, displaytext=new_display_text)
+        updated_project = Project.list(
+            self.apiclient,
+            id=project.id,
+            listall=True
+        )[0]
+        self.assertEqual(
+            updated_project.name,
+            new_name,
+            "Project name not updated"
+        )
+        self.assertEqual(
+            updated_project.displaytext,
+            new_display_text,
+            "Project displaytext not updated"
+        )
+        return
diff --git a/test/integration/smoke/test_register_userdata.py b/test/integration/smoke/test_register_userdata.py
index bc38cd9..c89d08e 100644
--- a/test/integration/smoke/test_register_userdata.py
+++ b/test/integration/smoke/test_register_userdata.py
@@ -31,6 +31,8 @@
 from marvin.lib.utils import (validateList, cleanup_resources)
 from nose.plugins.attrib import attr
 from marvin.codes import PASS,FAIL
+import base64
+import email
 
 
 from marvin.lib.common import (get_domain, get_template)
@@ -589,21 +591,23 @@
             2. Link a userdata to template with override policy is append
             3. Deploy a VM with that template and also by passing another userdata id
             4. Since the override policy is append, userdata passed during VM deployment will be appended to template's
-            userdata and configured to VM. Verify the same by SSH into VM.
+            userdata and configured to VM as a multipart MIME userdata. Verify the same by SSH into VM.
         """
 
+        shellscript_userdata = str("#!/bin/bash\ndate > /provisioned")
         self.apiUserdata = UserData.register(
             self.apiclient,
             name="ApiUserdata",
-            userdata="QVBJdXNlcmRhdGE=", #APIuserdata
+            userdata=base64.encodebytes(shellscript_userdata.encode()).decode(),
             account=self.account.name,
             domainid=self.account.domainid
         )
 
+        cloudconfig_userdata = str("#cloud-config\npassword: atomic\nchpasswd: { expire: False }\nssh_pwauth: True")
         self.templateUserdata = UserData.register(
             self.apiclient,
             name="TemplateUserdata",
-            userdata="VGVtcGxhdGVVc2VyRGF0YQ==", #TemplateUserData
+            userdata=base64.encodebytes(cloudconfig_userdata.encode()).decode(),
             account=self.account.name,
             domainid=self.account.domainid
         )
@@ -700,10 +704,32 @@
         cmd = "curl http://%s/latest/user-data" % vr_ip
         res = ssh.execute(cmd)
         self.debug("Verifying userdata in the VR")
-        self.assertEqual(
-            str(res[0]),
-            "TemplateUserDataAPIuserdata",
-            "Failed to match userdata"
+        self.assertTrue(
+            res is not None and len(res) > 0,
+            "Resultant userdata is not valid"
+        )
+        msg = email.message_from_string('\n'.join(res))
+        self.assertTrue(
+            msg.is_multipart(),
+            "Failed to match multipart userdata"
+        )
+        shellscript_userdata_found = False
+        cloudconfig_userdata_found = False
+        for part in msg.get_payload():
+            content_type = part.get_content_type()
+            payload = part.get_payload(decode=True).decode()
+            if "shellscript" in content_type:
+                shellscript_userdata_found = shellscript_userdata == payload
+            elif "cloud-config" in content_type:
+                cloudconfig_userdata_found = cloudconfig_userdata == payload
+
+        self.assertTrue(
+            shellscript_userdata_found,
+            "Failed to find shellscript userdata in append result"
+        )
+        self.assertTrue(
+            cloudconfig_userdata_found,
+            "Failed to find cloud-config userdata in append result"
         )
 
     @attr(tags=['advanced', 'simulator', 'basic', 'sg', 'testnow'], required_hardware=True)
diff --git a/test/integration/smoke/test_safe_shutdown.py b/test/integration/smoke/test_safe_shutdown.py
new file mode 100644
index 0000000..d757bb6
--- /dev/null
+++ b/test/integration/smoke/test_safe_shutdown.py
@@ -0,0 +1,121 @@
+# 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.
+
+from nose.plugins.attrib import attr
+from marvin.cloudstackTestCase import *
+from marvin.cloudstackAPI import *
+from marvin.lib.utils import *
+from marvin.lib.base import *
+from marvin.lib.common import *
+
+class TestSafeShutdown(cloudstackTestCase):
+    """
+        Tests safely shutting down the Management Server
+    """
+
+    def setUp(self):
+        self.apiclient = self.testClient.getApiClient()
+        self.mgtSvrDetails = self.config.__dict__["mgtSvr"][0].__dict__
+        self.cleanup = []
+
+    def tearDown(self):
+        self.startServer()
+        super(TestSafeShutdown, self).tearDown()
+
+    def isServerShutdown(self):
+        sshClient = SshClient(
+            self.mgtSvrDetails["mgtSvrIp"],
+            22,
+            self.mgtSvrDetails["user"],
+            self.mgtSvrDetails["passwd"]
+        )
+
+        timeout = time.time() + 300
+        while time.time() < timeout:
+            command = "service cloudstack-management status | grep dead"
+            results = sshClient.execute(command)
+
+            if len(results) > 0 and "(dead)" in results[0] :
+                return
+            time.sleep(30)
+        return self.fail("Management server did shut down, failing")
+
+    def isManagementUp(self):
+        try:
+            self.apiclient.listInfrastructure(listInfrastructure.listInfrastructureCmd())
+            return True
+        except Exception:
+            return False
+
+    def startServer(self):
+        """Start management server"""
+
+        sshClient = SshClient(
+                    self.mgtSvrDetails["mgtSvrIp"],
+            22,
+            self.mgtSvrDetails["user"],
+            self.mgtSvrDetails["passwd"]
+        )
+
+        command = "service cloudstack-management start"
+        sshClient.execute(command)
+
+        #Waits for management to come up in 5 mins, when it's up it will continue
+        timeout = time.time() + 300
+        while time.time() < timeout:
+            if self.isManagementUp() is True: return
+            time.sleep(5)
+        return self.fail("Management server did not come up, failing")
+
+    def run_async_cmd(self) :
+        return Project.create(
+            self.apiclient,
+            {"name": "test", "displaytext": "test"}
+        )
+
+    @attr(tags=["advanced", "smoke"])
+    def test_01_prepare_and_cancel_shutdown(self):
+        try :
+            prepare_for_shutdown_cmd = prepareForShutdown.prepareForShutdownCmd()
+            prepare_for_shutdown_cmd.managementserverid = 1
+            self.apiclient.prepareForShutdown(prepare_for_shutdown_cmd)
+            try :
+                self.run_async_cmd()
+            except Exception as e:
+                self.debug("Prepare for shutdown check successful, API failure: %s" % e)
+        finally :
+            cancel_shutdown_cmd = cancelShutdown.cancelShutdownCmd()
+            cancel_shutdown_cmd.managementserverid = 1
+            response = self.apiclient.cancelShutdown(cancel_shutdown_cmd)
+            self.assertEqual(
+                response.shutdowntriggered,
+                False,
+                "Failed to cancel shutdown"
+            )
+            ## Just to be sure, run another async command
+            project = self.run_async_cmd()
+            self.cleanup.append(project)
+
+    @attr(tags=["advanced", "smoke"])
+    def test_02_trigger_shutdown(self):
+        try :
+            cmd = triggerShutdown.triggerShutdownCmd()
+            cmd.managementserverid = 1
+            self.apiclient.triggerShutdown(cmd)
+            self.isServerShutdown()
+        finally :
+            self.startServer()
diff --git a/test/integration/smoke/test_set_sourcenat.py b/test/integration/smoke/test_set_sourcenat.py
new file mode 100644
index 0000000..e89af9f
--- /dev/null
+++ b/test/integration/smoke/test_set_sourcenat.py
@@ -0,0 +1,274 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# 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.
+""" BVT tests for Network Life Cycle
+"""
+# Import Local Modules
+from marvin.codes import (FAILED, STATIC_NAT_RULE, LB_RULE,
+                          NAT_RULE, PASS)
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.base import (Account,
+                             VPC,
+                             VpcOffering,
+                             ServiceOffering,
+                             PublicIPAddress,
+                             Network,
+                             NetworkOffering)
+from marvin.lib.common import (get_domain,
+                               get_free_vlan,
+                               get_zone,
+                               get_template,
+                               get_test_template,
+                               list_publicIP)
+
+from nose.plugins.attrib import attr
+# Import System modules
+import time
+import logging
+
+_multiprocess_shared_ = True
+
+logger = logging.getLogger('TestSetSourceNatIp')
+stream_handler = logging.StreamHandler()
+logger.setLevel(logging.DEBUG)
+logger.addHandler(stream_handler)
+
+
+class TestSetSourceNatIp(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        testClient = super(TestSetSourceNatIp, cls).getClsTestClient()
+        cls.apiclient = testClient.getApiClient()
+        cls.services = testClient.getParsedTestDataConfig()
+
+        # Get Zone, Domain and templates
+        cls.domain = get_domain(cls.apiclient)
+        cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
+        cls.services['mode'] = cls.zone.networktype
+        cls._cleanup = []
+        # Create Accounts & networks
+        cls.account = Account.create(
+            cls.apiclient,
+            cls.services["account"],
+            admin=True,
+            domainid=cls.domain.id
+        )
+        cls._cleanup.append(cls.account)
+
+        cls.services["network"]["zoneid"] = cls.zone.id
+
+        cls.vpc_offering = VpcOffering.create(
+            cls.apiclient,
+            cls.services["vpc_offering"],
+        )
+        cls._cleanup.append(cls.vpc_offering)
+        cls.vpc_offering.update(cls.apiclient, state='Enabled')
+        cls.services["vpc"]["vpcoffering"] = cls.vpc_offering.id
+
+        cls.network_offering = NetworkOffering.create(
+            cls.apiclient,
+            cls.services["network_offering"],
+        )
+        cls._cleanup.append(cls.network_offering)
+        # Enable Network offering
+        cls.network_offering.update(cls.apiclient, state='Enabled')
+
+        cls.services["network"]["networkoffering"] = cls.network_offering.id
+
+        cls.service_offering = ServiceOffering.create(
+            cls.apiclient,
+            cls.services["service_offerings"]["tiny"],
+        )
+        cls._cleanup.append(cls.service_offering)
+
+        cls.hypervisor = testClient.getHypervisorInfo()
+        cls.template = get_test_template(
+            cls.apiclient,
+            cls.zone.id,
+            cls.hypervisor
+        )
+        if cls.template == FAILED:
+            assert False, "get_test_template() failed to return template"
+
+        cls.services["virtual_machine"]["zoneid"] = cls.zone.id
+        network = Network.create(
+            cls.apiclient,
+            cls.services["network"],
+            cls.account.name,
+            cls.account.domainid
+        )
+        cls._cleanup.append(network)
+        ip_address = PublicIPAddress.create(
+            cls.apiclient,
+            cls.account.name,
+            cls.zone.id,
+            cls.account.domainid
+        )
+        cls._cleanup.append(ip_address)
+        cls.ip_to_want = ip_address.ipaddress.ipaddress
+        cls.debug(f'==== my local ip: {cls.ip_to_want}')
+        ip_address.delete(cls.apiclient)
+        cls._cleanup.remove(ip_address)
+        network.delete(cls.apiclient)
+        cls._cleanup.remove(network)
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestSetSourceNatIp, cls).tearDownClass()
+
+    def setUp(self):
+        self.cleanup = []
+
+    def tearDown(self):
+        super(TestSetSourceNatIp, self).tearDown()
+
+    @attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false")
+    def test_01_create_network_with_specified_source_nat_ip_address(self):
+        """
+        For creation of network witjh a specified address
+        """
+
+
+        self.services["network"]["networkoffering"] = self.network_offering.id
+        network = Network.create(
+            self.apiclient,
+            self.services["network"],
+            self.account.name,
+            self.account.domainid,
+            sourcenatipaddress = self.ip_to_want
+        )
+        self.cleanup.append(network)
+
+        self.validate_source_nat(network=network, ip=self.ip_to_want)
+
+
+    @attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false")
+    def test_02_change_source_nat_ip_address_for_network(self):
+        """
+        Test changing a networks source NAT IP address
+        """
+        network = Network.create(
+            self.apiclient,
+            self.services["network"],
+            self.account.name,
+            self.account.domainid,
+            sourcenatipaddress = self.ip_to_want
+        )
+        self.cleanup.append(network)
+        second_ip = PublicIPAddress.create(
+            self.apiclient,
+            self.account.name,
+            self.zone.id,
+            self.account.domainid,
+            networkid=network.id
+        )
+        self.cleanup.append(second_ip)
+        self.debug(f'==== second ip: {second_ip.ipaddress.ipaddress}')
+
+        self.validate_source_nat(network=network, ip=self.ip_to_want)
+
+        network.update(self.apiclient, sourcenatipaddress=second_ip.ipaddress.ipaddress)
+
+        self.validate_source_nat(network=network, ip=second_ip.ipaddress.ipaddress)
+
+        return
+
+
+    @attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false")
+    def test_03_create_vpc_with_specified_source_nat_ip_address(self):
+        """
+        Test for creation of a VPC with a specified address
+        """
+
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            self.vpc_offering.id,
+            self.zone.id,
+            sourcenatipaddress = self.ip_to_want
+        )
+        self.cleanup.append(vpc)
+
+        self.validate_source_nat(vpc=vpc, ip=self.ip_to_want)
+
+    @attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false")
+    def test_04_change_source_nat_ip_address_for_vpc(self):
+        """
+        Test changing a networks source NAT IP address
+        """
+        vpc = VPC.create(
+            self.apiclient,
+            self.services["vpc"],
+            self.vpc_offering.id,
+            self.zone.id,
+            account=self.account.name,
+            domainid = self.account.domainid,
+            sourcenatipaddress = self.ip_to_want
+        )
+        self.cleanup.append(vpc)
+        second_ip = PublicIPAddress.create(
+            self.apiclient,
+            self.account.name,
+            self.zone.id,
+            self.account.domainid,
+            vpcid=vpc.id
+        )
+        self.debug(f'==== second ip: {second_ip.ipaddress.ipaddress}')
+
+        self.validate_source_nat(vpc=vpc, ip=self.ip_to_want)
+
+        vpc.update(self.apiclient, sourcenatipaddress=second_ip.ipaddress.ipaddress)
+
+        self.validate_source_nat(vpc=vpc, ip=second_ip.ipaddress.ipaddress)
+
+        return
+
+
+    def validate_source_nat(self, network=None, vpc=None, ip=None):
+        list_pub_ip_addr_resp = None
+        if network:
+            list_pub_ip_addr_resp = list_publicIP(
+                self.apiclient,
+                associatednetworkid=network.id,
+                listall=True,
+                issourcenat=True
+            )
+        elif vpc:
+            list_pub_ip_addr_resp = list_publicIP(
+                self.apiclient,
+                vpcid=vpc.id,
+                listall=True,
+                issourcenat=True
+            )
+        self.assertEqual(
+            isinstance(list_pub_ip_addr_resp, list),
+            True,
+            "Check list response returns a valid list"
+        )
+        self.assertNotEqual(
+            len(list_pub_ip_addr_resp),
+            0,
+            "Check if new IP Address is associated"
+        )
+        self.debug(f'==== my result {list_pub_ip_addr_resp[0]}')
+        self.assertEqual(
+            list_pub_ip_addr_resp[0].ipaddress,
+            ip,
+            f"Check Correct IP Address is returned in the List, expected {ip} but got {list_pub_ip_addr_resp[0].ipaddress}"
+        )
diff --git a/test/integration/smoke/test_vm_deployment_planner.py b/test/integration/smoke/test_vm_deployment_planner.py
index 636eaac..e8d24cb 100644
--- a/test/integration/smoke/test_vm_deployment_planner.py
+++ b/test/integration/smoke/test_vm_deployment_planner.py
@@ -69,8 +69,7 @@
         cmd = deployVirtualMachine.deployVirtualMachineCmd()
         template = get_template(
             self.apiclient,
-            self.zone.id,
-            hypervisor=self.hypervisor
+            self.zone.id
         )
         cmd.zoneid = self.zone.id
         cmd.templateid = template.id
diff --git a/test/integration/smoke/test_vm_schedule.py b/test/integration/smoke/test_vm_schedule.py
new file mode 100644
index 0000000..e66470d
--- /dev/null
+++ b/test/integration/smoke/test_vm_schedule.py
@@ -0,0 +1,609 @@
+# 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.
+""" P1 tests for VM Schedule
+"""
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.base import Account, ServiceOffering, VirtualMachine, VMSchedule
+from marvin.lib.common import get_domain, get_zone, get_template
+from marvin.lib.utils import cleanup_resources
+
+# Import Local Modules
+from nose.plugins.attrib import attr
+
+import datetime
+import time
+
+
+class Services:
+    """Test Snapshots Services"""
+
+    def __init__(self):
+        self.services = {
+            "account": {
+                "email": "test@test.com",
+                "firstname": "Test",
+                "lastname": "User",
+                "username": "test",
+                # Random characters are appended for unique
+                # username
+                "password": "password",
+            },
+            "service_offering": {
+                "name": "Tiny Instance",
+                "displaytext": "Tiny Instance",
+                "cpunumber": 1,
+                "cpuspeed": 200,  # in MHz
+                "memory": 256,  # In MBs
+            },
+            "disk_offering": {
+                "displaytext": "Small Disk",
+                "name": "Small Disk",
+                "disksize": 1,
+            },
+            "server": {
+                "displayname": "TestVM",
+                "username": "root",
+                "password": "password",
+                "ssh_port": 22,
+                "privateport": 22,
+                "publicport": 22,
+                "protocol": "TCP",
+            },
+            "mgmt_server": {
+                "ipaddress": "192.168.100.21",
+                "username": "root",
+                "password": "password",
+                "port": 22,
+            },
+            "templates": {
+                "displaytext": "Template",
+                "name": "Template",
+                "ostype": "CentOS 5.3 (64-bit)",
+                "templatefilter": "self",
+            },
+            "ostype": "CentOS 5.3 (64-bit)",
+        }
+
+
+class TestVMSchedule(cloudstackTestCase):
+    @classmethod
+    def setUpClass(cls):
+        cls.testClient = super(TestVMSchedule, cls).getClsTestClient()
+        cls.api_client = cls.testClient.getApiClient()
+
+        cls._cleanup = []
+
+        cls.hypervisor = cls.testClient.getHypervisorInfo()
+
+        cls.services = Services().services
+        # Get Zone, Domain and templates
+        cls.domain = get_domain(cls.api_client)
+        cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
+        cls.services["mode"] = cls.zone.networktype
+        template = get_template(cls.api_client, cls.zone.id, cls.services["ostype"])
+
+        cls.services["domainid"] = cls.domain.id
+        cls.services["server"]["zoneid"] = cls.zone.id
+
+        cls.services["templates"]["ostypeid"] = template.ostypeid
+        cls.services["zoneid"] = cls.zone.id
+
+        # Create VMs, NAT Rules etc
+        cls.account = Account.create(
+            cls.api_client, cls.services["account"], domainid=cls.domain.id
+        )
+        cls._cleanup.append(cls.account)
+
+        cls.services["account"] = cls.account.name
+
+        cls.service_offering = ServiceOffering.create(
+            cls.api_client, cls.services["service_offering"]
+        )
+        cls._cleanup.append(cls.service_offering)
+        cls.virtual_machine = VirtualMachine.create(
+            cls.api_client,
+            cls.services["server"],
+            templateid=template.id,
+            accountid=cls.account.name,
+            domainid=cls.account.domainid,
+            serviceofferingid=cls.service_offering.id,
+        )
+        return
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestVMSchedule, cls).tearDownClass()
+
+    def setUp(self):
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        super(TestVMSchedule, self).tearDown()
+
+    @attr(tags=["advanced", "basic"], required_hardware="false")
+    def test_01_vmschedule_create(self):
+        """Test VM Schedule Creation in cron format and validate responses"""
+
+        # Validate the following
+        # 1. Create VM Schedule in cron format
+        # 2. List VM Schedule and verify the response
+        # 3. Delete VM Schedule and verify the response
+
+        # Create VM Schedule
+        schedule = "0 0 1 * *"
+        vmschedule = VMSchedule.create(
+            self.apiclient,
+            self.virtual_machine.id,
+            "start",
+            schedule,
+            datetime.datetime.now().astimezone().tzinfo,
+            # Current date minutes in format "2014-01-01 00:00:00"
+            (datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
+                "%Y-%m-%d %H:%M:%S"
+            ),
+            enabled=True,
+        )
+
+        self.cleanup.append(vmschedule)
+
+        self.debug("Created VM Schedule with ID: %s" % vmschedule.id)
+
+        # List VM Schedule
+        vmschedules = VMSchedule.list(
+            self.apiclient, self.virtual_machine.id, id=vmschedule.id
+        )
+
+        self.assertEqual(
+            isinstance(vmschedules, list),
+            True,
+            "Check list response returns a valid list",
+        )
+
+        self.assertNotEqual(len(vmschedules), 0, "Check VM Schedule list")
+
+        self.debug("List VM Schedule response: %s" % vmschedules[0].__dict__)
+
+        self.assertEqual(
+            vmschedules[0].id,
+            vmschedule.id,
+            "Check VM Schedule ID in list resources call",
+        )
+
+        self.assertEqual(
+            vmschedules[0].virtualmachineid,
+            self.virtual_machine.id,
+            "Check VM ID in list resources call",
+        )
+
+        self.assertEqual(
+            vmschedules[0].schedule,
+            schedule,
+            "Check VM Schedule in list resources call",
+        )
+
+        self.assertEqual(
+            vmschedules[0].timezone,
+            str(datetime.datetime.now().astimezone().tzinfo),
+            "Check VM Schedule timezone in list resources call",
+        )
+
+        # Check for entry in vm_scheduled_job in db
+        vmscheduled_job = self.dbclient.execute(
+            "select * from vm_scheduled_job where vm_schedule_id IN (SELECT id FROM vm_schedule WHERE uuid = '%s')"
+            % vmschedule.id,
+            db="cloud",
+        )
+
+        self.assertIsInstance(
+            vmscheduled_job,
+            list,
+            "Check if VM Schedule exists in vm_scheduled_job table",
+        )
+
+        self.assertGreater(
+            len(vmscheduled_job),
+            0,
+            "Check if VM Schedule exists in vm_scheduled_job table",
+        )
+        return
+
+    @attr(tags=["advanced", "basic"], required_hardware="false")
+    def test_02_vmschedule_create_parameter_exceptions(self):
+        """Test VM Schedule Creation exceptions with invalid parameters"""
+
+        # Validate the following
+        # 1. Create VM Schedule with invalid virtual machine ID
+        # 2. Create VM Schedule with invalid schedule
+        # 3. Create VM Schedule with invalid start date
+        # 5. Create VM Schedule with invalid action
+        # 6. Create VM Schedule with invalid end date
+
+        # Create VM Schedule with invalid virtual machine ID
+        with self.assertRaises(Exception):
+            VMSchedule.create(
+                self.apiclient,
+                "invalid",
+                "start",
+                "0 0 1 * *",
+                datetime.datetime.now().astimezone().tzinfo,
+                # Current date minutes in format "2014-01-01 00:00:00"
+                (datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
+                    "%Y-%m-%d %H:%M:%S"
+                ),
+            )
+
+        # Create VM Schedule with invalid schedule
+        with self.assertRaises(Exception):
+            VMSchedule.create(
+                self.apiclient,
+                self.virtual_machine.id,
+                "start",
+                "invalid",
+                datetime.datetime.now().astimezone().tzinfo,
+                # Current date minutes in format "2014-01-01 00:00:00"
+                (datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
+                    "%Y-%m-%d %H:%M:%S"
+                ),
+            )
+
+        # Create VM Schedule with invalid start date
+        with self.assertRaises(Exception):
+            VMSchedule.create(
+                self.apiclient,
+                self.virtual_machine.id,
+                "start",
+                "0 0 1 * *",
+                datetime.datetime.now().astimezone().tzinfo,
+                # Current date minutes in format "2014-01-01 00:00:00"
+                "invalid",
+            )
+
+        # Create VM Schedule with invalid action
+        with self.assertRaises(Exception):
+            VMSchedule.create(
+                self.apiclient,
+                self.virtual_machine.id,
+                "invalid",
+                "0 0 1 * *",
+                datetime.datetime.now().astimezone().tzinfo,
+                # Current date minutes in format "2014-01-01 00:00:00"
+                (datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
+                    "%Y-%m-%d %H:%M:%S"
+                ),
+            )
+
+        # test invalid end date
+        with self.assertRaises(Exception):
+            VMSchedule.create(
+                self.apiclient,
+                self.virtual_machine.id,
+                "start",
+                "0 0 1 * *",
+                datetime.datetime.now().astimezone().tzinfo,
+                # Current date minutes in format "2014-01-01 00:00:00"
+                (datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
+                    "%Y-%m-%d %H:%M:%S"
+                ),
+                enddate="invalid",
+            )
+        return
+
+    @attr(tags=["advanced", "basic"], required_hardware="false")
+    def test_03_vmschedule_update(self):
+        """Test VM Schedule Update in cron format and validate responses"""
+
+        # Validate the following
+        # 1. Create VM Schedule in cron format
+        # 2. Update VM Schedule and verify the response
+
+        # Create VM Schedule
+        schedule = "0 0 1 * *"
+        vmschedule = VMSchedule.create(
+            self.apiclient,
+            self.virtual_machine.id,
+            "start",
+            schedule,
+            datetime.datetime.now().astimezone().tzinfo,
+            # Current date minutes in format "2014-01-01 00:00:00"
+            (datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
+                "%Y-%m-%d %H:%M:%S"
+            ),
+        )
+
+        self.cleanup.append(vmschedule)
+
+        self.debug("Created VM Schedule with ID: %s" % vmschedule.id)
+
+        # Update VM Schedule
+        new_schedule = "0 0 2 * *"
+        vmschedule.update(
+            self.apiclient,
+            id=vmschedule.id,
+            virtualmachineid=self.virtual_machine.id,
+            description="TestVM",
+            schedule=new_schedule,
+            timezone=datetime.datetime.now().astimezone().tzinfo,
+            startdate=(
+                datetime.datetime.now() + datetime.timedelta(minutes=10)
+            ).strftime("%Y-%m-%d %H:%M:%S"),
+            enddate=(datetime.datetime.now() + datetime.timedelta(hours=10)).strftime(
+                "%Y-%m-%d %H:%M:%S"
+            ),
+        )
+
+        self.debug("Updated VM Schedule with ID: %s" % vmschedule.id)
+
+        # List VM Schedule
+        vmschedules = VMSchedule.list(
+            self.apiclient, self.virtual_machine.id, id=vmschedule.id
+        )
+        self.assertEqual(
+            isinstance(vmschedules, list),
+            True,
+            "Check list response returns a valid list",
+        )
+
+        self.assertNotEqual(len(vmschedules), 0, "Check VM Schedule list")
+
+        self.debug("List VM Schedule response: %s" % vmschedules[0].__dict__)
+
+        self.assertEqual(
+            vmschedules[0].id,
+            vmschedule.id,
+            "Check VM Schedule ID in list resources call",
+        )
+
+        self.assertEqual(
+            vmschedules[0].virtualmachineid,
+            self.virtual_machine.id,
+            "Check VM ID in list resources call",
+        )
+
+        self.assertEqual(
+            vmschedules[0].schedule,
+            new_schedule,
+            "Check VM Schedule in list resources call",
+        )
+        return
+
+    @attr(tags=["advanced", "basic"], required_hardware="false")
+    def test_04_vmschedule_update_parameter_exceptions(self):
+        """Test VM Schedule Update exceptions with invalid parameters"""
+
+        # Validate the following
+        # 1. Update VM Schedule with invalid schedule
+        # 2. Update VM Schedule with invalid start date
+        # 3. Update VM Schedule with invalid ID
+        # 4. Update VM Schedule with invalid end date
+
+        # Create VM Schedule
+        schedule = "0 0 1 * *"
+        vmschedule = VMSchedule.create(
+            self.apiclient,
+            self.virtual_machine.id,
+            "start",
+            schedule,
+            datetime.datetime.now().astimezone().tzinfo,
+            # Current date minutes in format "2014-01-01 00:00:00"
+            (datetime.datetime.now() + datetime.timedelta(minutes=5)).strftime(
+                "%Y-%m-%d %H:%M:%S"
+            ),
+        )
+
+        self.cleanup.append(vmschedule)
+
+        self.debug("Created VM Schedule with ID: %s" % vmschedule.id)
+
+        # Update VM Schedule with invalid schedule
+        with self.assertRaises(Exception):
+            vmschedule.update(
+                self.apiclient,
+                id=vmschedule.id,
+                virtualmachineid=self.virtual_machine.id,
+                description="TestVM",
+                schedule="invalid",
+                timezone=datetime.datetime.now().astimezone().tzinfo,
+                startdate=(
+                    datetime.datetime.now() + datetime.timedelta(minutes=5)
+                ).strftime("%Y-%m-%d %H:%M:%S"),
+            )
+
+        # Update VM Schedule with invalid start date
+        with self.assertRaises(Exception):
+            vmschedule.update(
+                self.apiclient,
+                id=vmschedule.id,
+                virtualmachineid=self.virtual_machine.id,
+                description="TestVM",
+                schedule=schedule,
+                timezone=datetime.datetime.now().astimezone().tzinfo,
+                startdate=(
+                    datetime.datetime.now() - datetime.timedelta(days=1)
+                ).strftime("%Y-%m-%d %H:%M:%S"),
+            )
+
+        # Update VM Schedule with invalid ID
+        with self.assertRaises(Exception):
+            vmschedule.update(
+                self.apiclient,
+                id="invalid",
+                virtualmachineid=self.virtual_machine.id,
+                description="TestVM",
+                schedule=schedule,
+                timezone=datetime.datetime.now().astimezone().tzinfo,
+                startdate=(
+                    datetime.datetime.now() + datetime.timedelta(minutes=5)
+                ).strftime("%Y-%m-%d %H:%M:%S"),
+            )
+
+        # Update VM Schedule with invalid end date
+        with self.assertRaises(Exception):
+            vmschedule.update(
+                self.apiclient,
+                id=vmschedule.id,
+                virtualmachineid=self.virtual_machine.id,
+                description="TestVM",
+                schedule=schedule,
+                timezone=datetime.datetime.now().astimezone().tzinfo,
+                startdate=(
+                    datetime.datetime.now() + datetime.timedelta(minutes=5)
+                ).strftime("%Y-%m-%d %H:%M:%S"),
+                enddate=(
+                    datetime.datetime.now() - datetime.timedelta(minutes=5)
+                ).strftime("%Y-%m-%d %H:%M:%S"),
+            )
+
+        return
+
+    @attr(tags=["advanced", "basic"], required_hardware="false")
+    def test_05_vmschedule_test_e2e(self):
+        # Validate the following
+        # 1. Create 2 VM Schedules - start and stop
+        # 2. Verify VM Schedule is created
+        # 3. Verify VM is stopped after schedule time
+        # 4. Verify VM is started after schedule time
+        # 5. Delete VM Schedule
+        # 6. Verify VM Schedule is deleted
+        # 7. Verify VM is not stopped after schedule time
+        # 8. Verify VM is not started after schedule time
+
+        # Create VM Schedule - start
+        start_schedule = "*/2 * * * *"
+        start_vmschedule = VMSchedule.create(
+            self.apiclient,
+            self.virtual_machine.id,
+            "start",
+            start_schedule,
+            datetime.datetime.now().astimezone().tzinfo,
+            # Current date minutes in format "2014-01-01 00:00:00"
+            (datetime.datetime.now() + datetime.timedelta(seconds=5)).strftime(
+                "%Y-%m-%d %H:%M:%S"
+            ),
+            enabled=True,
+        )
+
+        self.debug("Created VM Schedule with ID: %s" % start_vmschedule.id)
+
+        # Create VM Schedule - stop
+        stop_schedule = "*/1 * * * *"
+        stop_vmschedule = VMSchedule.create(
+            self.apiclient,
+            self.virtual_machine.id,
+            "stop",
+            stop_schedule,
+            datetime.datetime.now().astimezone().tzinfo,
+            # Current date minutes in format "2014-01-01 00:00:00"
+            (datetime.datetime.now() + datetime.timedelta(seconds=5)).strftime(
+                "%Y-%m-%d %H:%M:%S"
+            ),
+            enabled=True,
+        )
+
+        self.debug("Created VM Schedule with ID: %s" % stop_vmschedule.id)
+
+        # Verify VM Schedule is created
+        vmschedules = VMSchedule.list(
+            self.apiclient, self.virtual_machine.id, id=start_vmschedule.id
+        )
+
+        self.assertEqual(
+            isinstance(vmschedules, list),
+            True,
+            "Check list response returns a valid list",
+        )
+        self.assertNotEqual(len(vmschedules), 0, "Check VM Schedule is created")
+
+        # poll every 10 seconds (max waiting time is 6 minutes) and check VM's state for changes
+        previous_state = self.virtual_machine.state
+        self.debug("VM state: %s" % self.virtual_machine.state)
+        is_stop_schedule_working = False
+        is_start_schedule_working = False
+        for i in range(0, 36):
+            time.sleep(10)
+            current_state = self.virtual_machine.update(self.apiclient).state
+            self.debug("Polling VM state: %s" % current_state)
+            if previous_state in ("Running", "Starting") and current_state in (
+                "Stopped",
+                "Stopping",
+            ):
+                is_stop_schedule_working = True
+            elif previous_state in ("Stopped", "Stopping") and current_state in (
+                "Running",
+                "Starting",
+            ):
+                is_start_schedule_working = True
+            if is_start_schedule_working and is_stop_schedule_working:
+                break
+            previous_state = current_state
+
+        self.debug("Is stop schedule working: %s" % is_stop_schedule_working)
+        self.debug("Is start schedule working: %s" % is_start_schedule_working)
+
+        self.assertTrue(
+            is_stop_schedule_working,
+            "VM switched states from Running to Stopped at least once",
+        )
+
+        self.assertTrue(
+            is_start_schedule_working,
+            "VM switched states from Stopped to Running at least once",
+        )
+
+        # Delete VM Schedule
+        start_vmschedule.delete(self.apiclient)
+        stop_vmschedule.delete(self.apiclient)
+
+        # To ensure that all vm schedules have been deleted and all of their jobs have been completed
+        time.sleep(15)
+
+        # Verify VM Schedule is deleted
+        self.assertEqual(
+            VMSchedule.list(
+                self.apiclient, self.virtual_machine.id, id=start_vmschedule.id
+            ),
+            None,
+            "Check VM Schedule is deleted",
+        )
+        self.assertEqual(
+            VMSchedule.list(
+                self.apiclient, self.virtual_machine.id, id=stop_vmschedule.id
+            ),
+            None,
+            "Check VM Schedule is deleted",
+        )
+
+        # Verify VM does not switch states after deleting schedules at least for 2 minutes
+        previous_state = self.virtual_machine.update(self.apiclient).state
+        state_changed = False
+        for i in range(0, 4):
+            time.sleep(30)
+            current_state = self.virtual_machine.update(self.apiclient).state
+            if previous_state != current_state:
+                self.debug(
+                    "VM changed state from %s to %s" % (previous_state, current_state)
+                )
+                state_changed = True
+                break
+
+        self.assertFalse(
+            state_changed,
+            "VM did not switch states after schedule time",
+        )
+        return
diff --git a/test/metadata/func/templates_sync.xml b/test/metadata/func/templates_sync.xml
index a03e4bf..96d6362 100644
--- a/test/metadata/func/templates_sync.xml
+++ b/test/metadata/func/templates_sync.xml
@@ -1058,6 +1058,3 @@
 

 

 </templatesync>

-

-

-

diff --git a/test/pom.xml b/test/pom.xml
index 2106fa7..1692a13 100644
--- a/test/pom.xml
+++ b/test/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
     </parent>
     <dependencies>
         <dependency>
diff --git a/test/scripts/bootstrap-regression.sh b/test/scripts/bootstrap-regression.sh
index 8328d10..ff219dd 100755
--- a/test/scripts/bootstrap-regression.sh
+++ b/test/scripts/bootstrap-regression.sh
@@ -34,4 +34,4 @@
 ./cleanparallel.sh
 ./deploy.sh  -b ../cloud-management-dist -d -r
 sleep 300
-./regression.sh
\ No newline at end of file
+./regression.sh
diff --git a/test/scripts/build-env.sh b/test/scripts/build-env.sh
index 2a9a586..299b6b6 100755
--- a/test/scripts/build-env.sh
+++ b/test/scripts/build-env.sh
@@ -27,5 +27,3 @@
 
 CP=commons-httpclient-3.1.jar${PATHSEP}commons-logging-1.1.1.jar${PATHSEP}commons-codec-1.3.jar${PATHSEP}testclient.jar${PATHSEP}log4j-1.2.15.jar${PATHSEP}utils.jar${PATHSEP}./conf
 java -cp $CP com.vmops.test.longrun.BuildGuestNetwork $*
-
-
diff --git a/test/scripts/checkOutOfMemory.sh b/test/scripts/checkOutOfMemory.sh
index 08dccda..cb5b595 100755
--- a/test/scripts/checkOutOfMemory.sh
+++ b/test/scripts/checkOutOfMemory.sh
@@ -34,4 +34,4 @@
 sleep 1800
 done
 fi
-done
\ No newline at end of file
+done
diff --git a/test/scripts/cleanparallel.sh b/test/scripts/cleanparallel.sh
index fe72da7..0ccb546 100755
--- a/test/scripts/cleanparallel.sh
+++ b/test/scripts/cleanparallel.sh
@@ -110,6 +110,3 @@
   echo "Starting cleanup on secondary storage $i";
   cleanup_storage $i $SECONDARY_STORAGE_DIR
 done
-
-
-
diff --git a/test/scripts/deploy-and-run-regression.sh b/test/scripts/deploy-and-run-regression.sh
index 5c2ad98..691a930 100755
--- a/test/scripts/deploy-and-run-regression.sh
+++ b/test/scripts/deploy-and-run-regression.sh
@@ -45,4 +45,3 @@
 scp -o BatchMode\ yes -r "$srcbootstrapper" $host:$destbootstrapper
 
 ssh -o BatchMode\ yes $host $destbootstrapper
-
diff --git a/test/scripts/deploycluster.sh b/test/scripts/deploycluster.sh
index 636a56b..91111d9 100755
--- a/test/scripts/deploycluster.sh
+++ b/test/scripts/deploycluster.sh
@@ -70,8 +70,3 @@
   echo "$ip"
   deploy_server $ip
 done
-
-
-
-
-
diff --git a/test/scripts/executeUserAPI.sh b/test/scripts/executeUserAPI.sh
index 55107bc..caf54b1 100755
--- a/test/scripts/executeUserAPI.sh
+++ b/test/scripts/executeUserAPI.sh
@@ -30,5 +30,3 @@
 
 CP=${DST}commons-httpclient-3.1.jar${PATHSEP}${DST}commons-logging-1.1.1.jar${PATHSEP}${DST}commons-codec-1.4.jar${PATHSEP}${DST}testclient.jar${PATHSEP}.././conf
 java -cp $CP com.cloud.sample.UserCloudAPIExecutor
-
-
diff --git a/test/scripts/run.sh b/test/scripts/run.sh
index 987f70e..de1dc22 100755
--- a/test/scripts/run.sh
+++ b/test/scripts/run.sh
@@ -31,4 +31,3 @@
 CP=${DST}commons-httpclient-3.1.jar${PATHSEP}${DST}commons-logging-1.1.1.jar${PATHSEP}${DST}commons-codec-1.4.jar${PATHSEP}${DST}cloud-test.jar${PATHSEP}${DST}log4j.jar${PATHSEP}${DST}trilead-ssh2-build213.jar${PATHSEP}${DST}cloud-utils.jar${PATHSEP}.././conf
 java -cp $CP com.cloud.test.stress.TestClientWithAPI $*
 #java -cp $CP com.cloud.test.stress.StressTestDirectAttach $*
-
diff --git a/test/scripts/usage/allocated.sh b/test/scripts/usage/allocated.sh
index 7ae5737..bb7fa1b 100755
--- a/test/scripts/usage/allocated.sh
+++ b/test/scripts/usage/allocated.sh
@@ -83,4 +83,3 @@
 echo "Skipping verification for account $i (the account either a) misses the second VM b) VM wasn't stopped 3) VM Stop failed "
 fi
 done
-
diff --git a/test/scripts/usage/volume_usage.sh b/test/scripts/usage/volume_usage.sh
index c18493b..a3b21d6 100755
--- a/test/scripts/usage/volume_usage.sh
+++ b/test/scripts/usage/volume_usage.sh
@@ -157,5 +157,3 @@
 echo "Skipping verification for account $i (the account either a) misses root volume $volume_name b) volume wasn't deleted 3) Delete volume failed "
 fi
 done
-
-
diff --git a/test/scripts/xen/corrupttemplate.sh b/test/scripts/xen/corrupttemplate.sh
index 528dcf1..d26097f 100755
--- a/test/scripts/xen/corrupttemplate.sh
+++ b/test/scripts/xen/corrupttemplate.sh
@@ -48,4 +48,4 @@
 exit 2
 else
 exit 0
-fi
\ No newline at end of file
+fi
diff --git a/test/scripts/xen/createfaketemplate.sh b/test/scripts/xen/createfaketemplate.sh
index a68a0c3..cc91122 100755
--- a/test/scripts/xen/createfaketemplate.sh
+++ b/test/scripts/xen/createfaketemplate.sh
@@ -50,4 +50,4 @@
 exit 2
 else
 exit 0
-fi
\ No newline at end of file
+fi
diff --git a/test/scripts/xen/killvm.sh b/test/scripts/xen/killvm.sh
index 43b81c9..5aa9b1e 100755
--- a/test/scripts/xen/killvm.sh
+++ b/test/scripts/xen/killvm.sh
@@ -49,4 +49,4 @@
 exit 2
 else
 exit 0
-fi
\ No newline at end of file
+fi
diff --git a/test/scripts/xen/listtemplate.sh b/test/scripts/xen/listtemplate.sh
index bf3c589..4b76b4a 100755
--- a/test/scripts/xen/listtemplate.sh
+++ b/test/scripts/xen/listtemplate.sh
@@ -44,4 +44,4 @@
 exit 2
 else
 exit 0
-fi
\ No newline at end of file
+fi
diff --git a/test/scripts/xen/listvdi.sh b/test/scripts/xen/listvdi.sh
index cf20bc6..9125b75 100755
--- a/test/scripts/xen/listvdi.sh
+++ b/test/scripts/xen/listvdi.sh
@@ -55,4 +55,4 @@
 exit 2
 else
 exit 0
-fi
\ No newline at end of file
+fi
diff --git a/test/scripts/xen/listvm.sh b/test/scripts/xen/listvm.sh
index cd58e78..0a4e8b2 100755
--- a/test/scripts/xen/listvm.sh
+++ b/test/scripts/xen/listvm.sh
@@ -55,4 +55,4 @@
 exit 2
 else
 exit 0
-fi
\ No newline at end of file
+fi
diff --git a/test/scripts/xen/ms.sh b/test/scripts/xen/ms.sh
index c06b119..d4a6cbc 100755
--- a/test/scripts/xen/ms.sh
+++ b/test/scripts/xen/ms.sh
@@ -37,4 +37,4 @@
 sleep 30
 
 exit 0
-fi
\ No newline at end of file
+fi
diff --git a/test/scripts/xen/removetemplate.sh b/test/scripts/xen/removetemplate.sh
index dc7a63a..dd632cf 100755
--- a/test/scripts/xen/removetemplate.sh
+++ b/test/scripts/xen/removetemplate.sh
@@ -48,4 +48,4 @@
 exit 2
 else
 exit 0
-fi
\ No newline at end of file
+fi
diff --git a/test/scripts/xen/shutdown.sh b/test/scripts/xen/shutdown.sh
index 69c51fe..c5621b1b 100755
--- a/test/scripts/xen/shutdown.sh
+++ b/test/scripts/xen/shutdown.sh
@@ -49,4 +49,4 @@
 exit 2
 else
 exit 0
-fi
\ No newline at end of file
+fi
diff --git a/test/scripts/xen/sleep.sh b/test/scripts/xen/sleep.sh
index f06798d..68bde07 100755
--- a/test/scripts/xen/sleep.sh
+++ b/test/scripts/xen/sleep.sh
@@ -30,4 +30,4 @@
   esac
 done
 
-sleep $sleep
\ No newline at end of file
+sleep $sleep
diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py
index 1352800..bd102e9 100644
--- a/tools/apidoc/gen_toc.py
+++ b/tools/apidoc/gen_toc.py
@@ -248,7 +248,8 @@
     'Rolling': 'Rolling Maintenance',
     'importVsphereStoragePolicies' : 'vSphere storage policies',
     'listVsphereStoragePolicies' : 'vSphere storage policies',
-    'ConsoleEndpoint': 'Console Endpoint'
+    'ConsoleEndpoint': 'Console Endpoint',
+    'Shutdown': 'Shutdown'
 }
 
 
diff --git a/tools/apidoc/generatecommand.xsl b/tools/apidoc/generatecommand.xsl
index a54170a..e610d09 100644
--- a/tools/apidoc/generatecommand.xsl
+++ b/tools/apidoc/generatecommand.xsl
@@ -192,4 +192,3 @@
 </html>
 </xsl:template>
 </xsl:stylesheet>
-
diff --git a/tools/apidoc/generatecustomcommand.xsl b/tools/apidoc/generatecustomcommand.xsl
index d03cf56..ae480bc 100644
--- a/tools/apidoc/generatecustomcommand.xsl
+++ b/tools/apidoc/generatecustomcommand.xsl
@@ -62,4 +62,3 @@
 </body></html>
 </xsl:template>
 </xsl:stylesheet>
-
diff --git a/tools/apidoc/generategenericcommand.xsl b/tools/apidoc/generategenericcommand.xsl
index 0d5dd14..0e93667 100644
--- a/tools/apidoc/generategenericcommand.xsl
+++ b/tools/apidoc/generategenericcommand.xsl
@@ -54,4 +54,3 @@
 </body></html>
 </xsl:template>
 </xsl:stylesheet>
-
diff --git a/tools/apidoc/generatetoc.xsl b/tools/apidoc/generatetoc.xsl
index 687e626..72be6a1 100644
--- a/tools/apidoc/generatetoc.xsl
+++ b/tools/apidoc/generatetoc.xsl
@@ -1143,4 +1143,3 @@
 </body></html>
 </xsl:template>
 </xsl:stylesheet>
-
diff --git a/tools/apidoc/pom.xml b/tools/apidoc/pom.xml
index a86de3d..43f4bc8 100644
--- a/tools/apidoc/pom.xml
+++ b/tools/apidoc/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-tools</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <properties>
diff --git a/tools/checkstyle/pom.xml b/tools/checkstyle/pom.xml
index d5ea235..bef394c 100644
--- a/tools/checkstyle/pom.xml
+++ b/tools/checkstyle/pom.xml
@@ -22,7 +22,7 @@
     <name>Apache CloudStack Developer Tools - Checkstyle Configuration</name>
     <groupId>org.apache.cloudstack</groupId>
     <artifactId>checkstyle</artifactId>
-    <version>4.18.1.0-SNAPSHOT</version>
+    <version>4.19.0.0-SNAPSHOT</version>
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
diff --git a/tools/devcloud-kvm/pom.xml b/tools/devcloud-kvm/pom.xml
index 299480e..d91e9f2 100644
--- a/tools/devcloud-kvm/pom.xml
+++ b/tools/devcloud-kvm/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-tools</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/tools/devcloud4/.gitignore b/tools/devcloud4/.gitignore
index 3969b1b..107499d 100644
--- a/tools/devcloud4/.gitignore
+++ b/tools/devcloud4/.gitignore
@@ -1,4 +1,4 @@
 tmp
 cookbooks
 *.lock
-.vagrant
\ No newline at end of file
+.vagrant
diff --git a/tools/devcloud4/binary-installation-advanced/Berksfile b/tools/devcloud4/binary-installation-advanced/Berksfile
index 7ad09e1..918a6d7 100644
--- a/tools/devcloud4/binary-installation-advanced/Berksfile
+++ b/tools/devcloud4/binary-installation-advanced/Berksfile
@@ -23,4 +23,4 @@
 cookbook 'selinux'
 cookbook 'nat-router', git: 'http://github.com/imduffy15/cookbook_nat-router'
 cookbook 'cloudstack', git: 'https://github.com/imduffy15/cookbook_cloudstack-1'
-cookbook 'binary-installation', path: '../common/binary-installation'
\ No newline at end of file
+cookbook 'binary-installation', path: '../common/binary-installation'
diff --git a/tools/devcloud4/binary-installation-advanced/marvin.cfg.erb b/tools/devcloud4/binary-installation-advanced/marvin.cfg.erb
index 6c847fb..bd65d3d 100644
--- a/tools/devcloud4/binary-installation-advanced/marvin.cfg.erb
+++ b/tools/devcloud4/binary-installation-advanced/marvin.cfg.erb
@@ -120,4 +120,4 @@
         "passwd": "<%= @database_password %>",
         "db": "<%= @database %>"
     }
-}
\ No newline at end of file
+}
diff --git a/tools/devcloud4/binary-installation-basic/Berksfile b/tools/devcloud4/binary-installation-basic/Berksfile
index 7ad09e1..918a6d7 100644
--- a/tools/devcloud4/binary-installation-basic/Berksfile
+++ b/tools/devcloud4/binary-installation-basic/Berksfile
@@ -23,4 +23,4 @@
 cookbook 'selinux'
 cookbook 'nat-router', git: 'http://github.com/imduffy15/cookbook_nat-router'
 cookbook 'cloudstack', git: 'https://github.com/imduffy15/cookbook_cloudstack-1'
-cookbook 'binary-installation', path: '../common/binary-installation'
\ No newline at end of file
+cookbook 'binary-installation', path: '../common/binary-installation'
diff --git a/tools/devcloud4/binary-installation-basic/marvin.cfg.erb b/tools/devcloud4/binary-installation-basic/marvin.cfg.erb
index 62415c9..721fc07 100644
--- a/tools/devcloud4/binary-installation-basic/marvin.cfg.erb
+++ b/tools/devcloud4/binary-installation-basic/marvin.cfg.erb
@@ -106,4 +106,4 @@
         "passwd": "<%= @database_password %>",
         "db": "<%= @database %>"
     }
-}
\ No newline at end of file
+}
diff --git a/tools/devcloud4/common/binary-installation/attributes/default.rb b/tools/devcloud4/common/binary-installation/attributes/default.rb
index 3b3eba0..94662ce 100644
--- a/tools/devcloud4/common/binary-installation/attributes/default.rb
+++ b/tools/devcloud4/common/binary-installation/attributes/default.rb
@@ -35,4 +35,4 @@
 default['cloudstack']['primary']['mgt_path'] = node['cloudstack']['primary']['path']
 
 
-default['cloudstack']['configuration'] = '/vagrant/marvin.cfg.erb'
\ No newline at end of file
+default['cloudstack']['configuration'] = '/vagrant/marvin.cfg.erb'
diff --git a/tools/devcloud4/common/binary-installation/recipes/database_server.rb b/tools/devcloud4/common/binary-installation/recipes/database_server.rb
index 28a374c..b9341a2 100644
--- a/tools/devcloud4/common/binary-installation/recipes/database_server.rb
+++ b/tools/devcloud4/common/binary-installation/recipes/database_server.rb
@@ -21,4 +21,3 @@
 include_recipe 'mysql::client'
 
 include_recipe 'cloudstack::mysql_conf'
-
diff --git a/tools/devcloud4/common/binary-installation/recipes/default.rb b/tools/devcloud4/common/binary-installation/recipes/default.rb
index 6dcd47c..600ec98 100644
--- a/tools/devcloud4/common/binary-installation/recipes/default.rb
+++ b/tools/devcloud4/common/binary-installation/recipes/default.rb
@@ -24,4 +24,4 @@
 
 include_recipe 'binary-installation::nfsshares'
 include_recipe 'binary-installation::database_server'
-include_recipe 'binary-installation::management_server'
\ No newline at end of file
+include_recipe 'binary-installation::management_server'
diff --git a/tools/devcloud4/common/development-installation/attributes/default.rb b/tools/devcloud4/common/development-installation/attributes/default.rb
index 705423b..f2c5712 100644
--- a/tools/devcloud4/common/development-installation/attributes/default.rb
+++ b/tools/devcloud4/common/development-installation/attributes/default.rb
@@ -26,4 +26,4 @@
 default['cloudstack']['primary']['mgt_path'] = node['cloudstack']['primary']['path']
 
 default['cloudstack']['cloud-install-sys-tmplt'] = "#{Chef::Config['file_cache_path']}/cloud-install-sys-tmplt"
-default['cloudstack']['createtmplt'] = "#{Chef::Config['file_cache_path']}/createtmplt.sh"
\ No newline at end of file
+default['cloudstack']['createtmplt'] = "#{Chef::Config['file_cache_path']}/createtmplt.sh"
diff --git a/tools/devcloud4/common/development-installation/recipes/database_server.rb b/tools/devcloud4/common/development-installation/recipes/database_server.rb
index 28a374c..b9341a2 100644
--- a/tools/devcloud4/common/development-installation/recipes/database_server.rb
+++ b/tools/devcloud4/common/development-installation/recipes/database_server.rb
@@ -21,4 +21,3 @@
 include_recipe 'mysql::client'
 
 include_recipe 'cloudstack::mysql_conf'
-
diff --git a/tools/devcloud4/common/development-installation/recipes/default.rb b/tools/devcloud4/common/development-installation/recipes/default.rb
index 617acc7..188d923 100644
--- a/tools/devcloud4/common/development-installation/recipes/default.rb
+++ b/tools/devcloud4/common/development-installation/recipes/default.rb
@@ -24,4 +24,4 @@
 
 include_recipe 'development-installation::nfsshares'
 include_recipe 'development-installation::system_templates'
-include_recipe 'development-installation::database_server'
\ No newline at end of file
+include_recipe 'development-installation::database_server'
diff --git a/tools/devcloud4/common/development-installation/recipes/system_templates.rb b/tools/devcloud4/common/development-installation/recipes/system_templates.rb
index 7723f26..9601e7b 100644
--- a/tools/devcloud4/common/development-installation/recipes/system_templates.rb
+++ b/tools/devcloud4/common/development-installation/recipes/system_templates.rb
@@ -35,4 +35,4 @@
   nfs_server node['cloudstack']['secondary']['host']
   url node['cloudstack']['hypervisor_tpl']['xenserver']
   action :create
-end
\ No newline at end of file
+end
diff --git a/tools/devcloud4/pom.xml b/tools/devcloud4/pom.xml
index adf5933..6e31176 100644
--- a/tools/devcloud4/pom.xml
+++ b/tools/devcloud4/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-tools</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/tools/devcloud4/prefill.sql b/tools/devcloud4/prefill.sql
index d06de50..4213cd9 100644
--- a/tools/devcloud4/prefill.sql
+++ b/tools/devcloud4/prefill.sql
@@ -31,4 +31,4 @@
 REPLACE INTO `cloud`.`configuration` (instance, name, value) VALUE('DEFAULT', 'expunge.interval', '60');
 REPLACE INTO `cloud`.`configuration` (instance, name, value) VALUE('DEFAULT', 'management.network.cidr', '0.0.0.0/0');
 REPLACE INTO `cloud`.`configuration` (instance, name, value) VALUE('DEFAULT', 'secstorage.allowed.internal.sites', '0.0.0.0/0');
-UPDATE `cloud`.`vm_template` SET unique_name="Macchinina",name="Macchinina",url="http://dl.openvm.eu/cloudstack/macchinina/x86_64/macchinina-xen.vhd.bz2",checksum="30985504bc31bf0cd3b9d2c6ca7944d3",display_text="Macchinina" where id=5;
\ No newline at end of file
+UPDATE `cloud`.`vm_template` SET unique_name="Macchinina",name="Macchinina",url="http://dl.openvm.eu/cloudstack/macchinina/x86_64/macchinina-xen.vhd.bz2",checksum="30985504bc31bf0cd3b9d2c6ca7944d3",display_text="Macchinina" where id=5;
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile
index 5b132f2..9c135b0 100644
--- a/tools/docker/Dockerfile
+++ b/tools/docker/Dockerfile
@@ -20,7 +20,7 @@
 FROM ubuntu:22.04
 
 MAINTAINER "Apache CloudStack" <dev@cloudstack.apache.org>
-LABEL Vendor="Apache.org" License="ApacheV2" Version="4.18.1.0"
+LABEL Vendor="Apache.org" License="ApacheV2" Version="4.19.0.0"
 
 ARG DEBIAN_FRONTEND=noninteractive
 
diff --git a/tools/docker/Dockerfile.marvin b/tools/docker/Dockerfile.marvin
index f0329fa..3faf721 100644
--- a/tools/docker/Dockerfile.marvin
+++ b/tools/docker/Dockerfile.marvin
@@ -20,11 +20,11 @@
 FROM python:2
 
 MAINTAINER "Apache CloudStack" <dev@cloudstack.apache.org>
-LABEL Vendor="Apache.org" License="ApacheV2" Version="4.18.1.0"
+LABEL Vendor="Apache.org" License="ApacheV2" Version="4.19.0.0"
 
 ENV WORK_DIR=/marvin
 
-ENV PKG_URL=https://builds.cloudstack.org/job/build-master-marvin/lastSuccessfulBuild/artifact/tools/marvin/dist/Marvin-4.18.1.0-SNAPSHOT.tar.gz
+ENV PKG_URL=https://builds.cloudstack.org/job/build-master-marvin/lastSuccessfulBuild/artifact/tools/marvin/dist/Marvin-4.19.0.0-SNAPSHOT.tar.gz
 
 RUN apt-get update && apt-get install -y vim
 RUN pip install --upgrade paramiko nose requests
diff --git a/tools/docker/Dockerfile.smokedev b/tools/docker/Dockerfile.smokedev
index 881e100..4476f6a 100644
--- a/tools/docker/Dockerfile.smokedev
+++ b/tools/docker/Dockerfile.smokedev
@@ -140,4 +140,4 @@
 #
 # cat /root/docker_run_tests.sh
 # for instructions
-#
\ No newline at end of file
+#
diff --git a/tools/eclipse/set-eclipse-profile.sh b/tools/eclipse/set-eclipse-profile.sh
index c0cc9a9..70dc8d4 100644
--- a/tools/eclipse/set-eclipse-profile.sh
+++ b/tools/eclipse/set-eclipse-profile.sh
@@ -23,4 +23,4 @@
 	echo Replacing $file; 
     sed -i -e s/activeProfiles=/activeProfiles=eclipse/g $file;
   fi; 
-done
\ No newline at end of file
+done
diff --git a/tools/git/prepare-commit-msg b/tools/git/prepare-commit-msg
index f957c18..dd801b0 100755
--- a/tools/git/prepare-commit-msg
+++ b/tools/git/prepare-commit-msg
@@ -101,4 +101,3 @@
   run_generic_commit $1
   ;;
 esac
-
diff --git a/tools/marvin/marvin/lib/base.py b/tools/marvin/marvin/lib/base.py
index 9d28d5a..5906d2f 100755
--- a/tools/marvin/marvin/lib/base.py
+++ b/tools/marvin/marvin/lib/base.py
@@ -108,6 +108,8 @@
             cmd.roleid = services["roleid"]
         if "description" in services:
             cmd.description = services["description"]
+        if "ispublic" in services:
+            cmd.ispublic = services["ispublic"]
 
         return Role(apiclient.createRole(cmd).__dict__)
 
@@ -122,6 +124,8 @@
             cmd.description = services["description"]
         if "forced" in services:
             cmd.type = services["forced"]
+        if "ispublic" in services:
+            cmd.ispublic = services["ispublic"]
 
         return Role(apiclient.importRole(cmd).__dict__)
 
@@ -3481,7 +3485,8 @@
                networkofferingid=None, projectid=None,
                subdomainaccess=None, zoneid=None,
                gateway=None, netmask=None, vpcid=None, aclid=None, vlan=None,
-               externalid=None, bypassvlanoverlapcheck=None, associatednetworkid=None, publicmtu=None, privatemtu=None):
+               externalid=None, bypassvlanoverlapcheck=None, associatednetworkid=None, publicmtu=None, privatemtu=None,
+               sourcenatipaddress=None):
         """Create Network for account"""
         cmd = createNetwork.createNetworkCmd()
         cmd.name = services["name"]
@@ -3563,6 +3568,8 @@
             cmd.publicmtu = publicmtu
         if privatemtu:
             cmd.privatemtu = privatemtu
+        if sourcenatipaddress:
+            cmd.sourcenatipaddress = sourcenatipaddress
         return Network(apiclient.createNetwork(cmd).__dict__)
 
     def delete(self, apiclient):
@@ -6514,3 +6521,182 @@
         cmd.policyuuid = policyuuid
         cmd.ruleuuid = ruleuuid
         return apiclient.removeTungstenFabricPolicyRule(cmd)
+
+class GuestOSCategory:
+    """Manage Guest OS Categories"""
+
+    def __init__(self, items, services):
+        self.__dict__.update(items)
+
+    @classmethod
+    def list(cls, apiclient, id=None, name=None, **kwargs):
+        """List all Guest OS categories"""
+        cmd = listOsCategories.listOsCategoriesCmd()
+        [setattr(cmd, k, v) for k, v in list(kwargs.items())]
+        if 'account' in list(kwargs.keys()) and 'domainid' in list(kwargs.keys()):
+            cmd.listall = True
+        if id is not None:
+            cmd.id = id
+        if name is not None:
+            cmd.name = name
+
+        return (apiclient.listOsCategories(cmd))
+
+class GuestOS:
+    """Manage Guest OS"""
+
+    def __init__(self, items, services):
+        self.__dict__.update(items)
+
+    @classmethod
+    def add(cls, apiclient, osdisplayname=None,
+                  oscategoryid=None, name=None, details=None):
+        """Add Guest OS"""
+        cmd = addGuestOs.addGuestOsCmd()
+        cmd.osdisplayname = osdisplayname
+        cmd.oscategoryid = oscategoryid
+        if name is not None:
+            cmd.name = name
+        if details is not None:
+            cmd.details = details
+
+        return (apiclient.addGuestOs(cmd))
+
+    @classmethod
+    def remove(cls, apiclient, id):
+        """Remove Guest OS"""
+        cmd = removeGuestOs.removeGuestOsCmd()
+        cmd.id = id
+
+        return apiclient.removeGuestOs(cmd)
+
+    @classmethod
+    def update(cls, apiclient, id, osdisplayname=None, details=None):
+        """Update Guest OS"""
+        cmd = updateGuestOs.updateGuestOsCmd()
+        cmd.id = id
+        cmd.osdisplayname = osdisplayname
+        if details is not None:
+            cmd.details = details
+
+        return apiclient.updateGuestOs(cmd)
+
+    @classmethod
+    def list(cls, apiclient, id=None, oscategoryid=None, description=None, **kwargs):
+        """List all Guest OS"""
+        cmd = listOsTypes.listOsTypesCmd()
+        [setattr(cmd, k, v) for k, v in list(kwargs.items())]
+        if 'account' in list(kwargs.keys()) and 'domainid' in list(kwargs.keys()):
+            cmd.listall = True
+        if id is not None:
+            cmd.id = id
+        if oscategoryid is not None:
+            cmd.oscategoryid = oscategoryid
+        if description is not None:
+            cmd.description = description
+
+        return (apiclient.listOsTypes(cmd))
+
+class GuestOsMapping:
+    """Manage Guest OS Mappings"""
+
+    def __init__(self, items, services):
+        self.__dict__.update(items)
+
+    @classmethod
+    def add(cls, apiclient, ostypeid=None,
+                  hypervisor=None, hypervisorversion=None,
+                  osnameforhypervisor=None, osmappingcheckenabled=None, forced=None):
+        """Add Guest OS mapping"""
+        cmd = addGuestOsMapping.addGuestOsMappingCmd()
+        cmd.ostypeid = ostypeid
+        cmd.hypervisor = hypervisor
+        cmd.hypervisorversion = hypervisorversion
+        cmd.osnameforhypervisor = osnameforhypervisor
+        if osmappingcheckenabled is not None:
+            cmd.osmappingcheckenabled = osmappingcheckenabled
+        if forced is not None:
+            cmd.forced = forced
+
+        return (apiclient.addGuestOsMapping(cmd))
+
+    @classmethod
+    def remove(cls, apiclient, id):
+        """Remove Guest OS mapping"""
+        cmd = removeGuestOsMapping.removeGuestOsMappingCmd()
+        cmd.id = id
+
+        return apiclient.removeGuestOsMapping(cmd)
+
+    @classmethod
+    def update(cls, apiclient, id, osnameforhypervisor=None, osmappingcheckenabled=None):
+        """Update Guest OS mapping"""
+        cmd = updateGuestOsMapping.updateGuestOsMappingCmd()
+        cmd.id = id
+        cmd.osnameforhypervisor = osnameforhypervisor
+        if osmappingcheckenabled is not None:
+            cmd.osmappingcheckenabled = osmappingcheckenabled
+
+        return apiclient.updateGuestOsMapping(cmd)
+
+    @classmethod
+    def list(cls, apiclient, id=None, ostypeid=None, osdisplayname=None,
+             osnameforhypervisor=None, hypervisor=None, hypervisorversion=None, **kwargs):
+        """List all Guest OS mappings"""
+        cmd = listGuestOsMapping.listGuestOsMappingCmd()
+        [setattr(cmd, k, v) for k, v in list(kwargs.items())]
+        if 'account' in list(kwargs.keys()) and 'domainid' in list(kwargs.keys()):
+            cmd.listall = True
+        if id is not None:
+            cmd.id = id
+        if ostypeid is not None:
+            cmd.ostypeid = ostypeid
+        if osdisplayname is not None:
+            cmd.osdisplayname = osdisplayname
+        if osnameforhypervisor is not None:
+            cmd.osnameforhypervisor = osnameforhypervisor
+        if hypervisor is not None:
+            cmd.hypervisor = hypervisor
+        if hypervisorversion is not None:
+            cmd.hypervisorversion = hypervisorversion
+
+        return (apiclient.listGuestOsMapping(cmd))
+
+class VMSchedule:
+
+    def __init__(self, items):
+        self.__dict__.update(items)
+
+    @classmethod
+    def create(cls, apiclient, virtualmachineid, action, schedule, timezone, startdate, enabled=False, description=None, enddate=None):
+        cmd = createVMSchedule.createVMScheduleCmd()
+        cmd.virtualmachineid = virtualmachineid
+        cmd.description = description
+        cmd.action = action
+        cmd.schedule = schedule
+        cmd.timezone = timezone
+        cmd.startdate = startdate
+        cmd.enddate = enddate
+        cmd.enabled = enabled
+        return VMSchedule(apiclient.createVMSchedule(cmd).__dict__)
+
+    @classmethod
+    def list(cls, apiclient, virtualmachineid, id=None, enabled=None, action=None):
+        cmd = listVMSchedule.listVMScheduleCmd()
+        cmd.virtualmachineid = virtualmachineid
+        cmd.id = id
+        cmd.enabled = enabled
+        cmd.action = action
+        return apiclient.listVMSchedule(cmd)
+
+    def update(self, apiclient, **kwargs):
+        cmd = updateVMSchedule.updateVMScheduleCmd()
+        cmd.id = self.id
+        [setattr(cmd, k, v) for k, v in list(kwargs.items())]
+        return apiclient.updateVMSchedule(cmd)
+
+    def delete(self, apiclient):
+        cmd = deleteVMSchedule.deleteVMScheduleCmd()
+        cmd.id = self.id
+        cmd.virtualmachineid = self.virtualmachineid
+        return (apiclient.deleteVMSchedule(cmd))
diff --git a/tools/marvin/marvin/lib/common.py b/tools/marvin/marvin/lib/common.py
index f1f09bb..cc77365 100644
--- a/tools/marvin/marvin/lib/common.py
+++ b/tools/marvin/marvin/lib/common.py
@@ -58,6 +58,7 @@
                                   listNetworkOfferings,
                                   listResourceLimits,
                                   listVPCOfferings,
+                                  listManagementServers,
                                   migrateSystemVm)
 from marvin.sshClient import SshClient
 from marvin.codes import (PASS, FAILED, ISOLATED_NETWORK, VPC_NETWORK,
@@ -1056,6 +1057,14 @@
         cmd.listall=True
     return(apiclient.listVPCOfferings(cmd))
 
+def list_mgmt_servers(apiclient, **kwargs):
+    """ Lists Management Servers """
+
+    cmd = listManagementServers.listManagementServersCmd()
+    [setattr(cmd, k, v) for k, v in list(kwargs.items())]
+    if 'account' in list(kwargs.keys()) and 'domainid' in list(kwargs.keys()):
+        cmd.listall=True
+    return(apiclient.listManagementServers(cmd))
 
 def update_resource_count(apiclient, domainid, accountid=None,
                           projectid=None, rtype=None):
diff --git a/tools/marvin/marvin/lib/utils.py b/tools/marvin/marvin/lib/utils.py
index bc4d15c..d3cbd42 100644
--- a/tools/marvin/marvin/lib/utils.py
+++ b/tools/marvin/marvin/lib/utils.py
@@ -288,6 +288,18 @@
     assert hosts_list_validation_result[0] == PASS, "host list validation failed"
     return hosts_list_validation_result[1].hypervisor
 
+def get_hypervisor_version(apiclient):
+
+    """Return the hypervisor type of the hosts in setup"""
+
+    cmd = listHosts.listHostsCmd()
+    cmd.type = 'Routing'
+    cmd.listall = True
+    hosts = apiclient.listHosts(cmd)
+    hosts_list_validation_result = validateList(hosts)
+    assert hosts_list_validation_result[0] == PASS, "host list validation failed"
+    return hosts_list_validation_result[1].hypervisorversion
+
 def is_snapshot_on_nfs(apiclient, dbconn, config, zoneid, snapshotid):
     """
     Checks whether a snapshot with id (not UUID) `snapshotid` is present on the nfs storage
diff --git a/tools/marvin/marvin/misc/build/vm-start.sh b/tools/marvin/marvin/misc/build/vm-start.sh
index e23f434..86d7cc5b 100755
--- a/tools/marvin/marvin/misc/build/vm-start.sh
+++ b/tools/marvin/marvin/misc/build/vm-start.sh
@@ -53,4 +53,3 @@
 #Minimum mem requirements for RHEL/Ubuntu
 $(xe vm-memory-limits-set  static-min=1GiB static-max=1GiB dynamic-min=1GiB dynamic-max=1GiB uuid=$vmuuid)
 $(xe vm-start uuid=$vmuuid)
-
diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml
index 84da98a..334d0b3 100644
--- a/tools/marvin/pom.xml
+++ b/tools/marvin/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloud-tools</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
diff --git a/tools/marvin/setup.py b/tools/marvin/setup.py
index 3ceb275..e96065f 100644
--- a/tools/marvin/setup.py
+++ b/tools/marvin/setup.py
@@ -27,7 +27,7 @@
         raise RuntimeError("python setuptools is required to build Marvin")
 
 
-VERSION = "4.18.1.0"
+VERSION = "4.19.0.0"
 
 setup(name="Marvin",
       version=VERSION,
diff --git a/tools/ngui/static/bootstrap/js/bootstrap.min.js b/tools/ngui/static/bootstrap/js/bootstrap.min.js
index 319a85d..8f130f0 100644
--- a/tools/ngui/static/bootstrap/js/bootstrap.min.js
+++ b/tools/ngui/static/bootstrap/js/bootstrap.min.js
@@ -4,4 +4,4 @@
 * Copyright 2012 Twitter, Inc.
 * http://www.apache.org/licenses/LICENSE-2.0.txt
 */
-!function(a){a(function(){a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in").attr("aria-hidden",!1),b.enforceFocus(),c?b.$element.one(a.support.transition.end,function(){b.$element.focus().trigger("shown")}):b.$element.focus().trigger("shown")})},hide:function(b){b&&b.preventDefault();var c=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,this.escape(),a(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),a.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var b=this;a(document).on("focusin.modal",function(a){b.$element[0]!==a.target&&!b.$element.has(a.target).length&&b.$element.focus()})},escape:function(){var a=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(b){b.which==27&&a.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),b.hideModal()},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),b.hideModal()})},hideModal:function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?a.proxy(this.$element[0].focus,this.$element[0]):a.proxy(this.hide,this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!b)return;e?this.$backdrop.one(a.support.transition.end,b):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b):b()):b&&b()}};var c=a.fn.modal;a.fn.modal=function(c){return this.each(function(){var d=a(this),e=d.data("modal"),f=a.extend({},a.fn.modal.defaults,d.data(),typeof c=="object"&&c);e||d.data("modal",e=new b(this,f)),typeof c=="string"?e[c]():f.show&&e.show()})},a.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());b.preventDefault(),e.modal(f).one("hide",function(){c.focus()})})}(window.jQuery),!function(a){function d(){a(".dropdown-backdrop").remove(),a(b).each(function(){e(a(this)).removeClass("open")})}function e(b){var c=b.attr("data-target"),d;c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,"")),d=c&&a(c);if(!d||!d.length)d=b.parent();return d}var b="[data-toggle=dropdown]",c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),f,g;if(c.is(".disabled, :disabled"))return;return f=e(c),g=f.hasClass("open"),d(),g||("ontouchstart"in document.documentElement&&a('<div class="dropdown-backdrop"/>').insertBefore(a(this)).on("click",d),f.toggleClass("open")),c.focus(),!1},keydown:function(c){var d,f,g,h,i,j;if(!/(38|40|27)/.test(c.keyCode))return;d=a(this),c.preventDefault(),c.stopPropagation();if(d.is(".disabled, :disabled"))return;h=e(d),i=h.hasClass("open");if(!i||i&&c.keyCode==27)return c.which==27&&h.find(b).focus(),d.click();f=a("[role=menu] li:not(.divider):visible a",h);if(!f.length)return;j=f.index(f.filter(":focus")),c.keyCode==38&&j>0&&j--,c.keyCode==40&&j<f.length-1&&j++,~j||(j=0),f.eq(j).focus()}};var f=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=f,this},a(document).on("click.dropdown.data-api",d).on("click.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.dropdown.data-api",b,c.prototype.toggle).on("keydown.dropdown.data-api",b+", [role=menu]",c.prototype.keydown)}(window.jQuery),!function(a){function b(b,c){var d=a.proxy(this.process,this),e=a(b).is("body")?a(window):a(b),f;this.options=a.extend({},a.fn.scrollspy.defaults,c),this.$scrollElement=e.on("scroll.scroll-spy.data-api",d),this.selector=(this.options.target||(f=a(b).attr("href"))&&f.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=a("body"),this.refresh(),this.process()}b.prototype={constructor:b,refresh:function(){var b=this,c;this.offsets=a([]),this.targets=a([]),c=this.$body.find(this.selector).map(function(){var c=a(this),d=c.data("target")||c.attr("href"),e=/^#\w/.test(d)&&a(d);return e&&e.length&&[[e.position().top+(!a.isWindow(b.$scrollElement.get(0))&&b.$scrollElement.scrollTop()),d]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},process:function(){var a=this.$scrollElement.scrollTop()+this.options.offset,b=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,c=b-this.$scrollElement.height(),d=this.offsets,e=this.targets,f=this.activeTarget,g;if(a>=c)return f!=(g=e.last()[0])&&this.activate(g);for(g=d.length;g--;)f!=e[g]&&a>=d[g]&&(!d[g+1]||a<=d[g+1])&&this.activate(e[g])},activate:function(b){var c,d;this.activeTarget=b,a(this.selector).parent(".active").removeClass("active"),d=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',c=a(d).parent("li").addClass("active"),c.parent(".dropdown-menu").length&&(c=c.closest("li.dropdown").addClass("active")),c.trigger("activate")}};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("scrollspy"),f=typeof c=="object"&&c;e||d.data("scrollspy",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.defaults={offset:10},a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery),!function(a){var b=function(b){this.element=a(b)};b.prototype={constructor:b,show:function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.attr("data-target"),e,f,g;d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,""));if(b.parent("li").hasClass("active"))return;e=c.find(".active:last a")[0],g=a.Event("show",{relatedTarget:e}),b.trigger(g);if(g.isDefaultPrevented())return;f=a(d),this.activate(b.parent("li"),c),this.activate(f,f.parent(),function(){b.trigger({type:"shown",relatedTarget:e})})},activate:function(b,c,d){function g(){e.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),f?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var e=c.find("> .active"),f=d&&a.support.transition&&e.hasClass("fade");f?e.one(a.support.transition.end,g):g(),e.removeClass("in")}};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("tab");e||d.data("tab",e=new b(this)),typeof c=="string"&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(window.jQuery),!function(a){var b=function(a,b){this.init("tooltip",a,b)};b.prototype={constructor:b,init:function(b,c,d){var e,f,g,h,i;this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.enabled=!0,g=this.options.trigger.split(" ");for(i=g.length;i--;)h=g[i],h=="click"?this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this)):h!="manual"&&(e=h=="hover"?"mouseenter":"focus",f=h=="hover"?"mouseleave":"blur",this.$element.on(e+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(f+"."+this.type,this.options.selector,a.proxy(this.leave,this)));this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(b){return b=a.extend({},a.fn[this.type].defaults,this.$element.data(),b),b.delay&&typeof b.delay=="number"&&(b.delay={show:b.delay,hide:b.delay}),b},enter:function(b){var c=a.fn[this.type].defaults,d={},e;this._options&&a.each(this._options,function(a,b){c[a]!=b&&(d[a]=b)},this),e=a(b.currentTarget)[this.type](d).data(this.type);if(!e.options.delay||!e.options.delay.show)return e.show();clearTimeout(this.timeout),e.hoverState="in",this.timeout=setTimeout(function(){e.hoverState=="in"&&e.show()},e.options.delay.show)},leave:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!c.options.delay||!c.options.delay.hide)return c.hide();c.hoverState="out",this.timeout=setTimeout(function(){c.hoverState=="out"&&c.hide()},c.options.delay.hide)},show:function(){var b,c,d,e,f,g,h=a.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(h);if(h.isDefaultPrevented())return;b=this.tip(),this.setContent(),this.options.animation&&b.addClass("fade"),f=typeof this.options.placement=="function"?this.options.placement.call(this,b[0],this.$element[0]):this.options.placement,b.detach().css({top:0,left:0,display:"block"}),this.options.container?b.appendTo(this.options.container):b.insertAfter(this.$element),c=this.getPosition(),d=b[0].offsetWidth,e=b[0].offsetHeight;switch(f){case"bottom":g={top:c.top+c.height,left:c.left+c.width/2-d/2};break;case"top":g={top:c.top-e,left:c.left+c.width/2-d/2};break;case"left":g={top:c.top+c.height/2-e/2,left:c.left-d};break;case"right":g={top:c.top+c.height/2-e/2,left:c.left+c.width}}this.applyPlacement(g,f),this.$element.trigger("shown")}},applyPlacement:function(a,b){var c=this.tip(),d=c[0].offsetWidth,e=c[0].offsetHeight,f,g,h,i;c.offset(a).addClass(b).addClass("in"),f=c[0].offsetWidth,g=c[0].offsetHeight,b=="top"&&g!=e&&(a.top=a.top+e-g,i=!0),b=="bottom"||b=="top"?(h=0,a.left<0&&(h=a.left*-2,a.left=0,c.offset(a),f=c[0].offsetWidth,g=c[0].offsetHeight),this.replaceArrow(h-d+f,f,"left")):this.replaceArrow(g-e,g,"top"),i&&c.offset(a)},replaceArrow:function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},setContent:function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},hide:function(){function e(){var b=setTimeout(function(){c.off(a.support.transition.end).detach()},500);c.one(a.support.transition.end,function(){clearTimeout(b),c.detach()})}var b=this,c=this.tip(),d=a.Event("hide");this.$element.trigger(d);if(d.isDefaultPrevented())return;return c.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?e():c.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var a=this.$element;(a.attr("title")||typeof a.attr("data-original-title")!="string")&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var b=this.$element[0];return a.extend({},typeof b.getBoundingClientRect=="function"?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},getTitle:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||(typeof c.title=="function"?c.title.call(b[0]):c.title),a},tip:function(){return this.$tip=this.$tip||a(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(b){var c=b?a(b.currentTarget)[this.type](this._options).data(this.type):this;c.tip().hasClass("in")?c.hide():c.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("tooltip"),f=typeof c=="object"&&c;e||d.data("tooltip",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(window.jQuery),!function(a){var b=function(a,b){this.init("popover",a,b)};b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype,{constructor:b,setContent:function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var a,b=this.$element,c=this.options;return a=(typeof c.content=="function"?c.content.call(b[0]):c.content)||b.attr("data-content"),a},tip:function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("popover"),f=typeof c=="object"&&c;e||d.data("popover",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.defaults=a.extend({},a.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(window.jQuery),!function(a){var b=function(b,c){this.options=a.extend({},a.fn.affix.defaults,c),this.$window=a(window).on("scroll.affix.data-api",a.proxy(this.checkPosition,this)).on("click.affix.data-api",a.proxy(function(){setTimeout(a.proxy(this.checkPosition,this),1)},this)),this.$element=a(b),this.checkPosition()};b.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var b=a(document).height(),c=this.$window.scrollTop(),d=this.$element.offset(),e=this.options.offset,f=e.bottom,g=e.top,h="affix affix-top affix-bottom",i;typeof e!="object"&&(f=g=e),typeof g=="function"&&(g=e.top()),typeof f=="function"&&(f=e.bottom()),i=this.unpin!=null&&c+this.unpin<=d.top?!1:f!=null&&d.top+this.$element.height()>=b-f?"bottom":g!=null&&c<=g?"top":!1;if(this.affixed===i)return;this.affixed=i,this.unpin=i=="bottom"?d.top-c:null,this.$element.removeClass(h).addClass("affix"+(i?"-"+i:""))};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("affix"),f=typeof c=="object"&&c;e||d.data("affix",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.defaults={offset:0},a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(window.jQuery),!function(a){var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.alert.data-api",b,c.prototype.close)}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a+="Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle")})}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b,c,d,e;if(this.transitioning||this.$element.hasClass("in"))return;b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find("> .accordion-group > .in");if(d&&d.length){e=d.data("collapse");if(e&&e.transitioning)return;d.collapse("hide"),e||d.data("collapse",null)}this.$element[b](0),this.transition("addClass",a.Event("show"),"shown"),a.support.transition&&this.$element[b](this.$element[0][c])},hide:function(){var b;if(this.transitioning||!this.$element.hasClass("in"))return;b=this.dimension(),this.reset(this.$element[b]()),this.transition("removeClass",a.Event("hide"),"hidden"),this.$element[b](0)},reset:function(a){var b=this.dimension();return this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element[a!==null?"addClass":"removeClass"]("collapse"),this},transition:function(b,c,d){var e=this,f=function(){c.type=="show"&&e.reset(),e.transitioning=0,e.$element.trigger(d)};this.$element.trigger(c);if(c.isDefaultPrevented())return;this.transitioning=1,this.$element[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=a.extend({},a.fn.collapse.defaults,d.data(),typeof c=="object"&&c);e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();c[a(e).hasClass("in")?"addClass":"removeClass"]("collapsed"),a(e).collapse(f)})}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.options.pause=="hover"&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.prototype={cycle:function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(b){var c=this.getActiveIndex(),d=this;if(b>this.$items.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){d.to(b)}):c==b?this.pause().cycle():this.slide(b>c?"next":"prev",a(this.$items[b]))},pause:function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this,j;this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h](),j=a.Event("slide",{relatedTarget:e[0],direction:g});if(e.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")}));if(a.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(j);if(j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})}else{this.$element.trigger(j);if(j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=a.extend({},a.fn.carousel.defaults,typeof c=="object"&&c),g=typeof c=="string"?c:f.slide;e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.defaults={interval:5e3,pause:"hover"},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),c.data()),g;e.carousel(f),(g=c.attr("data-slide-to"))&&e.data("carousel").pause().to(g).cycle(),b.preventDefault()})}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=a(this.options.menu),this.shown=!1,this.listen()};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(a)).change(),this.hide()},updater:function(a){return a},show:function(){var b=a.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:b.top+b.height,left:b.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){var c;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(c=a.isFunction(this.source)?this.source(this.query,a.proxy(this.process,this)):this.source,c?this.process(c):this)},process:function(b){var c=this;return b=a.grep(b,function(a){return c.matcher(a)}),b=this.sorter(b),b.length?this.render(b.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(a){return~a.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){var b=[],c=[],d=[],e;while(e=a.shift())e.toLowerCase().indexOf(this.query.toLowerCase())?~e.indexOf(this.query)?c.push(e):d.push(e):b.push(e);return b.concat(c,d)},highlighter:function(a){var b=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return a.replace(new RegExp("("+b+")","ig"),function(a,b){return"<strong>"+b+"</strong>"})},render:function(b){var c=this;return b=a(b).map(function(b,d){return b=a(c.options.item).attr("data-value",d),b.find("a").html(c.highlighter(d)),b[0]}),b.first().addClass("active"),this.$menu.html(b),this},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("focus",a.proxy(this.focus,this)).on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",a.proxy(this.keydown,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this)).on("mouseleave","li",a.proxy(this.mouseleave,this))},eventSupported:function(a){var b=a in this.$element;return b||(this.$element.setAttribute(a,"return;"),b=typeof this.$element[a]=="function"),b},move:function(a){if(!this.shown)return;switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:a.preventDefault(),this.prev();break;case 40:a.preventDefault(),this.next()}a.stopPropagation()},keydown:function(b){this.suppressKeyPressRepeat=~a.inArray(b.keyCode,[40,38,9,13,27]),this.move(b)},keypress:function(a){if(this.suppressKeyPressRepeat)return;this.move(a)},keyup:function(a){switch(a.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}a.stopPropagation(),a.preventDefault()},focus:function(a){this.focused=!0},blur:function(a){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(a){a.stopPropagation(),a.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(b){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")},mouseleave:function(a){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var c=a.fn.typeahead;a.fn.typeahead=function(c){return this.each(function(){var d=a(this),e=d.data("typeahead"),f=typeof c=="object"&&c;e||d.data("typeahead",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},a.fn.typeahead.Constructor=b,a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this},a(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);if(c.data("typeahead"))return;c.typeahead(c.data())})}(window.jQuery)
\ No newline at end of file
+!function(a){a(function(){a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in").attr("aria-hidden",!1),b.enforceFocus(),c?b.$element.one(a.support.transition.end,function(){b.$element.focus().trigger("shown")}):b.$element.focus().trigger("shown")})},hide:function(b){b&&b.preventDefault();var c=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,this.escape(),a(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),a.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var b=this;a(document).on("focusin.modal",function(a){b.$element[0]!==a.target&&!b.$element.has(a.target).length&&b.$element.focus()})},escape:function(){var a=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(b){b.which==27&&a.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),b.hideModal()},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),b.hideModal()})},hideModal:function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?a.proxy(this.$element[0].focus,this.$element[0]):a.proxy(this.hide,this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!b)return;e?this.$backdrop.one(a.support.transition.end,b):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b):b()):b&&b()}};var c=a.fn.modal;a.fn.modal=function(c){return this.each(function(){var d=a(this),e=d.data("modal"),f=a.extend({},a.fn.modal.defaults,d.data(),typeof c=="object"&&c);e||d.data("modal",e=new b(this,f)),typeof c=="string"?e[c]():f.show&&e.show()})},a.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());b.preventDefault(),e.modal(f).one("hide",function(){c.focus()})})}(window.jQuery),!function(a){function d(){a(".dropdown-backdrop").remove(),a(b).each(function(){e(a(this)).removeClass("open")})}function e(b){var c=b.attr("data-target"),d;c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,"")),d=c&&a(c);if(!d||!d.length)d=b.parent();return d}var b="[data-toggle=dropdown]",c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),f,g;if(c.is(".disabled, :disabled"))return;return f=e(c),g=f.hasClass("open"),d(),g||("ontouchstart"in document.documentElement&&a('<div class="dropdown-backdrop"/>').insertBefore(a(this)).on("click",d),f.toggleClass("open")),c.focus(),!1},keydown:function(c){var d,f,g,h,i,j;if(!/(38|40|27)/.test(c.keyCode))return;d=a(this),c.preventDefault(),c.stopPropagation();if(d.is(".disabled, :disabled"))return;h=e(d),i=h.hasClass("open");if(!i||i&&c.keyCode==27)return c.which==27&&h.find(b).focus(),d.click();f=a("[role=menu] li:not(.divider):visible a",h);if(!f.length)return;j=f.index(f.filter(":focus")),c.keyCode==38&&j>0&&j--,c.keyCode==40&&j<f.length-1&&j++,~j||(j=0),f.eq(j).focus()}};var f=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=f,this},a(document).on("click.dropdown.data-api",d).on("click.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.dropdown.data-api",b,c.prototype.toggle).on("keydown.dropdown.data-api",b+", [role=menu]",c.prototype.keydown)}(window.jQuery),!function(a){function b(b,c){var d=a.proxy(this.process,this),e=a(b).is("body")?a(window):a(b),f;this.options=a.extend({},a.fn.scrollspy.defaults,c),this.$scrollElement=e.on("scroll.scroll-spy.data-api",d),this.selector=(this.options.target||(f=a(b).attr("href"))&&f.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=a("body"),this.refresh(),this.process()}b.prototype={constructor:b,refresh:function(){var b=this,c;this.offsets=a([]),this.targets=a([]),c=this.$body.find(this.selector).map(function(){var c=a(this),d=c.data("target")||c.attr("href"),e=/^#\w/.test(d)&&a(d);return e&&e.length&&[[e.position().top+(!a.isWindow(b.$scrollElement.get(0))&&b.$scrollElement.scrollTop()),d]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},process:function(){var a=this.$scrollElement.scrollTop()+this.options.offset,b=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,c=b-this.$scrollElement.height(),d=this.offsets,e=this.targets,f=this.activeTarget,g;if(a>=c)return f!=(g=e.last()[0])&&this.activate(g);for(g=d.length;g--;)f!=e[g]&&a>=d[g]&&(!d[g+1]||a<=d[g+1])&&this.activate(e[g])},activate:function(b){var c,d;this.activeTarget=b,a(this.selector).parent(".active").removeClass("active"),d=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',c=a(d).parent("li").addClass("active"),c.parent(".dropdown-menu").length&&(c=c.closest("li.dropdown").addClass("active")),c.trigger("activate")}};var c=a.fn.scrollspy;a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("scrollspy"),f=typeof c=="object"&&c;e||d.data("scrollspy",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.defaults={offset:10},a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=c,this},a(window).on("load",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery),!function(a){var b=function(b){this.element=a(b)};b.prototype={constructor:b,show:function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.attr("data-target"),e,f,g;d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,""));if(b.parent("li").hasClass("active"))return;e=c.find(".active:last a")[0],g=a.Event("show",{relatedTarget:e}),b.trigger(g);if(g.isDefaultPrevented())return;f=a(d),this.activate(b.parent("li"),c),this.activate(f,f.parent(),function(){b.trigger({type:"shown",relatedTarget:e})})},activate:function(b,c,d){function g(){e.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),f?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var e=c.find("> .active"),f=d&&a.support.transition&&e.hasClass("fade");f?e.one(a.support.transition.end,g):g(),e.removeClass("in")}};var c=a.fn.tab;a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("tab");e||d.data("tab",e=new b(this)),typeof c=="string"&&e[c]()})},a.fn.tab.Constructor=b,a.fn.tab.noConflict=function(){return a.fn.tab=c,this},a(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})}(window.jQuery),!function(a){var b=function(a,b){this.init("tooltip",a,b)};b.prototype={constructor:b,init:function(b,c,d){var e,f,g,h,i;this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.enabled=!0,g=this.options.trigger.split(" ");for(i=g.length;i--;)h=g[i],h=="click"?this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this)):h!="manual"&&(e=h=="hover"?"mouseenter":"focus",f=h=="hover"?"mouseleave":"blur",this.$element.on(e+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(f+"."+this.type,this.options.selector,a.proxy(this.leave,this)));this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(b){return b=a.extend({},a.fn[this.type].defaults,this.$element.data(),b),b.delay&&typeof b.delay=="number"&&(b.delay={show:b.delay,hide:b.delay}),b},enter:function(b){var c=a.fn[this.type].defaults,d={},e;this._options&&a.each(this._options,function(a,b){c[a]!=b&&(d[a]=b)},this),e=a(b.currentTarget)[this.type](d).data(this.type);if(!e.options.delay||!e.options.delay.show)return e.show();clearTimeout(this.timeout),e.hoverState="in",this.timeout=setTimeout(function(){e.hoverState=="in"&&e.show()},e.options.delay.show)},leave:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!c.options.delay||!c.options.delay.hide)return c.hide();c.hoverState="out",this.timeout=setTimeout(function(){c.hoverState=="out"&&c.hide()},c.options.delay.hide)},show:function(){var b,c,d,e,f,g,h=a.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(h);if(h.isDefaultPrevented())return;b=this.tip(),this.setContent(),this.options.animation&&b.addClass("fade"),f=typeof this.options.placement=="function"?this.options.placement.call(this,b[0],this.$element[0]):this.options.placement,b.detach().css({top:0,left:0,display:"block"}),this.options.container?b.appendTo(this.options.container):b.insertAfter(this.$element),c=this.getPosition(),d=b[0].offsetWidth,e=b[0].offsetHeight;switch(f){case"bottom":g={top:c.top+c.height,left:c.left+c.width/2-d/2};break;case"top":g={top:c.top-e,left:c.left+c.width/2-d/2};break;case"left":g={top:c.top+c.height/2-e/2,left:c.left-d};break;case"right":g={top:c.top+c.height/2-e/2,left:c.left+c.width}}this.applyPlacement(g,f),this.$element.trigger("shown")}},applyPlacement:function(a,b){var c=this.tip(),d=c[0].offsetWidth,e=c[0].offsetHeight,f,g,h,i;c.offset(a).addClass(b).addClass("in"),f=c[0].offsetWidth,g=c[0].offsetHeight,b=="top"&&g!=e&&(a.top=a.top+e-g,i=!0),b=="bottom"||b=="top"?(h=0,a.left<0&&(h=a.left*-2,a.left=0,c.offset(a),f=c[0].offsetWidth,g=c[0].offsetHeight),this.replaceArrow(h-d+f,f,"left")):this.replaceArrow(g-e,g,"top"),i&&c.offset(a)},replaceArrow:function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},setContent:function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},hide:function(){function e(){var b=setTimeout(function(){c.off(a.support.transition.end).detach()},500);c.one(a.support.transition.end,function(){clearTimeout(b),c.detach()})}var b=this,c=this.tip(),d=a.Event("hide");this.$element.trigger(d);if(d.isDefaultPrevented())return;return c.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?e():c.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var a=this.$element;(a.attr("title")||typeof a.attr("data-original-title")!="string")&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var b=this.$element[0];return a.extend({},typeof b.getBoundingClientRect=="function"?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},getTitle:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||(typeof c.title=="function"?c.title.call(b[0]):c.title),a},tip:function(){return this.$tip=this.$tip||a(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(b){var c=b?a(b.currentTarget)[this.type](this._options).data(this.type):this;c.tip().hasClass("in")?c.hide():c.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("tooltip"),f=typeof c=="object"&&c;e||d.data("tooltip",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(window.jQuery),!function(a){var b=function(a,b){this.init("popover",a,b)};b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype,{constructor:b,setContent:function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"html":"text"](c),a.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var a,b=this.$element,c=this.options;return a=(typeof c.content=="function"?c.content.call(b[0]):c.content)||b.attr("data-content"),a},tip:function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("popover"),f=typeof c=="object"&&c;e||d.data("popover",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.defaults=a.extend({},a.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(window.jQuery),!function(a){var b=function(b,c){this.options=a.extend({},a.fn.affix.defaults,c),this.$window=a(window).on("scroll.affix.data-api",a.proxy(this.checkPosition,this)).on("click.affix.data-api",a.proxy(function(){setTimeout(a.proxy(this.checkPosition,this),1)},this)),this.$element=a(b),this.checkPosition()};b.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var b=a(document).height(),c=this.$window.scrollTop(),d=this.$element.offset(),e=this.options.offset,f=e.bottom,g=e.top,h="affix affix-top affix-bottom",i;typeof e!="object"&&(f=g=e),typeof g=="function"&&(g=e.top()),typeof f=="function"&&(f=e.bottom()),i=this.unpin!=null&&c+this.unpin<=d.top?!1:f!=null&&d.top+this.$element.height()>=b-f?"bottom":g!=null&&c<=g?"top":!1;if(this.affixed===i)return;this.affixed=i,this.unpin=i=="bottom"?d.top-c:null,this.$element.removeClass(h).addClass("affix"+(i?"-"+i:""))};var c=a.fn.affix;a.fn.affix=function(c){return this.each(function(){var d=a(this),e=d.data("affix"),f=typeof c=="object"&&c;e||d.data("affix",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.affix.Constructor=b,a.fn.affix.defaults={offset:0},a.fn.affix.noConflict=function(){return a.fn.affix=c,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var b=a(this),c=b.data();c.offset=c.offset||{},c.offsetBottom&&(c.offset.bottom=c.offsetBottom),c.offsetTop&&(c.offset.top=c.offsetTop),b.affix(c)})})}(window.jQuery),!function(a){var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.alert.data-api",b,c.prototype.close)}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype.setState=function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a+="Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},b.prototype.toggle=function(){var a=this.$element.closest('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")};var c=a.fn.button;a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a.fn.button.noConflict=function(){return a.fn.button=c,this},a(document).on("click.button.data-api","[data-toggle^=button]",function(b){var c=a(b.target);c.hasClass("btn")||(c=c.closest(".btn")),c.button("toggle")})}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b,c,d,e;if(this.transitioning||this.$element.hasClass("in"))return;b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find("> .accordion-group > .in");if(d&&d.length){e=d.data("collapse");if(e&&e.transitioning)return;d.collapse("hide"),e||d.data("collapse",null)}this.$element[b](0),this.transition("addClass",a.Event("show"),"shown"),a.support.transition&&this.$element[b](this.$element[0][c])},hide:function(){var b;if(this.transitioning||!this.$element.hasClass("in"))return;b=this.dimension(),this.reset(this.$element[b]()),this.transition("removeClass",a.Event("hide"),"hidden"),this.$element[b](0)},reset:function(a){var b=this.dimension();return this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element[a!==null?"addClass":"removeClass"]("collapse"),this},transition:function(b,c,d){var e=this,f=function(){c.type=="show"&&e.reset(),e.transitioning=0,e.$element.trigger(d)};this.$element.trigger(c);if(c.isDefaultPrevented())return;this.transitioning=1,this.$element[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var c=a.fn.collapse;a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=a.extend({},a.fn.collapse.defaults,d.data(),typeof c=="object"&&c);e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a.fn.collapse.noConflict=function(){return a.fn.collapse=c,this},a(document).on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();c[a(e).hasClass("in")?"addClass":"removeClass"]("collapsed"),a(e).collapse(f)})}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.options.pause=="hover"&&this.$element.on("mouseenter",a.proxy(this.pause,this)).on("mouseleave",a.proxy(this.cycle,this))};b.prototype={cycle:function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(b){var c=this.getActiveIndex(),d=this;if(b>this.$items.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){d.to(b)}):c==b?this.pause().cycle():this.slide(b>c?"next":"prev",a(this.$items[b]))},pause:function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition.end&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this,j;this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h](),j=a.Event("slide",{relatedTarget:e[0],direction:g});if(e.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var b=a(i.$indicators.children()[i.getActiveIndex()]);b&&b.addClass("active")}));if(a.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(j);if(j.isDefaultPrevented())return;e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})}else{this.$element.trigger(j);if(j.isDefaultPrevented())return;d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return f&&this.cycle(),this}};var c=a.fn.carousel;a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=a.extend({},a.fn.carousel.defaults,typeof c=="object"&&c),g=typeof c=="string"?c:f.slide;e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):g?e[g]():f.interval&&e.pause().cycle()})},a.fn.carousel.defaults={interval:5e3,pause:"hover"},a.fn.carousel.Constructor=b,a.fn.carousel.noConflict=function(){return a.fn.carousel=c,this},a(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=a.extend({},e.data(),c.data()),g;e.carousel(f),(g=c.attr("data-slide-to"))&&e.data("carousel").pause().to(g).cycle(),b.preventDefault()})}(window.jQuery),!function(a){var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=a(this.options.menu),this.shown=!1,this.listen()};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(a)).change(),this.hide()},updater:function(a){return a},show:function(){var b=a.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:b.top+b.height,left:b.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){var c;return this.query=this.$element.val(),!this.query||this.query.length<this.options.minLength?this.shown?this.hide():this:(c=a.isFunction(this.source)?this.source(this.query,a.proxy(this.process,this)):this.source,c?this.process(c):this)},process:function(b){var c=this;return b=a.grep(b,function(a){return c.matcher(a)}),b=this.sorter(b),b.length?this.render(b.slice(0,this.options.items)).show():this.shown?this.hide():this},matcher:function(a){return~a.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){var b=[],c=[],d=[],e;while(e=a.shift())e.toLowerCase().indexOf(this.query.toLowerCase())?~e.indexOf(this.query)?c.push(e):d.push(e):b.push(e);return b.concat(c,d)},highlighter:function(a){var b=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return a.replace(new RegExp("("+b+")","ig"),function(a,b){return"<strong>"+b+"</strong>"})},render:function(b){var c=this;return b=a(b).map(function(b,d){return b=a(c.options.item).attr("data-value",d),b.find("a").html(c.highlighter(d)),b[0]}),b.first().addClass("active"),this.$menu.html(b),this},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("focus",a.proxy(this.focus,this)).on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",a.proxy(this.keydown,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this)).on("mouseleave","li",a.proxy(this.mouseleave,this))},eventSupported:function(a){var b=a in this.$element;return b||(this.$element.setAttribute(a,"return;"),b=typeof this.$element[a]=="function"),b},move:function(a){if(!this.shown)return;switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:a.preventDefault(),this.prev();break;case 40:a.preventDefault(),this.next()}a.stopPropagation()},keydown:function(b){this.suppressKeyPressRepeat=~a.inArray(b.keyCode,[40,38,9,13,27]),this.move(b)},keypress:function(a){if(this.suppressKeyPressRepeat)return;this.move(a)},keyup:function(a){switch(a.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}a.stopPropagation(),a.preventDefault()},focus:function(a){this.focused=!0},blur:function(a){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(a){a.stopPropagation(),a.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(b){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")},mouseleave:function(a){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var c=a.fn.typeahead;a.fn.typeahead=function(c){return this.each(function(){var d=a(this),e=d.data("typeahead"),f=typeof c=="object"&&c;e||d.data("typeahead",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>',minLength:1},a.fn.typeahead.Constructor=b,a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this},a(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);if(c.data("typeahead"))return;c.typeahead(c.data())})}(window.jQuery)
diff --git a/tools/ngui/static/js/app/dashboard/dashboard.js b/tools/ngui/static/js/app/dashboard/dashboard.js
index 5cd17fb..b248758 100644
--- a/tools/ngui/static/js/app/dashboard/dashboard.js
+++ b/tools/ngui/static/js/app/dashboard/dashboard.js
@@ -14,4 +14,3 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-
diff --git a/tools/ngui/static/js/app/infrastructure/infrastructure.js b/tools/ngui/static/js/app/infrastructure/infrastructure.js
index 5cd17fb..b248758 100644
--- a/tools/ngui/static/js/app/infrastructure/infrastructure.js
+++ b/tools/ngui/static/js/app/infrastructure/infrastructure.js
@@ -14,4 +14,3 @@
 // KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
-
diff --git a/tools/ngui/static/js/lib/angular.js b/tools/ngui/static/js/lib/angular.js
index 4a17e64..e960afe 100644
--- a/tools/ngui/static/js/lib/angular.js
+++ b/tools/ngui/static/js/lib/angular.js
@@ -14844,4 +14844,4 @@
   });
 
 })(window, document);
-angular.element(document).find('head').append('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}</style>');
\ No newline at end of file
+angular.element(document).find('head').append('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}</style>');
diff --git a/tools/pom.xml b/tools/pom.xml
index 81bfe9b..a39a504 100644
--- a/tools/pom.xml
+++ b/tools/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <build>
diff --git a/tools/transifex/.tx/config b/tools/transifex/.tx/config
index 45bd841..9e3983e 100644
--- a/tools/transifex/.tx/config
+++ b/tools/transifex/.tx/config
@@ -19,4 +19,3 @@
 trans.pt_BR = work-dir/pt_BR.json
 trans.ru_RU = work-dir/ru_RU.json
 trans.zh_CN = work-dir/zh_CN.json
-
diff --git a/tools/transifex/sync-transifex-ui.sh b/tools/transifex/sync-transifex-ui.sh
index 0e3c494..13d6ed6 100755
--- a/tools/transifex/sync-transifex-ui.sh
+++ b/tools/transifex/sync-transifex-ui.sh
@@ -159,4 +159,3 @@
                 exit 1
                 ;;
 esac
-
diff --git a/tools/utils/database_comparision_during_upgrade/README b/tools/utils/database_comparision_during_upgrade/README
index 2c4251d..45c55ea 100644
--- a/tools/utils/database_comparision_during_upgrade/README
+++ b/tools/utils/database_comparision_during_upgrade/README
@@ -42,4 +42,3 @@
 	•	Database user password
 
 8.	Result will be shown in the form of files . 
-
diff --git a/tools/utils/database_comparision_during_upgrade/before_upgrade_data_collection.sh b/tools/utils/database_comparision_during_upgrade/before_upgrade_data_collection.sh
index eb912f4..a168233 100644
--- a/tools/utils/database_comparision_during_upgrade/before_upgrade_data_collection.sh
+++ b/tools/utils/database_comparision_during_upgrade/before_upgrade_data_collection.sh
@@ -23,5 +23,3 @@
 mkdir data_before_upgrade
 
 mysql -u $dbuser -p$dbpwd -h $dbhost --skip-column-names  -e "select  name, value  from cloud.configuration" > ./data_before_upgrade/configuration_before_upgrade
-
-
diff --git a/tools/utils/database_comparision_during_upgrade/fresh_install_data_collection.sh b/tools/utils/database_comparision_during_upgrade/fresh_install_data_collection.sh
index df493d3..aa97304 100644
--- a/tools/utils/database_comparision_during_upgrade/fresh_install_data_collection.sh
+++ b/tools/utils/database_comparision_during_upgrade/fresh_install_data_collection.sh
@@ -46,4 +46,3 @@
                 mysql -u $dbuser -p$dbpwd -h $dbhost -e "describe cloud_usage.$tablename" > ./base_data/usage_data/$tablename
         fi
 done
-
diff --git a/tools/utils/database_comparision_during_upgrade/test_config_before_and_after_upgrade.sh b/tools/utils/database_comparision_during_upgrade/test_config_before_and_after_upgrade.sh
index 48278e0..b7a0c30 100644
--- a/tools/utils/database_comparision_during_upgrade/test_config_before_and_after_upgrade.sh
+++ b/tools/utils/database_comparision_during_upgrade/test_config_before_and_after_upgrade.sh
@@ -110,4 +110,3 @@
 
 rm -rf $path2 *.sort category description scope component temp temp1 $a
 rm -rf mismatch_config_between_before_and_after_upgrade  config_difference_before_and_after_upgrade.sort t
-
diff --git a/tools/utils/database_comparision_during_upgrade/test_config_between_fresh_and_upgraded_setup.sh b/tools/utils/database_comparision_during_upgrade/test_config_between_fresh_and_upgraded_setup.sh
index 8848358..d7fe251 100644
--- a/tools/utils/database_comparision_during_upgrade/test_config_between_fresh_and_upgraded_setup.sh
+++ b/tools/utils/database_comparision_during_upgrade/test_config_between_fresh_and_upgraded_setup.sh
@@ -154,16 +154,3 @@
 rm -rf $path2 *.sort category description scope component temp temp1 $a
 rm -rf mismatch_config_between_before_and_after_upgrade  config_difference_before_and_after_upgrade.sort t
 #rm -rf $path2
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tools/utils/database_comparision_during_upgrade/usage_schema_comparison.sh b/tools/utils/database_comparision_during_upgrade/usage_schema_comparison.sh
index bff6457..7538d36 100644
--- a/tools/utils/database_comparision_during_upgrade/usage_schema_comparison.sh
+++ b/tools/utils/database_comparision_during_upgrade/usage_schema_comparison.sh
@@ -73,4 +73,3 @@
 
 
 rm -rf $path1
-
diff --git a/tools/whisker/LICENSE b/tools/whisker/LICENSE
index af091a4..2dab15b 100644
--- a/tools/whisker/LICENSE
+++ b/tools/whisker/LICENSE
@@ -4738,4 +4738,3 @@
         from The Apache Software Foundation  http://www.apache.org/ 
             EasySSLProtocolSocketFactory.java 
             EasyX509TrustManager.java 
-
diff --git a/ui/.babelrc b/ui/.babelrc
index 7804579..d86eab1 100644
--- a/ui/.babelrc
+++ b/ui/.babelrc
@@ -7,4 +7,4 @@
       "plugins": ["require-context-hook"]
     }
   }
-}
\ No newline at end of file
+}
diff --git a/ui/.gitattributes b/ui/.gitattributes
index e507319..2c6c39a 100644
--- a/ui/.gitattributes
+++ b/ui/.gitattributes
@@ -1 +1 @@
-public/* linguist-vendored
\ No newline at end of file
+public/* linguist-vendored
diff --git a/ui/jest.config.js b/ui/jest.config.js
index b49888a..7659c94 100644
--- a/ui/jest.config.js
+++ b/ui/jest.config.js
@@ -42,7 +42,7 @@
     '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
   ],
   transformIgnorePatterns: [
-    '<rootDir>/node_modules/(?!ant-design-vue|vue|@babel/runtime|lodash-es|@ant-design)'
+    '<rootDir>/node_modules/(?!ant-design-vue|vue|@babel/runtime|lodash-es|@ant-design|@vue-js-cron)'
   ],
   collectCoverage: true,
   collectCoverageFrom: [
diff --git a/ui/package-lock.json b/ui/package-lock.json
index 97cebc3..ed091b3 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -25,12 +25,13 @@
       }
     },
     "@ampproject/remapping": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz",
-      "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
+      "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
       "dev": true,
       "requires": {
-        "@jridgewell/trace-mapping": "^0.3.0"
+        "@jridgewell/gen-mapping": "^0.1.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
       }
     },
     "@ant-design/colors": {
@@ -41,6 +42,18 @@
         "@ctrl/tinycolor": "^3.4.0"
       }
     },
+    "@ant-design/icons": {
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-4.7.0.tgz",
+      "integrity": "sha512-aoB4Z7JA431rt6d4u+8xcNPPCrdufSRMUOpxa1ab6mz1JCQZOEVolj2WVs/tDFmN62zzK30mNelEsprLYsSF3g==",
+      "requires": {
+        "@ant-design/colors": "^6.0.0",
+        "@ant-design/icons-svg": "^4.2.1",
+        "@babel/runtime": "^7.11.2",
+        "classnames": "^2.2.6",
+        "rc-util": "^5.9.4"
+      }
+    },
     "@ant-design/icons-svg": {
       "version": "4.2.1",
       "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz",
@@ -55,6 +68,18 @@
         "@ant-design/icons-svg": "^4.2.1"
       }
     },
+    "@ant-design/react-slick": {
+      "version": "0.29.2",
+      "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-0.29.2.tgz",
+      "integrity": "sha512-kgjtKmkGHa19FW21lHnAfyyH9AAoh35pBdcJ53rHmQ3O+cfFHGHnUbj/HFrRNJ5vIts09FKJVAD8RpaC+RaWfA==",
+      "requires": {
+        "@babel/runtime": "^7.10.4",
+        "classnames": "^2.2.5",
+        "json2mq": "^0.2.0",
+        "lodash": "^4.17.21",
+        "resize-observer-polyfill": "^1.5.1"
+      }
+    },
     "@apollo/protobufjs": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.2.tgz",
@@ -85,9 +110,9 @@
       }
     },
     "@apollographql/apollo-tools": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.5.2.tgz",
-      "integrity": "sha512-KxZiw0Us3k1d0YkJDhOpVH5rJ+mBfjXcgoRoCcslbgirjgLotKMzOcx4PZ7YTEvvEROmvG7X3Aon41GvMmyGsw==",
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.5.4.tgz",
+      "integrity": "sha512-shM3q7rUbNyXVVRkQJQseXv6bnYM3BUma/eZhwXR4xsuM+bqWnJKvW7SAfRjP7LuSCocrexa5AXhjjawNHrIlw==",
       "dev": true
     },
     "@apollographql/graphql-playground-html": {
@@ -115,40 +140,40 @@
       }
     },
     "@babel/code-frame": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
-      "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+      "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
       "dev": true,
       "requires": {
-        "@babel/highlight": "^7.16.7"
+        "@babel/highlight": "^7.18.6"
       }
     },
     "@babel/compat-data": {
-      "version": "7.17.7",
-      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.7.tgz",
-      "integrity": "sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.6.tgz",
+      "integrity": "sha512-tzulrgDT0QD6U7BJ4TKVk2SDDg7wlP39P9yAx1RfLy7vP/7rsDRlWVfbWxElslu56+r7QOhB2NSDsabYYruoZQ==",
       "dev": true
     },
     "@babel/core": {
-      "version": "7.17.8",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz",
-      "integrity": "sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz",
+      "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==",
       "dev": true,
       "requires": {
         "@ampproject/remapping": "^2.1.0",
-        "@babel/code-frame": "^7.16.7",
-        "@babel/generator": "^7.17.7",
-        "@babel/helper-compilation-targets": "^7.17.7",
-        "@babel/helper-module-transforms": "^7.17.7",
-        "@babel/helpers": "^7.17.8",
-        "@babel/parser": "^7.17.8",
-        "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.17.3",
-        "@babel/types": "^7.17.0",
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.18.6",
+        "@babel/helper-compilation-targets": "^7.18.6",
+        "@babel/helper-module-transforms": "^7.18.6",
+        "@babel/helpers": "^7.18.6",
+        "@babel/parser": "^7.18.6",
+        "@babel/template": "^7.18.6",
+        "@babel/traverse": "^7.18.6",
+        "@babel/types": "^7.18.6",
         "convert-source-map": "^1.7.0",
         "debug": "^4.1.0",
         "gensync": "^1.0.0-beta.2",
-        "json5": "^2.1.2",
+        "json5": "^2.2.1",
         "semver": "^6.3.0"
       },
       "dependencies": {
@@ -161,52 +186,57 @@
       }
     },
     "@babel/generator": {
-      "version": "7.17.7",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz",
-      "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==",
+      "version": "7.18.7",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz",
+      "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.17.0",
-        "jsesc": "^2.5.1",
-        "source-map": "^0.5.0"
+        "@babel/types": "^7.18.7",
+        "@jridgewell/gen-mapping": "^0.3.2",
+        "jsesc": "^2.5.1"
       },
       "dependencies": {
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
+        "@jridgewell/gen-mapping": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+          "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+          "dev": true,
+          "requires": {
+            "@jridgewell/set-array": "^1.0.1",
+            "@jridgewell/sourcemap-codec": "^1.4.10",
+            "@jridgewell/trace-mapping": "^0.3.9"
+          }
         }
       }
     },
     "@babel/helper-annotate-as-pure": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz",
-      "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz",
+      "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.16.7"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-builder-binary-assignment-operator-visitor": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz",
-      "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.6.tgz",
+      "integrity": "sha512-KT10c1oWEpmrIRYnthbzHgoOf6B+Xd6a5yhdbNtdhtG7aO1or5HViuf1TQR36xY/QprXA5nvxO6nAjhJ4y38jw==",
       "dev": true,
       "requires": {
-        "@babel/helper-explode-assignable-expression": "^7.16.7",
-        "@babel/types": "^7.16.7"
+        "@babel/helper-explode-assignable-expression": "^7.18.6",
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-compilation-targets": {
-      "version": "7.17.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz",
-      "integrity": "sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz",
+      "integrity": "sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==",
       "dev": true,
       "requires": {
-        "@babel/compat-data": "^7.17.7",
-        "@babel/helper-validator-option": "^7.16.7",
-        "browserslist": "^4.17.5",
+        "@babel/compat-data": "^7.18.6",
+        "@babel/helper-validator-option": "^7.18.6",
+        "browserslist": "^4.20.2",
         "semver": "^6.3.0"
       },
       "dependencies": {
@@ -219,28 +249,28 @@
       }
     },
     "@babel/helper-create-class-features-plugin": {
-      "version": "7.17.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz",
-      "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.6.tgz",
+      "integrity": "sha512-YfDzdnoxHGV8CzqHGyCbFvXg5QESPFkXlHtvdCkesLjjVMT2Adxe4FGUR5ChIb3DxSaXO12iIOCWoXdsUVwnqw==",
       "dev": true,
       "requires": {
-        "@babel/helper-annotate-as-pure": "^7.16.7",
-        "@babel/helper-environment-visitor": "^7.16.7",
-        "@babel/helper-function-name": "^7.16.7",
-        "@babel/helper-member-expression-to-functions": "^7.16.7",
-        "@babel/helper-optimise-call-expression": "^7.16.7",
-        "@babel/helper-replace-supers": "^7.16.7",
-        "@babel/helper-split-export-declaration": "^7.16.7"
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "@babel/helper-environment-visitor": "^7.18.6",
+        "@babel/helper-function-name": "^7.18.6",
+        "@babel/helper-member-expression-to-functions": "^7.18.6",
+        "@babel/helper-optimise-call-expression": "^7.18.6",
+        "@babel/helper-replace-supers": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6"
       }
     },
     "@babel/helper-create-regexp-features-plugin": {
-      "version": "7.17.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz",
-      "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz",
+      "integrity": "sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A==",
       "dev": true,
       "requires": {
-        "@babel/helper-annotate-as-pure": "^7.16.7",
-        "regexpu-core": "^5.0.1"
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "regexpu-core": "^5.1.0"
       }
     },
     "@babel/helper-define-polyfill-provider": {
@@ -260,12 +290,12 @@
       },
       "dependencies": {
         "resolve": {
-          "version": "1.22.0",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
-          "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
+          "version": "1.22.1",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+          "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
           "dev": true,
           "requires": {
-            "is-core-module": "^2.8.1",
+            "is-core-module": "^2.9.0",
             "path-parse": "^1.0.7",
             "supports-preserve-symlinks-flag": "^1.0.0"
           }
@@ -279,194 +309,182 @@
       }
     },
     "@babel/helper-environment-visitor": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz",
-      "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.16.7"
-      }
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz",
+      "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==",
+      "dev": true
     },
     "@babel/helper-explode-assignable-expression": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz",
-      "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz",
+      "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.16.7"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-function-name": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz",
-      "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz",
+      "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==",
       "dev": true,
       "requires": {
-        "@babel/helper-get-function-arity": "^7.16.7",
-        "@babel/template": "^7.16.7",
-        "@babel/types": "^7.16.7"
-      }
-    },
-    "@babel/helper-get-function-arity": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz",
-      "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==",
-      "dev": true,
-      "requires": {
-        "@babel/types": "^7.16.7"
+        "@babel/template": "^7.18.6",
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-hoist-variables": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
-      "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
+      "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.16.7"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-member-expression-to-functions": {
-      "version": "7.17.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz",
-      "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.6.tgz",
+      "integrity": "sha512-CeHxqwwipekotzPDUuJOfIMtcIHBuc7WAzLmTYWctVigqS5RktNMQ5bEwQSuGewzYnCtTWa3BARXeiLxDTv+Ng==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.17.0"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-module-imports": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
-      "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
+      "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.16.7"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-module-transforms": {
-      "version": "7.17.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz",
-      "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.6.tgz",
+      "integrity": "sha512-L//phhB4al5uucwzlimruukHB3jRd5JGClwRMD/ROrVjXfLqovYnvQrK/JK36WYyVwGGO7OD3kMyVTjx+WVPhw==",
       "dev": true,
       "requires": {
-        "@babel/helper-environment-visitor": "^7.16.7",
-        "@babel/helper-module-imports": "^7.16.7",
-        "@babel/helper-simple-access": "^7.17.7",
-        "@babel/helper-split-export-declaration": "^7.16.7",
-        "@babel/helper-validator-identifier": "^7.16.7",
-        "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.17.3",
-        "@babel/types": "^7.17.0"
+        "@babel/helper-environment-visitor": "^7.18.6",
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-simple-access": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/helper-validator-identifier": "^7.18.6",
+        "@babel/template": "^7.18.6",
+        "@babel/traverse": "^7.18.6",
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-optimise-call-expression": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz",
-      "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz",
+      "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.16.7"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-plugin-utils": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz",
-      "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz",
+      "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==",
       "dev": true
     },
     "@babel/helper-remap-async-to-generator": {
-      "version": "7.16.8",
-      "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz",
-      "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.6.tgz",
+      "integrity": "sha512-z5wbmV55TveUPZlCLZvxWHtrjuJd+8inFhk7DG0WW87/oJuGDcjDiu7HIvGcpf5464L6xKCg3vNkmlVVz9hwyQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-annotate-as-pure": "^7.16.7",
-        "@babel/helper-wrap-function": "^7.16.8",
-        "@babel/types": "^7.16.8"
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "@babel/helper-environment-visitor": "^7.18.6",
+        "@babel/helper-wrap-function": "^7.18.6",
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-replace-supers": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz",
-      "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.6.tgz",
+      "integrity": "sha512-fTf7zoXnUGl9gF25fXCWE26t7Tvtyn6H4hkLSYhATwJvw2uYxd3aoXplMSe0g9XbwK7bmxNes7+FGO0rB/xC0g==",
       "dev": true,
       "requires": {
-        "@babel/helper-environment-visitor": "^7.16.7",
-        "@babel/helper-member-expression-to-functions": "^7.16.7",
-        "@babel/helper-optimise-call-expression": "^7.16.7",
-        "@babel/traverse": "^7.16.7",
-        "@babel/types": "^7.16.7"
+        "@babel/helper-environment-visitor": "^7.18.6",
+        "@babel/helper-member-expression-to-functions": "^7.18.6",
+        "@babel/helper-optimise-call-expression": "^7.18.6",
+        "@babel/traverse": "^7.18.6",
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-simple-access": {
-      "version": "7.17.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz",
-      "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz",
+      "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.17.0"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-skip-transparent-expression-wrappers": {
-      "version": "7.16.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz",
-      "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.6.tgz",
+      "integrity": "sha512-4KoLhwGS9vGethZpAhYnMejWkX64wsnHPDwvOsKWU6Fg4+AlK2Jz3TyjQLMEPvz+1zemi/WBdkYxCD0bAfIkiw==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.16.0"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-split-export-declaration": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
-      "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
+      "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.16.7"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-validator-identifier": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
-      "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz",
+      "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==",
       "dev": true
     },
     "@babel/helper-validator-option": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
-      "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
+      "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
       "dev": true
     },
     "@babel/helper-wrap-function": {
-      "version": "7.16.8",
-      "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz",
-      "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.6.tgz",
+      "integrity": "sha512-I5/LZfozwMNbwr/b1vhhuYD+J/mU+gfGAj5td7l5Rv9WYmH6i3Om69WGKNmlIpsVW/mF6O5bvTKbvDQZVgjqOw==",
       "dev": true,
       "requires": {
-        "@babel/helper-function-name": "^7.16.7",
-        "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.16.8",
-        "@babel/types": "^7.16.8"
+        "@babel/helper-function-name": "^7.18.6",
+        "@babel/template": "^7.18.6",
+        "@babel/traverse": "^7.18.6",
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helpers": {
-      "version": "7.17.8",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.8.tgz",
-      "integrity": "sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.6.tgz",
+      "integrity": "sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ==",
       "dev": true,
       "requires": {
-        "@babel/template": "^7.16.7",
-        "@babel/traverse": "^7.17.3",
-        "@babel/types": "^7.17.0"
+        "@babel/template": "^7.18.6",
+        "@babel/traverse": "^7.18.6",
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/highlight": {
-      "version": "7.16.10",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz",
-      "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+      "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
       "dev": true,
       "requires": {
-        "@babel/helper-validator-identifier": "^7.16.7",
+        "@babel/helper-validator-identifier": "^7.18.6",
         "chalk": "^2.0.0",
         "js-tokens": "^4.0.0"
       },
@@ -503,13 +521,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "supports-color": {
@@ -524,199 +542,200 @@
       }
     },
     "@babel/parser": {
-      "version": "7.17.8",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.8.tgz",
-      "integrity": "sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ=="
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.6.tgz",
+      "integrity": "sha512-uQVSa9jJUe/G/304lXspfWVpKpK4euFLgGiMQFOCpM/bgcAdeoHwi/OQz23O9GK2osz26ZiXRRV9aV+Yl1O8tw=="
     },
     "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz",
-      "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz",
+      "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz",
-      "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.6.tgz",
+      "integrity": "sha512-Udgu8ZRgrBrttVz6A0EVL0SJ1z+RLbIeqsu632SA1hf0awEppD6TvdznoH+orIF8wtFFAV/Enmw9Y+9oV8TQcw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0",
-        "@babel/plugin-proposal-optional-chaining": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.18.6",
+        "@babel/plugin-proposal-optional-chaining": "^7.18.6"
       }
     },
     "@babel/plugin-proposal-async-generator-functions": {
-      "version": "7.16.8",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz",
-      "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz",
+      "integrity": "sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-remap-async-to-generator": "^7.16.8",
+        "@babel/helper-environment-visitor": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-remap-async-to-generator": "^7.18.6",
         "@babel/plugin-syntax-async-generators": "^7.8.4"
       }
     },
     "@babel/plugin-proposal-class-properties": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz",
-      "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz",
+      "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-class-features-plugin": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-create-class-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-proposal-class-static-block": {
-      "version": "7.17.6",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz",
-      "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz",
+      "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-class-features-plugin": "^7.17.6",
-        "@babel/helper-plugin-utils": "^7.16.7",
+        "@babel/helper-create-class-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6",
         "@babel/plugin-syntax-class-static-block": "^7.14.5"
       }
     },
     "@babel/plugin-proposal-decorators": {
-      "version": "7.17.8",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.8.tgz",
-      "integrity": "sha512-U69odN4Umyyx1xO1rTII0IDkAEC+RNlcKXtqOblfpzqy1C+aOplb76BQNq0+XdpVkOaPlpEDwd++joY8FNFJKA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.18.6.tgz",
+      "integrity": "sha512-gAdhsjaYmiZVxx5vTMiRfj31nB7LhwBJFMSLzeDxc7X4tKLixup0+k9ughn0RcpBrv9E3PBaXJW7jF5TCihAOg==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-class-features-plugin": "^7.17.6",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-replace-supers": "^7.16.7",
-        "@babel/plugin-syntax-decorators": "^7.17.0",
-        "charcodes": "^0.2.0"
+        "@babel/helper-create-class-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-replace-supers": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/plugin-syntax-decorators": "^7.18.6"
       }
     },
     "@babel/plugin-proposal-dynamic-import": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz",
-      "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz",
+      "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
+        "@babel/helper-plugin-utils": "^7.18.6",
         "@babel/plugin-syntax-dynamic-import": "^7.8.3"
       }
     },
     "@babel/plugin-proposal-export-namespace-from": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz",
-      "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.6.tgz",
+      "integrity": "sha512-zr/QcUlUo7GPo6+X1wC98NJADqmy5QTFWWhqeQWiki4XHafJtLl/YMGkmRB2szDD2IYJCCdBTd4ElwhId9T7Xw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
+        "@babel/helper-plugin-utils": "^7.18.6",
         "@babel/plugin-syntax-export-namespace-from": "^7.8.3"
       }
     },
     "@babel/plugin-proposal-json-strings": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz",
-      "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz",
+      "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
+        "@babel/helper-plugin-utils": "^7.18.6",
         "@babel/plugin-syntax-json-strings": "^7.8.3"
       }
     },
     "@babel/plugin-proposal-logical-assignment-operators": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz",
-      "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.6.tgz",
+      "integrity": "sha512-zMo66azZth/0tVd7gmkxOkOjs2rpHyhpcFo565PUP37hSp6hSd9uUKIfTDFMz58BwqgQKhJ9YxtM5XddjXVn+Q==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
+        "@babel/helper-plugin-utils": "^7.18.6",
         "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
       }
     },
     "@babel/plugin-proposal-nullish-coalescing-operator": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz",
-      "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz",
+      "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
+        "@babel/helper-plugin-utils": "^7.18.6",
         "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
       }
     },
     "@babel/plugin-proposal-numeric-separator": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz",
-      "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz",
+      "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
+        "@babel/helper-plugin-utils": "^7.18.6",
         "@babel/plugin-syntax-numeric-separator": "^7.10.4"
       }
     },
     "@babel/plugin-proposal-object-rest-spread": {
-      "version": "7.17.3",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz",
-      "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.6.tgz",
+      "integrity": "sha512-9yuM6wr4rIsKa1wlUAbZEazkCrgw2sMPEXCr4Rnwetu7cEW1NydkCWytLuYletbf8vFxdJxFhwEZqMpOx2eZyw==",
       "dev": true,
       "requires": {
-        "@babel/compat-data": "^7.17.0",
-        "@babel/helper-compilation-targets": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
+        "@babel/compat-data": "^7.18.6",
+        "@babel/helper-compilation-targets": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6",
         "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
-        "@babel/plugin-transform-parameters": "^7.16.7"
+        "@babel/plugin-transform-parameters": "^7.18.6"
       }
     },
     "@babel/plugin-proposal-optional-catch-binding": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz",
-      "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz",
+      "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
+        "@babel/helper-plugin-utils": "^7.18.6",
         "@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
       }
     },
     "@babel/plugin-proposal-optional-chaining": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz",
-      "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.6.tgz",
+      "integrity": "sha512-PatI6elL5eMzoypFAiYDpYQyMtXTn+iMhuxxQt5mAXD4fEmKorpSI3PHd+i3JXBJN3xyA6MvJv7at23HffFHwA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0",
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.18.6",
         "@babel/plugin-syntax-optional-chaining": "^7.8.3"
       }
     },
     "@babel/plugin-proposal-private-methods": {
-      "version": "7.16.11",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz",
-      "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz",
+      "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-class-features-plugin": "^7.16.10",
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-create-class-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-proposal-private-property-in-object": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz",
-      "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz",
+      "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==",
       "dev": true,
       "requires": {
-        "@babel/helper-annotate-as-pure": "^7.16.7",
-        "@babel/helper-create-class-features-plugin": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "@babel/helper-create-class-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6",
         "@babel/plugin-syntax-private-property-in-object": "^7.14.5"
       }
     },
     "@babel/plugin-proposal-unicode-property-regex": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz",
-      "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz",
+      "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-regexp-features-plugin": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-syntax-async-generators": {
@@ -756,12 +775,12 @@
       }
     },
     "@babel/plugin-syntax-decorators": {
-      "version": "7.17.0",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz",
-      "integrity": "sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.18.6.tgz",
+      "integrity": "sha512-fqyLgjcxf/1yhyZ6A+yo1u9gJ7eleFQod2lkaUsF9DQ7sbbY3Ligym3L0+I2c0WmqNKDpoD9UTb1AKP3qRMOAQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-syntax-dynamic-import": {
@@ -783,12 +802,21 @@
       }
     },
     "@babel/plugin-syntax-flow": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.16.7.tgz",
-      "integrity": "sha512-UDo3YGQO0jH6ytzVwgSLv9i/CzMcUjbKenL67dTrAZPPv6GFAtDhe6jqnvmoKzC/7htNTohhos+onPtDMqJwaQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz",
+      "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
+      }
+    },
+    "@babel/plugin-syntax-import-assertions": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz",
+      "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-syntax-import-meta": {
@@ -810,12 +838,12 @@
       }
     },
     "@babel/plugin-syntax-jsx": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz",
-      "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz",
+      "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-syntax-logical-assignment-operators": {
@@ -891,284 +919,286 @@
       }
     },
     "@babel/plugin-syntax-typescript": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz",
-      "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz",
+      "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-arrow-functions": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz",
-      "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz",
+      "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-async-to-generator": {
-      "version": "7.16.8",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz",
-      "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz",
+      "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==",
       "dev": true,
       "requires": {
-        "@babel/helper-module-imports": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-remap-async-to-generator": "^7.16.8"
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-remap-async-to-generator": "^7.18.6"
       }
     },
     "@babel/plugin-transform-block-scoped-functions": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz",
-      "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz",
+      "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-block-scoping": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz",
-      "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.6.tgz",
+      "integrity": "sha512-pRqwb91C42vs1ahSAWJkxOxU1RHWDn16XAa6ggQ72wjLlWyYeAcLvTtE0aM8ph3KNydy9CQF2nLYcjq1WysgxQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-classes": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz",
-      "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.6.tgz",
+      "integrity": "sha512-XTg8XW/mKpzAF3actL554Jl/dOYoJtv3l8fxaEczpgz84IeeVf+T1u2CSvPHuZbt0w3JkIx4rdn/MRQI7mo0HQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-annotate-as-pure": "^7.16.7",
-        "@babel/helper-environment-visitor": "^7.16.7",
-        "@babel/helper-function-name": "^7.16.7",
-        "@babel/helper-optimise-call-expression": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-replace-supers": "^7.16.7",
-        "@babel/helper-split-export-declaration": "^7.16.7",
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "@babel/helper-environment-visitor": "^7.18.6",
+        "@babel/helper-function-name": "^7.18.6",
+        "@babel/helper-optimise-call-expression": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-replace-supers": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6",
         "globals": "^11.1.0"
       }
     },
     "@babel/plugin-transform-computed-properties": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz",
-      "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.6.tgz",
+      "integrity": "sha512-9repI4BhNrR0KenoR9vm3/cIc1tSBIo+u1WVjKCAynahj25O8zfbiE6JtAtHPGQSs4yZ+bA8mRasRP+qc+2R5A==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-destructuring": {
-      "version": "7.17.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz",
-      "integrity": "sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.6.tgz",
+      "integrity": "sha512-tgy3u6lRp17ilY8r1kP4i2+HDUwxlVqq3RTc943eAWSzGgpU1qhiKpqZ5CMyHReIYPHdo3Kg8v8edKtDqSVEyQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-dotall-regex": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz",
-      "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz",
+      "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-regexp-features-plugin": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-duplicate-keys": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz",
-      "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.6.tgz",
+      "integrity": "sha512-NJU26U/208+sxYszf82nmGYqVF9QN8py2HFTblPT9hbawi8+1C5a9JubODLTGFuT0qlkqVinmkwOD13s0sZktg==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-exponentiation-operator": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz",
-      "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz",
+      "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==",
       "dev": true,
       "requires": {
-        "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-flow-strip-types": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.16.7.tgz",
-      "integrity": "sha512-mzmCq3cNsDpZZu9FADYYyfZJIOrSONmHcop2XEKPdBNMa4PDC4eEvcOvzZaCNcjKu72v0XQlA5y1g58aLRXdYg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.18.6.tgz",
+      "integrity": "sha512-wE0xtA7csz+hw4fKPwxmu5jnzAsXPIO57XnRwzXP3T19jWh1BODnPGoG9xKYwvAwusP7iUktHayRFbMPGtODaQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/plugin-syntax-flow": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/plugin-syntax-flow": "^7.18.6"
       }
     },
     "@babel/plugin-transform-for-of": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz",
-      "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.6.tgz",
+      "integrity": "sha512-WAjoMf4wIiSsy88KmG7tgj2nFdEK7E46tArVtcgED7Bkj6Fg/tG5SbvNIOKxbFS2VFgNh6+iaPswBeQZm4ox8w==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-function-name": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz",
-      "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.6.tgz",
+      "integrity": "sha512-kJha/Gbs5RjzIu0CxZwf5e3aTTSlhZnHMT8zPWnJMjNpLOUgqevg+PN5oMH68nMCXnfiMo4Bhgxqj59KHTlAnA==",
       "dev": true,
       "requires": {
-        "@babel/helper-compilation-targets": "^7.16.7",
-        "@babel/helper-function-name": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-compilation-targets": "^7.18.6",
+        "@babel/helper-function-name": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-literals": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz",
-      "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.6.tgz",
+      "integrity": "sha512-x3HEw0cJZVDoENXOp20HlypIHfl0zMIhMVZEBVTfmqbObIpsMxMbmU5nOEO8R7LYT+z5RORKPlTI5Hj4OsO9/Q==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-member-expression-literals": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz",
-      "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz",
+      "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-modules-amd": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz",
-      "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz",
+      "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==",
       "dev": true,
       "requires": {
-        "@babel/helper-module-transforms": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
+        "@babel/helper-module-transforms": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6",
         "babel-plugin-dynamic-import-node": "^2.3.3"
       }
     },
     "@babel/plugin-transform-modules-commonjs": {
-      "version": "7.17.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz",
-      "integrity": "sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz",
+      "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==",
       "dev": true,
       "requires": {
-        "@babel/helper-module-transforms": "^7.17.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-simple-access": "^7.17.7",
+        "@babel/helper-module-transforms": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-simple-access": "^7.18.6",
         "babel-plugin-dynamic-import-node": "^2.3.3"
       }
     },
     "@babel/plugin-transform-modules-systemjs": {
-      "version": "7.17.8",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz",
-      "integrity": "sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.6.tgz",
+      "integrity": "sha512-UbPYpXxLjTw6w6yXX2BYNxF3p6QY225wcTkfQCy3OMnSlS/C3xGtwUjEzGkldb/sy6PWLiCQ3NbYfjWUTI3t4g==",
       "dev": true,
       "requires": {
-        "@babel/helper-hoist-variables": "^7.16.7",
-        "@babel/helper-module-transforms": "^7.17.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-validator-identifier": "^7.16.7",
+        "@babel/helper-hoist-variables": "^7.18.6",
+        "@babel/helper-module-transforms": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-validator-identifier": "^7.18.6",
         "babel-plugin-dynamic-import-node": "^2.3.3"
       }
     },
     "@babel/plugin-transform-modules-umd": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz",
-      "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz",
+      "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-module-transforms": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-module-transforms": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-named-capturing-groups-regex": {
-      "version": "7.16.8",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz",
-      "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz",
+      "integrity": "sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-regexp-features-plugin": "^7.16.7"
+        "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-new-target": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz",
-      "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz",
+      "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-object-super": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz",
-      "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz",
+      "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-replace-supers": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-replace-supers": "^7.18.6"
       }
     },
     "@babel/plugin-transform-parameters": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz",
-      "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.6.tgz",
+      "integrity": "sha512-FjdqgMv37yVl/gwvzkcB+wfjRI8HQmc5EgOG9iGNvUY1ok+TjsoaMP7IqCDZBhkFcM5f3OPVMs6Dmp03C5k4/A==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-property-literals": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz",
-      "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz",
+      "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-regenerator": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz",
-      "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz",
+      "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==",
       "dev": true,
       "requires": {
-        "regenerator-transform": "^0.14.2"
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "regenerator-transform": "^0.15.0"
       }
     },
     "@babel/plugin-transform-reserved-words": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz",
-      "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz",
+      "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-runtime": {
-      "version": "7.17.0",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.0.tgz",
-      "integrity": "sha512-fr7zPWnKXNc1xoHfrIU9mN/4XKX4VLZ45Q+oMhfsYIaHvg7mHgmhfOy/ckRWqDK7XF3QDigRpkh5DKq6+clE8A==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.6.tgz",
+      "integrity": "sha512-8uRHk9ZmRSnWqUgyae249EJZ94b0yAGLBIqzZzl+0iEdbno55Pmlt/32JZsHwXD9k/uZj18Aqqk35wBX4CBTXA==",
       "dev": true,
       "requires": {
-        "@babel/helper-module-imports": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "babel-plugin-polyfill-corejs2": "^0.3.0",
-        "babel-plugin-polyfill-corejs3": "^0.5.0",
-        "babel-plugin-polyfill-regenerator": "^0.3.0",
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "babel-plugin-polyfill-corejs2": "^0.3.1",
+        "babel-plugin-polyfill-corejs3": "^0.5.2",
+        "babel-plugin-polyfill-regenerator": "^0.3.1",
         "semver": "^6.3.0"
       },
       "dependencies": {
@@ -1181,113 +1211,114 @@
       }
     },
     "@babel/plugin-transform-shorthand-properties": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz",
-      "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz",
+      "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-spread": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz",
-      "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.6.tgz",
+      "integrity": "sha512-ayT53rT/ENF8WWexIRg9AiV9h0aIteyWn5ptfZTZQrjk/+f3WdrJGCY4c9wcgl2+MKkKPhzbYp97FTsquZpDCw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0"
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.18.6"
       }
     },
     "@babel/plugin-transform-sticky-regex": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz",
-      "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz",
+      "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-template-literals": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz",
-      "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.6.tgz",
+      "integrity": "sha512-UuqlRrQmT2SWRvahW46cGSany0uTlcj8NYOS5sRGYi8FxPYPoLd5DDmMd32ZXEj2Jq+06uGVQKHxa/hJx2EzKw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-typeof-symbol": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz",
-      "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.6.tgz",
+      "integrity": "sha512-7m71iS/QhsPk85xSjFPovHPcH3H9qeyzsujhTc+vcdnsXavoWYJ74zx0lP5RhpC5+iDnVLO+PPMHzC11qels1g==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-typescript": {
-      "version": "7.16.8",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz",
-      "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.6.tgz",
+      "integrity": "sha512-ijHNhzIrLj5lQCnI6aaNVRtGVuUZhOXFLRVFs7lLrkXTHip4FKty5oAuQdk4tywG0/WjXmjTfQCWmuzrvFer1w==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-class-features-plugin": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/plugin-syntax-typescript": "^7.16.7"
+        "@babel/helper-create-class-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/plugin-syntax-typescript": "^7.18.6"
       }
     },
     "@babel/plugin-transform-unicode-escapes": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz",
-      "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.6.tgz",
+      "integrity": "sha512-XNRwQUXYMP7VLuy54cr/KS/WeL3AZeORhrmeZ7iewgu+X2eBqmpaLI/hzqr9ZxCeUoq0ASK4GUzSM0BDhZkLFw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-unicode-regex": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz",
-      "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz",
+      "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-regexp-features-plugin": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7"
+        "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/preset-env": {
-      "version": "7.16.11",
-      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz",
-      "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.6.tgz",
+      "integrity": "sha512-WrthhuIIYKrEFAwttYzgRNQ5hULGmwTj+D6l7Zdfsv5M7IWV/OZbUfbeL++Qrzx1nVJwWROIFhCHRYQV4xbPNw==",
       "dev": true,
       "requires": {
-        "@babel/compat-data": "^7.16.8",
-        "@babel/helper-compilation-targets": "^7.16.7",
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-validator-option": "^7.16.7",
-        "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7",
-        "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7",
-        "@babel/plugin-proposal-async-generator-functions": "^7.16.8",
-        "@babel/plugin-proposal-class-properties": "^7.16.7",
-        "@babel/plugin-proposal-class-static-block": "^7.16.7",
-        "@babel/plugin-proposal-dynamic-import": "^7.16.7",
-        "@babel/plugin-proposal-export-namespace-from": "^7.16.7",
-        "@babel/plugin-proposal-json-strings": "^7.16.7",
-        "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7",
-        "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7",
-        "@babel/plugin-proposal-numeric-separator": "^7.16.7",
-        "@babel/plugin-proposal-object-rest-spread": "^7.16.7",
-        "@babel/plugin-proposal-optional-catch-binding": "^7.16.7",
-        "@babel/plugin-proposal-optional-chaining": "^7.16.7",
-        "@babel/plugin-proposal-private-methods": "^7.16.11",
-        "@babel/plugin-proposal-private-property-in-object": "^7.16.7",
-        "@babel/plugin-proposal-unicode-property-regex": "^7.16.7",
+        "@babel/compat-data": "^7.18.6",
+        "@babel/helper-compilation-targets": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-validator-option": "^7.18.6",
+        "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6",
+        "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.6",
+        "@babel/plugin-proposal-async-generator-functions": "^7.18.6",
+        "@babel/plugin-proposal-class-properties": "^7.18.6",
+        "@babel/plugin-proposal-class-static-block": "^7.18.6",
+        "@babel/plugin-proposal-dynamic-import": "^7.18.6",
+        "@babel/plugin-proposal-export-namespace-from": "^7.18.6",
+        "@babel/plugin-proposal-json-strings": "^7.18.6",
+        "@babel/plugin-proposal-logical-assignment-operators": "^7.18.6",
+        "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
+        "@babel/plugin-proposal-numeric-separator": "^7.18.6",
+        "@babel/plugin-proposal-object-rest-spread": "^7.18.6",
+        "@babel/plugin-proposal-optional-catch-binding": "^7.18.6",
+        "@babel/plugin-proposal-optional-chaining": "^7.18.6",
+        "@babel/plugin-proposal-private-methods": "^7.18.6",
+        "@babel/plugin-proposal-private-property-in-object": "^7.18.6",
+        "@babel/plugin-proposal-unicode-property-regex": "^7.18.6",
         "@babel/plugin-syntax-async-generators": "^7.8.4",
         "@babel/plugin-syntax-class-properties": "^7.12.13",
         "@babel/plugin-syntax-class-static-block": "^7.14.5",
         "@babel/plugin-syntax-dynamic-import": "^7.8.3",
         "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
+        "@babel/plugin-syntax-import-assertions": "^7.18.6",
         "@babel/plugin-syntax-json-strings": "^7.8.3",
         "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
         "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
@@ -1297,44 +1328,44 @@
         "@babel/plugin-syntax-optional-chaining": "^7.8.3",
         "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
         "@babel/plugin-syntax-top-level-await": "^7.14.5",
-        "@babel/plugin-transform-arrow-functions": "^7.16.7",
-        "@babel/plugin-transform-async-to-generator": "^7.16.8",
-        "@babel/plugin-transform-block-scoped-functions": "^7.16.7",
-        "@babel/plugin-transform-block-scoping": "^7.16.7",
-        "@babel/plugin-transform-classes": "^7.16.7",
-        "@babel/plugin-transform-computed-properties": "^7.16.7",
-        "@babel/plugin-transform-destructuring": "^7.16.7",
-        "@babel/plugin-transform-dotall-regex": "^7.16.7",
-        "@babel/plugin-transform-duplicate-keys": "^7.16.7",
-        "@babel/plugin-transform-exponentiation-operator": "^7.16.7",
-        "@babel/plugin-transform-for-of": "^7.16.7",
-        "@babel/plugin-transform-function-name": "^7.16.7",
-        "@babel/plugin-transform-literals": "^7.16.7",
-        "@babel/plugin-transform-member-expression-literals": "^7.16.7",
-        "@babel/plugin-transform-modules-amd": "^7.16.7",
-        "@babel/plugin-transform-modules-commonjs": "^7.16.8",
-        "@babel/plugin-transform-modules-systemjs": "^7.16.7",
-        "@babel/plugin-transform-modules-umd": "^7.16.7",
-        "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8",
-        "@babel/plugin-transform-new-target": "^7.16.7",
-        "@babel/plugin-transform-object-super": "^7.16.7",
-        "@babel/plugin-transform-parameters": "^7.16.7",
-        "@babel/plugin-transform-property-literals": "^7.16.7",
-        "@babel/plugin-transform-regenerator": "^7.16.7",
-        "@babel/plugin-transform-reserved-words": "^7.16.7",
-        "@babel/plugin-transform-shorthand-properties": "^7.16.7",
-        "@babel/plugin-transform-spread": "^7.16.7",
-        "@babel/plugin-transform-sticky-regex": "^7.16.7",
-        "@babel/plugin-transform-template-literals": "^7.16.7",
-        "@babel/plugin-transform-typeof-symbol": "^7.16.7",
-        "@babel/plugin-transform-unicode-escapes": "^7.16.7",
-        "@babel/plugin-transform-unicode-regex": "^7.16.7",
+        "@babel/plugin-transform-arrow-functions": "^7.18.6",
+        "@babel/plugin-transform-async-to-generator": "^7.18.6",
+        "@babel/plugin-transform-block-scoped-functions": "^7.18.6",
+        "@babel/plugin-transform-block-scoping": "^7.18.6",
+        "@babel/plugin-transform-classes": "^7.18.6",
+        "@babel/plugin-transform-computed-properties": "^7.18.6",
+        "@babel/plugin-transform-destructuring": "^7.18.6",
+        "@babel/plugin-transform-dotall-regex": "^7.18.6",
+        "@babel/plugin-transform-duplicate-keys": "^7.18.6",
+        "@babel/plugin-transform-exponentiation-operator": "^7.18.6",
+        "@babel/plugin-transform-for-of": "^7.18.6",
+        "@babel/plugin-transform-function-name": "^7.18.6",
+        "@babel/plugin-transform-literals": "^7.18.6",
+        "@babel/plugin-transform-member-expression-literals": "^7.18.6",
+        "@babel/plugin-transform-modules-amd": "^7.18.6",
+        "@babel/plugin-transform-modules-commonjs": "^7.18.6",
+        "@babel/plugin-transform-modules-systemjs": "^7.18.6",
+        "@babel/plugin-transform-modules-umd": "^7.18.6",
+        "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6",
+        "@babel/plugin-transform-new-target": "^7.18.6",
+        "@babel/plugin-transform-object-super": "^7.18.6",
+        "@babel/plugin-transform-parameters": "^7.18.6",
+        "@babel/plugin-transform-property-literals": "^7.18.6",
+        "@babel/plugin-transform-regenerator": "^7.18.6",
+        "@babel/plugin-transform-reserved-words": "^7.18.6",
+        "@babel/plugin-transform-shorthand-properties": "^7.18.6",
+        "@babel/plugin-transform-spread": "^7.18.6",
+        "@babel/plugin-transform-sticky-regex": "^7.18.6",
+        "@babel/plugin-transform-template-literals": "^7.18.6",
+        "@babel/plugin-transform-typeof-symbol": "^7.18.6",
+        "@babel/plugin-transform-unicode-escapes": "^7.18.6",
+        "@babel/plugin-transform-unicode-regex": "^7.18.6",
         "@babel/preset-modules": "^0.1.5",
-        "@babel/types": "^7.16.8",
-        "babel-plugin-polyfill-corejs2": "^0.3.0",
-        "babel-plugin-polyfill-corejs3": "^0.5.0",
-        "babel-plugin-polyfill-regenerator": "^0.3.0",
-        "core-js-compat": "^3.20.2",
+        "@babel/types": "^7.18.6",
+        "babel-plugin-polyfill-corejs2": "^0.3.1",
+        "babel-plugin-polyfill-corejs3": "^0.5.2",
+        "babel-plugin-polyfill-regenerator": "^0.3.1",
+        "core-js-compat": "^3.22.1",
         "semver": "^6.3.0"
       },
       "dependencies": {
@@ -1347,14 +1378,14 @@
       }
     },
     "@babel/preset-flow": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.16.7.tgz",
-      "integrity": "sha512-6ceP7IyZdUYQ3wUVqyRSQXztd1YmFHWI4Xv11MIqAlE4WqxBSd/FZ61V9k+TS5Gd4mkHOtQtPp9ymRpxH4y1Ug==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.18.6.tgz",
+      "integrity": "sha512-E7BDhL64W6OUqpuyHnSroLnqyRTcG6ZdOBl1OKI/QK/HJfplqK/S3sq1Cckx7oTodJ5yOXyfw7rEADJ6UjoQDQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-validator-option": "^7.16.7",
-        "@babel/plugin-transform-flow-strip-types": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-validator-option": "^7.18.6",
+        "@babel/plugin-transform-flow-strip-types": "^7.18.6"
       }
     },
     "@babel/preset-modules": {
@@ -1371,20 +1402,20 @@
       }
     },
     "@babel/preset-typescript": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz",
-      "integrity": "sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz",
+      "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.16.7",
-        "@babel/helper-validator-option": "^7.16.7",
-        "@babel/plugin-transform-typescript": "^7.16.7"
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-validator-option": "^7.18.6",
+        "@babel/plugin-transform-typescript": "^7.18.6"
       }
     },
     "@babel/register": {
-      "version": "7.17.7",
-      "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.17.7.tgz",
-      "integrity": "sha512-fg56SwvXRifootQEDQAu1mKdjh5uthPzdO0N6t358FktfL4XjAVXuH58ULoiW8mesxiOgNIrxiImqEwv0+hRRA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.18.6.tgz",
+      "integrity": "sha512-tkYtONzaO8rQubZzpBnvZPFcHgh8D9F55IjOsYton4X2IBoyRn2ZSWQqySTZnUn2guZbxbQiAB27hJEbvXamhQ==",
       "dev": true,
       "requires": {
         "clone-deep": "^4.0.1",
@@ -1419,56 +1450,56 @@
       }
     },
     "@babel/runtime": {
-      "version": "7.17.8",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.8.tgz",
-      "integrity": "sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz",
+      "integrity": "sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==",
       "requires": {
         "regenerator-runtime": "^0.13.4"
       }
     },
     "@babel/template": {
-      "version": "7.16.7",
-      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
-      "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz",
+      "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==",
       "dev": true,
       "requires": {
-        "@babel/code-frame": "^7.16.7",
-        "@babel/parser": "^7.16.7",
-        "@babel/types": "^7.16.7"
+        "@babel/code-frame": "^7.18.6",
+        "@babel/parser": "^7.18.6",
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/traverse": {
-      "version": "7.17.3",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz",
-      "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.6.tgz",
+      "integrity": "sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw==",
       "dev": true,
       "requires": {
-        "@babel/code-frame": "^7.16.7",
-        "@babel/generator": "^7.17.3",
-        "@babel/helper-environment-visitor": "^7.16.7",
-        "@babel/helper-function-name": "^7.16.7",
-        "@babel/helper-hoist-variables": "^7.16.7",
-        "@babel/helper-split-export-declaration": "^7.16.7",
-        "@babel/parser": "^7.17.3",
-        "@babel/types": "^7.17.0",
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.18.6",
+        "@babel/helper-environment-visitor": "^7.18.6",
+        "@babel/helper-function-name": "^7.18.6",
+        "@babel/helper-hoist-variables": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/parser": "^7.18.6",
+        "@babel/types": "^7.18.6",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       }
     },
     "@babel/types": {
-      "version": "7.17.0",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz",
-      "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==",
+      "version": "7.18.7",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz",
+      "integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-validator-identifier": "^7.16.7",
+        "@babel/helper-validator-identifier": "^7.18.6",
         "to-fast-properties": "^2.0.0"
       }
     },
     "@ctrl/tinycolor": {
-      "version": "3.4.0",
-      "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz",
-      "integrity": "sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ=="
+      "version": "3.4.1",
+      "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz",
+      "integrity": "sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw=="
     },
     "@fortawesome/fontawesome-common-types": {
       "version": "0.3.0",
@@ -1514,9 +1545,9 @@
       }
     },
     "@fortawesome/vue-fontawesome": {
-      "version": "3.0.0-5",
-      "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.0-5.tgz",
-      "integrity": "sha512-aNmBT4bOecrFsZTog1l6AJDQHPP3ocXV+WQ3Ogy8WZCqstB/ahfhH4CPu5i4N9Hw0MBKXqE+LX+NbUxcj8cVTw=="
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.1.tgz",
+      "integrity": "sha512-CdXZJoCS+aEPec26ZP7hWWU3SaJlQPZSCGdgpQ2qGl2HUmtUUNrI3zC4XWdn1JUmh3t5OuDeRG1qB4eGRNSD4A=="
     },
     "@gar/promisify": {
       "version": "1.1.3",
@@ -1573,67 +1604,6 @@
         "postcss": "^7.0.0"
       }
     },
-    "@intlify/core-base": {
-      "version": "9.1.9",
-      "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.9.tgz",
-      "integrity": "sha512-x5T0p/Ja0S8hs5xs+ImKyYckVkL4CzcEXykVYYV6rcbXxJTe2o58IquSqX9bdncVKbRZP7GlBU1EcRaQEEJ+vw==",
-      "requires": {
-        "@intlify/devtools-if": "9.1.9",
-        "@intlify/message-compiler": "9.1.9",
-        "@intlify/message-resolver": "9.1.9",
-        "@intlify/runtime": "9.1.9",
-        "@intlify/shared": "9.1.9",
-        "@intlify/vue-devtools": "9.1.9"
-      }
-    },
-    "@intlify/devtools-if": {
-      "version": "9.1.9",
-      "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.9.tgz",
-      "integrity": "sha512-oKSMKjttG3Ut/1UGEZjSdghuP3fwA15zpDPcjkf/1FjlOIm6uIBGMNS5jXzsZy593u+P/YcnrZD6cD3IVFz9vQ==",
-      "requires": {
-        "@intlify/shared": "9.1.9"
-      }
-    },
-    "@intlify/message-compiler": {
-      "version": "9.1.9",
-      "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.9.tgz",
-      "integrity": "sha512-6YgCMF46Xd0IH2hMRLCssZI3gFG4aywidoWQ3QP4RGYQXQYYfFC54DxhSgfIPpVoPLQ+4AD29eoYmhiHZ+qLFQ==",
-      "requires": {
-        "@intlify/message-resolver": "9.1.9",
-        "@intlify/shared": "9.1.9",
-        "source-map": "0.6.1"
-      }
-    },
-    "@intlify/message-resolver": {
-      "version": "9.1.9",
-      "resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.9.tgz",
-      "integrity": "sha512-Lx/DBpigeK0sz2BBbzv5mu9/dAlt98HxwbG7xLawC3O2xMF9MNWU5FtOziwYG6TDIjNq0O/3ZbOJAxwITIWXEA=="
-    },
-    "@intlify/runtime": {
-      "version": "9.1.9",
-      "resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.9.tgz",
-      "integrity": "sha512-XgPw8+UlHCiie3fI41HPVa/VDJb3/aSH7bLhY1hJvlvNV713PFtb4p4Jo+rlE0gAoMsMCGcsiT982fImolSltg==",
-      "requires": {
-        "@intlify/message-compiler": "9.1.9",
-        "@intlify/message-resolver": "9.1.9",
-        "@intlify/shared": "9.1.9"
-      }
-    },
-    "@intlify/shared": {
-      "version": "9.1.9",
-      "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.9.tgz",
-      "integrity": "sha512-xKGM1d0EAxdDFCWedcYXOm6V5Pfw/TMudd6/qCdEb4tv0hk9EKeg7lwQF1azE0dP2phvx0yXxrt7UQK+IZjNdw=="
-    },
-    "@intlify/vue-devtools": {
-      "version": "9.1.9",
-      "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.9.tgz",
-      "integrity": "sha512-YPehH9uL4vZcGXky4Ev5qQIITnHKIvsD2GKGXgqf+05osMUI6WSEQHaN9USRa318Rs8RyyPCiDfmA0hRu3k7og==",
-      "requires": {
-        "@intlify/message-resolver": "9.1.9",
-        "@intlify/runtime": "9.1.9",
-        "@intlify/shared": "9.1.9"
-      }
-    },
     "@istanbuljs/load-nyc-config": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -1704,13 +1674,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "slash": {
@@ -1810,13 +1780,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "rimraf": {
@@ -1938,13 +1908,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "node-notifier": {
@@ -2082,13 +2052,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "slash": {
@@ -2136,22 +2106,38 @@
       "integrity": "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==",
       "dev": true
     },
+    "@jridgewell/gen-mapping": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
+      "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/set-array": "^1.0.0",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      }
+    },
     "@jridgewell/resolve-uri": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz",
-      "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==",
+      "version": "3.0.8",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz",
+      "integrity": "sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w==",
+      "dev": true
+    },
+    "@jridgewell/set-array": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
+      "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
       "dev": true
     },
     "@jridgewell/sourcemap-codec": {
-      "version": "1.4.11",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz",
-      "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==",
+      "version": "1.4.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
       "dev": true
     },
     "@jridgewell/trace-mapping": {
-      "version": "0.3.4",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz",
-      "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==",
+      "version": "0.3.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz",
+      "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==",
       "dev": true,
       "requires": {
         "@jridgewell/resolve-uri": "^3.0.3",
@@ -2280,7 +2266,7 @@
     "@protobufjs/aspromise": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
-      "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=",
+      "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
       "dev": true
     },
     "@protobufjs/base64": {
@@ -2298,13 +2284,13 @@
     "@protobufjs/eventemitter": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
-      "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=",
+      "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
       "dev": true
     },
     "@protobufjs/fetch": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
-      "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=",
+      "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
       "dev": true,
       "requires": {
         "@protobufjs/aspromise": "^1.1.1",
@@ -2314,31 +2300,31 @@
     "@protobufjs/float": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
-      "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=",
+      "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
       "dev": true
     },
     "@protobufjs/inquire": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
-      "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=",
+      "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
       "dev": true
     },
     "@protobufjs/path": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
-      "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=",
+      "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
       "dev": true
     },
     "@protobufjs/pool": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
-      "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=",
+      "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
       "dev": true
     },
     "@protobufjs/utf8": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
-      "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=",
+      "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
       "dev": true
     },
     "@simonwep/pickr": {
@@ -2472,9 +2458,9 @@
       }
     },
     "@types/babel__traverse": {
-      "version": "7.14.2",
-      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz",
-      "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==",
+      "version": "7.17.1",
+      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz",
+      "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==",
       "dev": true,
       "requires": {
         "@babel/types": "^7.3.0"
@@ -2510,9 +2496,9 @@
       }
     },
     "@types/content-disposition": {
-      "version": "0.5.4",
-      "resolved": "https://registry.npmjs.org/@types/content-disposition/-/content-disposition-0.5.4.tgz",
-      "integrity": "sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ==",
+      "version": "0.5.5",
+      "resolved": "https://registry.npmjs.org/@types/content-disposition/-/content-disposition-0.5.5.tgz",
+      "integrity": "sha512-v6LCdKfK6BwcqMo+wYW05rLS12S0ZO0Fl4w1h4aaZMD7bqT3gVUns6FvLJKGZHQmYn3SX55JWGpziwJRwVgutA==",
       "dev": true
     },
     "@types/cookies": {
@@ -2552,9 +2538,9 @@
       }
     },
     "@types/express-serve-static-core": {
-      "version": "4.17.28",
-      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz",
-      "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==",
+      "version": "4.17.29",
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz",
+      "integrity": "sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==",
       "dev": true,
       "requires": {
         "@types/node": "*",
@@ -2603,9 +2589,9 @@
       "dev": true
     },
     "@types/http-proxy": {
-      "version": "1.17.8",
-      "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
-      "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==",
+      "version": "1.17.9",
+      "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz",
+      "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==",
       "dev": true,
       "requires": {
         "@types/node": "*"
@@ -2686,15 +2672,15 @@
       }
     },
     "@types/json-schema": {
-      "version": "7.0.10",
-      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.10.tgz",
-      "integrity": "sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A==",
+      "version": "7.0.11",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
+      "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
       "dev": true
     },
     "@types/json5": {
       "version": "0.0.29",
       "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
-      "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
+      "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
       "dev": true
     },
     "@types/keygrip": {
@@ -2729,9 +2715,9 @@
       }
     },
     "@types/long": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz",
-      "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==",
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
+      "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==",
       "dev": true
     },
     "@types/mime": {
@@ -2753,9 +2739,9 @@
       "dev": true
     },
     "@types/node": {
-      "version": "17.0.23",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz",
-      "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==",
+      "version": "18.0.0",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz",
+      "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==",
       "dev": true
     },
     "@types/normalize-package-data": {
@@ -2807,7 +2793,7 @@
     "@types/strip-bom": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz",
-      "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=",
+      "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==",
       "dev": true
     },
     "@types/strip-json-comments": {
@@ -2832,9 +2818,9 @@
       }
     },
     "@types/uglify-js": {
-      "version": "3.13.1",
-      "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.1.tgz",
-      "integrity": "sha512-O3MmRAk6ZuAKa9CHgg0Pr0+lUOqoMLpc9AS4R8ano2auvsg7IE8syF3Xh/NPr26TWklxYcqoEEFdzLLs1fV9PQ==",
+      "version": "3.16.0",
+      "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.16.0.tgz",
+      "integrity": "sha512-0yeUr92L3r0GLRnBOvtYK1v2SjqMIqQDHMl7GLb+l2L8+6LSFWEEWEIgVsPdMn5ImLM8qzWT8xFPtQYpp8co0g==",
       "dev": true,
       "requires": {
         "source-map": "^0.6.1"
@@ -2884,9 +2870,9 @@
       },
       "dependencies": {
         "source-map": {
-          "version": "0.7.3",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
-          "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+          "version": "0.7.4",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+          "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
           "dev": true
         }
       }
@@ -2915,6 +2901,49 @@
       "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
       "dev": true
     },
+    "@vue-js-cron/ant": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@vue-js-cron/ant/-/ant-1.1.3.tgz",
+      "integrity": "sha512-E7PbZX/Fwb4w4GYYllnhDx8ywTce3OQ3WS20BPS8EbPlmShmkdvtU9dyNC+C+bGyzXfUwPIdLbtQ1vKzLrMm0A==",
+      "requires": {
+        "@vue-js-cron/core": "3.7.1",
+        "ant-design-vue": "^3.2.12"
+      },
+      "dependencies": {
+        "ant-design-vue": {
+          "version": "3.2.20",
+          "resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-3.2.20.tgz",
+          "integrity": "sha512-YWpMfGaGoRastIXEYfCoJiaRiDHk4chqtYhlKQM5GqPt6NfvrM1Vg2e60yHtjxlZjed91wCMm0rAmyUr7Hwzdg==",
+          "requires": {
+            "@ant-design/colors": "^6.0.0",
+            "@ant-design/icons-vue": "^6.1.0",
+            "@babel/runtime": "^7.10.5",
+            "@ctrl/tinycolor": "^3.4.0",
+            "@simonwep/pickr": "~1.8.0",
+            "array-tree-filter": "^2.1.0",
+            "async-validator": "^4.0.0",
+            "dayjs": "^1.10.5",
+            "dom-align": "^1.12.1",
+            "dom-scroll-into-view": "^2.0.0",
+            "lodash": "^4.17.21",
+            "lodash-es": "^4.17.15",
+            "resize-observer-polyfill": "^1.5.1",
+            "scroll-into-view-if-needed": "^2.2.25",
+            "shallow-equal": "^1.0.0",
+            "vue-types": "^3.0.0",
+            "warning": "^4.0.0"
+          }
+        }
+      }
+    },
+    "@vue-js-cron/core": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/@vue-js-cron/core/-/core-3.7.1.tgz",
+      "integrity": "sha512-aWCkbfCbwpEJwmptY0tRFlxH4ZaVtnmR2Q3f0L8SzSC58cn45VYMe2/eSK53221cBmk/w+18Hq563u+W7Jp9Eg==",
+      "requires": {
+        "mustache": "^4.2.0"
+      }
+    },
     "@vue/babel-helper-vue-jsx-merge-props": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.2.1.tgz",
@@ -2969,15 +2998,15 @@
         "html-tags": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz",
-          "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=",
+          "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==",
           "dev": true
         }
       }
     },
     "@vue/babel-preset-app": {
-      "version": "4.5.17",
-      "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-4.5.17.tgz",
-      "integrity": "sha512-iFv9J3F5VKUPcbx+TqW5qhGmAVyXQxPRpKpPOuTLFIVTzg+iwJnrqVbL4kJU5ECGDxPESW2oCVgxv9bTlDPu7w==",
+      "version": "4.5.19",
+      "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-4.5.19.tgz",
+      "integrity": "sha512-VCNRiAt2P/bLo09rYt3DLe6xXUMlhJwrvU18Ddd/lYJgC7s8+wvhgYs+MTx4OiAXdu58drGwSBO9SPx7C6J82Q==",
       "dev": true,
       "requires": {
         "@babel/core": "^7.11.0",
@@ -3075,7 +3104,7 @@
         "html-tags": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz",
-          "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=",
+          "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==",
           "dev": true
         }
       }
@@ -3092,17 +3121,17 @@
       }
     },
     "@vue/cli": {
-      "version": "4.5.17",
-      "resolved": "https://registry.npmjs.org/@vue/cli/-/cli-4.5.17.tgz",
-      "integrity": "sha512-73nK2o/o7Wk9myPySdjxpMzABLynGmnQbJ5wz3CJ9SFrss8Y2LwLAnzlO77mr3uA2nFPdTJbkbUcZlvBWCVSrA==",
+      "version": "4.5.19",
+      "resolved": "https://registry.npmjs.org/@vue/cli/-/cli-4.5.19.tgz",
+      "integrity": "sha512-y+rPxbhwMNf9ZL3K1XuRDHaggnX4fVVDsm3oFzbZXKxK674Hi+cM+dc17TfKWNH8LbXiKH6R5KEWFoqIM/AbOA==",
       "dev": true,
       "requires": {
         "@types/ejs": "^2.7.0",
         "@types/inquirer": "^6.5.0",
-        "@vue/cli-shared-utils": "^4.5.17",
-        "@vue/cli-ui": "^4.5.17",
-        "@vue/cli-ui-addon-webpack": "^4.5.17",
-        "@vue/cli-ui-addon-widgets": "^4.5.17",
+        "@vue/cli-shared-utils": "^4.5.19",
+        "@vue/cli-ui": "^4.5.19",
+        "@vue/cli-ui-addon-webpack": "^4.5.19",
+        "@vue/cli-ui-addon-widgets": "^4.5.19",
         "boxen": "^4.1.0",
         "cmd-shim": "^3.0.3",
         "commander": "^2.20.0",
@@ -3156,12 +3185,12 @@
           }
         },
         "resolve": {
-          "version": "1.22.0",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
-          "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
+          "version": "1.22.1",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+          "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
           "dev": true,
           "requires": {
-            "is-core-module": "^2.8.1",
+            "is-core-module": "^2.9.0",
             "path-parse": "^1.0.7",
             "supports-preserve-symlinks-flag": "^1.0.0"
           }
@@ -3190,20 +3219,20 @@
       }
     },
     "@vue/cli-overlay": {
-      "version": "4.5.17",
-      "resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-4.5.17.tgz",
-      "integrity": "sha512-QKKp66VbMg+X8Qh0wgXSwgxLfxY7EIkZkV6bZ6nFqBx8xtaJQVDbTL+4zcUPPA6nygbIcQ6gvTinNEqIqX6FUQ==",
+      "version": "4.5.19",
+      "resolved": "https://registry.npmjs.org/@vue/cli-overlay/-/cli-overlay-4.5.19.tgz",
+      "integrity": "sha512-GdxvNSmOw7NHIazCO8gTK+xZbaOmScTtxj6eHVeMbYpDYVPJ+th3VMLWNpw/b6uOjwzzcyKlA5dRQ1DAb+gF/g==",
       "dev": true
     },
     "@vue/cli-plugin-babel": {
-      "version": "4.5.17",
-      "resolved": "https://registry.npmjs.org/@vue/cli-plugin-babel/-/cli-plugin-babel-4.5.17.tgz",
-      "integrity": "sha512-6kZuc3PdoUvGAnndUq6+GqjIXn3bqdTR8lOcAb1BH2b4N7IKGlmzcipALGS23HLVMAvDgNuUS7vf0unin9j2cg==",
+      "version": "4.5.19",
+      "resolved": "https://registry.npmjs.org/@vue/cli-plugin-babel/-/cli-plugin-babel-4.5.19.tgz",
+      "integrity": "sha512-8ebXzaMW9KNTMAN6+DzkhFsjty1ieqT7hIW5Lbk4v30Qhfjkms7lBWyXPGkoq+wAikXFa1Gnam2xmWOBqDDvWg==",
       "dev": true,
       "requires": {
         "@babel/core": "^7.11.0",
-        "@vue/babel-preset-app": "^4.5.17",
-        "@vue/cli-shared-utils": "^4.5.17",
+        "@vue/babel-preset-app": "^4.5.19",
+        "@vue/cli-shared-utils": "^4.5.19",
         "babel-loader": "^8.1.0",
         "cache-loader": "^4.1.0",
         "thread-loader": "^2.1.3",
@@ -3211,12 +3240,12 @@
       }
     },
     "@vue/cli-plugin-eslint": {
-      "version": "4.5.17",
-      "resolved": "https://registry.npmjs.org/@vue/cli-plugin-eslint/-/cli-plugin-eslint-4.5.17.tgz",
-      "integrity": "sha512-bVNDP+SuWcuJrBMc+JLaKvlxx25XKIlZBa+zzFnxhHZlwPZ7CeBD3e2wnsygJyPoKgDZcZwDgmEz1BZzMEjsNw==",
+      "version": "4.5.19",
+      "resolved": "https://registry.npmjs.org/@vue/cli-plugin-eslint/-/cli-plugin-eslint-4.5.19.tgz",
+      "integrity": "sha512-53sa4Pu9j5KajesFlj494CcO8vVo3e3nnZ1CCKjGGnrF90id1rUeepcFfz5XjwfEtbJZp2x/NoX/EZE6zCzSFQ==",
       "dev": true,
       "requires": {
-        "@vue/cli-shared-utils": "^4.5.17",
+        "@vue/cli-shared-utils": "^4.5.19",
         "eslint-loader": "^2.2.1",
         "globby": "^9.2.0",
         "inquirer": "^7.1.0",
@@ -3225,24 +3254,24 @@
       }
     },
     "@vue/cli-plugin-router": {
-      "version": "4.5.17",
-      "resolved": "https://registry.npmjs.org/@vue/cli-plugin-router/-/cli-plugin-router-4.5.17.tgz",
-      "integrity": "sha512-9r9CSwqv2+39XHQPDZJ0uaTtTP7oe0Gx17m7kBhHG3FA7R7AOSk2aVzhHZmDRhzlOxjx9kQSvrOSMfUG0kV4dQ==",
+      "version": "4.5.19",
+      "resolved": "https://registry.npmjs.org/@vue/cli-plugin-router/-/cli-plugin-router-4.5.19.tgz",
+      "integrity": "sha512-3icGzH1IbVYmMMsOwYa0lal/gtvZLebFXdE5hcQJo2mnTwngXGMTyYAzL56EgHBPjbMmRpyj6Iw9k4aVInVX6A==",
       "dev": true,
       "requires": {
-        "@vue/cli-shared-utils": "^4.5.17"
+        "@vue/cli-shared-utils": "^4.5.19"
       }
     },
     "@vue/cli-plugin-unit-jest": {
-      "version": "4.5.17",
-      "resolved": "https://registry.npmjs.org/@vue/cli-plugin-unit-jest/-/cli-plugin-unit-jest-4.5.17.tgz",
-      "integrity": "sha512-Ta8hx68Y252umik1yD50dyyrwhzj4KzTEpngY9YKB6bY6pga9GK2olqyrb3+2X8o6tnSQkTFz+UcobfRQJDs5A==",
+      "version": "4.5.19",
+      "resolved": "https://registry.npmjs.org/@vue/cli-plugin-unit-jest/-/cli-plugin-unit-jest-4.5.19.tgz",
+      "integrity": "sha512-yX61mpeU7DnjOv+Lxtjmr3pzESqBLIXeTK4MJpa/UdzrhnylHP4r6mCYETNLEYtxp8WZUXPjZFIzrKn5poZPJg==",
       "dev": true,
       "requires": {
         "@babel/core": "^7.11.0",
         "@babel/plugin-transform-modules-commonjs": "^7.9.6",
         "@types/jest": "^24.0.19",
-        "@vue/cli-shared-utils": "^4.5.17",
+        "@vue/cli-shared-utils": "^4.5.19",
         "babel-core": "^7.0.0-bridge.0",
         "babel-jest": "^24.9.0",
         "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
@@ -3303,13 +3332,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "slash": {
@@ -3321,7 +3350,7 @@
         "source-map": {
           "version": "0.5.7",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
           "dev": true
         },
         "supports-color": {
@@ -3355,15 +3384,15 @@
       }
     },
     "@vue/cli-plugin-vuex": {
-      "version": "4.5.17",
-      "resolved": "https://registry.npmjs.org/@vue/cli-plugin-vuex/-/cli-plugin-vuex-4.5.17.tgz",
-      "integrity": "sha512-ck/ju2T2dmPKLWK/5QctNJs9SCb+eSZbbmr8neFkMc7GlbXw6qLWw5v3Vpd4KevdQA8QuQOA1pjUmzpCiU/mYQ==",
+      "version": "4.5.19",
+      "resolved": "https://registry.npmjs.org/@vue/cli-plugin-vuex/-/cli-plugin-vuex-4.5.19.tgz",
+      "integrity": "sha512-DUmfdkG3pCdkP7Iznd87RfE9Qm42mgp2hcrNcYQYSru1W1gX2dG/JcW8bxmeGSa06lsxi9LEIc/QD1yPajSCZw==",
       "dev": true
     },
     "@vue/cli-service": {
-      "version": "4.5.17",
-      "resolved": "https://registry.npmjs.org/@vue/cli-service/-/cli-service-4.5.17.tgz",
-      "integrity": "sha512-MqfkRYIcIUACe3nYlzNrYstJTWRXHlIqh6JCkbWbdnXWN+IfaVdlG8zw5Q0DVcSdGvkevUW7zB4UhtZB4uyAcA==",
+      "version": "4.5.19",
+      "resolved": "https://registry.npmjs.org/@vue/cli-service/-/cli-service-4.5.19.tgz",
+      "integrity": "sha512-+Wpvj8fMTCt9ZPOLu5YaLkFCQmB4MrZ26aRmhhKiCQ/4PMoL6mLezfqdt6c+m2htM+1WV5RunRo+0WHl2DfwZA==",
       "dev": true,
       "requires": {
         "@intervolga/optimize-cssnano-plugin": "^1.0.5",
@@ -3372,10 +3401,10 @@
         "@types/minimist": "^1.2.0",
         "@types/webpack": "^4.0.0",
         "@types/webpack-dev-server": "^3.11.0",
-        "@vue/cli-overlay": "^4.5.17",
-        "@vue/cli-plugin-router": "^4.5.17",
-        "@vue/cli-plugin-vuex": "^4.5.17",
-        "@vue/cli-shared-utils": "^4.5.17",
+        "@vue/cli-overlay": "^4.5.19",
+        "@vue/cli-plugin-router": "^4.5.19",
+        "@vue/cli-plugin-vuex": "^4.5.19",
+        "@vue/cli-shared-utils": "^4.5.19",
         "@vue/component-compiler-utils": "^3.1.2",
         "@vue/preload-webpack-plugin": "^1.1.0",
         "@vue/web-component-wrapper": "^1.2.0",
@@ -3515,7 +3544,7 @@
             "hash-sum": {
               "version": "1.0.2",
               "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
-              "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=",
+              "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
               "dev": true
             }
           }
@@ -3533,16 +3562,16 @@
           },
           "dependencies": {
             "json5": {
-              "version": "2.2.1",
-              "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
-              "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
+              "version": "2.2.3",
+              "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+              "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
               "dev": true,
               "optional": true
             },
             "loader-utils": {
-              "version": "2.0.2",
-              "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
-              "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
+              "version": "2.0.4",
+              "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+              "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -3567,9 +3596,9 @@
       }
     },
     "@vue/cli-shared-utils": {
-      "version": "4.5.17",
-      "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-4.5.17.tgz",
-      "integrity": "sha512-VoFNdxvTW4vZu3ne+j1Mf7mU99J2SAoRVn9XPrsouTUUJablglM8DASk7Ixhsh6ymyL/W9EADQFR6Pgj8Ujjuw==",
+      "version": "4.5.19",
+      "resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-4.5.19.tgz",
+      "integrity": "sha512-JYpdsrC/d9elerKxbEUtmSSU6QRM60rirVubOewECHkBHj+tLNznWq/EhCjswywtePyLaMUK25eTqnTSZlEE+g==",
       "dev": true,
       "requires": {
         "@achrinza/node-ipc": "9.2.2",
@@ -3624,13 +3653,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "lru-cache": {
@@ -3675,14 +3704,14 @@
       }
     },
     "@vue/cli-ui": {
-      "version": "4.5.17",
-      "resolved": "https://registry.npmjs.org/@vue/cli-ui/-/cli-ui-4.5.17.tgz",
-      "integrity": "sha512-x5o+RUNkPLO6wDNY5/Sec9ZuZExzARU8KkP2SwM2SWLirkjKgLVvyL4/snAIWwRLxsxXVuyZ8YJdqnWidixzCg==",
+      "version": "4.5.19",
+      "resolved": "https://registry.npmjs.org/@vue/cli-ui/-/cli-ui-4.5.19.tgz",
+      "integrity": "sha512-wiZ63+uqB1b2+AH9rUkubvQEzDCwEBLJZ4xaTkRlI+eSPUj1nZM2SzvwbWo2aL0ObFAQwWaXwqjh2VW3zQEvJw==",
       "dev": true,
       "requires": {
         "@achrinza/node-ipc": "9.2.2",
         "@akryum/winattr": "^3.0.0",
-        "@vue/cli-shared-utils": "^4.5.17",
+        "@vue/cli-shared-utils": "^4.5.19",
         "apollo-server-express": "^2.13.1",
         "clone": "^2.1.1",
         "deepmerge": "^4.2.2",
@@ -3713,7 +3742,7 @@
         "clone": {
           "version": "2.1.2",
           "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
-          "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
+          "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
           "dev": true
         },
         "lru-cache": {
@@ -3734,48 +3763,48 @@
       }
     },
     "@vue/cli-ui-addon-webpack": {
-      "version": "4.5.17",
-      "resolved": "https://registry.npmjs.org/@vue/cli-ui-addon-webpack/-/cli-ui-addon-webpack-4.5.17.tgz",
-      "integrity": "sha512-AZMnDzToM2uxW/73mfjJweea3atC5sxOC3Nel5UEFnQK0hWN0/8NW6nPAiKDc+kJpZWFb7Y6ReP2hwYizUJK2w==",
+      "version": "4.5.19",
+      "resolved": "https://registry.npmjs.org/@vue/cli-ui-addon-webpack/-/cli-ui-addon-webpack-4.5.19.tgz",
+      "integrity": "sha512-ESkNIVbEMGwe42OcGbfF4fQD/JRHiN4notSGkQ5fnjVnEkNlH4UJotoNgea4lmnnCIMjMEN4wz3f+ADXKjzOlA==",
       "dev": true
     },
     "@vue/cli-ui-addon-widgets": {
-      "version": "4.5.17",
-      "resolved": "https://registry.npmjs.org/@vue/cli-ui-addon-widgets/-/cli-ui-addon-widgets-4.5.17.tgz",
-      "integrity": "sha512-K49weNsBggUL54Etdqml0hR3PpNzQSXUxC0G52qGNuZwPPxpZfZSQIH8GQ4jBTS8ySXmQYDT99DyxKSedE7McQ==",
+      "version": "4.5.19",
+      "resolved": "https://registry.npmjs.org/@vue/cli-ui-addon-widgets/-/cli-ui-addon-widgets-4.5.19.tgz",
+      "integrity": "sha512-MuujsH7WHSe4UJVok2EbmiTW/Ig3dlUMYqr1cvRY+G5YDpzychPetiQsHzoJsBc5yfEdRRzmJ04KAuzfAzIA1g==",
       "dev": true
     },
     "@vue/compiler-core": {
-      "version": "3.2.31",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.31.tgz",
-      "integrity": "sha512-aKno00qoA4o+V/kR6i/pE+aP+esng5siNAVQ422TkBNM6qA4veXiZbSe8OTXHXquEi/f6Akc+nLfB4JGfe4/WQ==",
+      "version": "3.2.37",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.37.tgz",
+      "integrity": "sha512-81KhEjo7YAOh0vQJoSmAD68wLfYqJvoiD4ulyedzF+OEk/bk6/hx3fTNVfuzugIIaTrOx4PGx6pAiBRe5e9Zmg==",
       "requires": {
         "@babel/parser": "^7.16.4",
-        "@vue/shared": "3.2.31",
+        "@vue/shared": "3.2.37",
         "estree-walker": "^2.0.2",
         "source-map": "^0.6.1"
       }
     },
     "@vue/compiler-dom": {
-      "version": "3.2.31",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.31.tgz",
-      "integrity": "sha512-60zIlFfzIDf3u91cqfqy9KhCKIJgPeqxgveH2L+87RcGU/alT6BRrk5JtUso0OibH3O7NXuNOQ0cDc9beT0wrg==",
+      "version": "3.2.37",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.37.tgz",
+      "integrity": "sha512-yxJLH167fucHKxaqXpYk7x8z7mMEnXOw3G2q62FTkmsvNxu4FQSu5+3UMb+L7fjKa26DEzhrmCxAgFLLIzVfqQ==",
       "requires": {
-        "@vue/compiler-core": "3.2.31",
-        "@vue/shared": "3.2.31"
+        "@vue/compiler-core": "3.2.37",
+        "@vue/shared": "3.2.37"
       }
     },
     "@vue/compiler-sfc": {
-      "version": "3.2.31",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.31.tgz",
-      "integrity": "sha512-748adc9msSPGzXgibHiO6T7RWgfnDcVQD+VVwYgSsyyY8Ans64tALHZANrKtOzvkwznV/F4H7OAod/jIlp/dkQ==",
+      "version": "3.2.37",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.37.tgz",
+      "integrity": "sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg==",
       "requires": {
         "@babel/parser": "^7.16.4",
-        "@vue/compiler-core": "3.2.31",
-        "@vue/compiler-dom": "3.2.31",
-        "@vue/compiler-ssr": "3.2.31",
-        "@vue/reactivity-transform": "3.2.31",
-        "@vue/shared": "3.2.31",
+        "@vue/compiler-core": "3.2.37",
+        "@vue/compiler-dom": "3.2.37",
+        "@vue/compiler-ssr": "3.2.37",
+        "@vue/reactivity-transform": "3.2.37",
+        "@vue/shared": "3.2.37",
         "estree-walker": "^2.0.2",
         "magic-string": "^0.25.7",
         "postcss": "^8.1.10",
@@ -3788,11 +3817,11 @@
           "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
         },
         "postcss": {
-          "version": "8.4.12",
-          "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz",
-          "integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==",
+          "version": "8.4.14",
+          "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
+          "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
           "requires": {
-            "nanoid": "^3.3.1",
+            "nanoid": "^3.3.4",
             "picocolors": "^1.0.0",
             "source-map-js": "^1.0.2"
           }
@@ -3800,12 +3829,12 @@
       }
     },
     "@vue/compiler-ssr": {
-      "version": "3.2.31",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.31.tgz",
-      "integrity": "sha512-mjN0rqig+A8TVDnsGPYJM5dpbjlXeHUm2oZHZwGyMYiGT/F4fhJf/cXy8QpjnLQK4Y9Et4GWzHn9PS8AHUnSkw==",
+      "version": "3.2.37",
+      "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.37.tgz",
+      "integrity": "sha512-7mQJD7HdXxQjktmsWp/J67lThEIcxLemz1Vb5I6rYJHR5vI+lON3nPGOH3ubmbvYGt8xEUaAr1j7/tIFWiEOqw==",
       "requires": {
-        "@vue/compiler-dom": "3.2.31",
-        "@vue/shared": "3.2.31"
+        "@vue/compiler-dom": "3.2.37",
+        "@vue/shared": "3.2.37"
       }
     },
     "@vue/component-compiler-utils": {
@@ -3828,7 +3857,7 @@
         "hash-sum": {
           "version": "1.0.2",
           "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
-          "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=",
+          "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
           "dev": true
         },
         "lru-cache": {
@@ -3844,15 +3873,15 @@
         "yallist": {
           "version": "2.1.2",
           "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
-          "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+          "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
           "dev": true
         }
       }
     },
     "@vue/devtools-api": {
-      "version": "6.1.3",
-      "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.1.3.tgz",
-      "integrity": "sha512-79InfO2xHv+WHIrH1bHXQUiQD/wMls9qBk6WVwGCbdwP7/3zINtvqPNMtmSHXsIKjvUAHc8L0ouOj6ZQQRmcXg=="
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.2.0.tgz",
+      "integrity": "sha512-pF1G4wky+hkifDiZSWn8xfuLOJI1ZXtuambpBEYaf7Xaf6zC/pM29rvAGpd3qaGXnr4BAXU1Pxz/VfvBGwexGA=="
     },
     "@vue/eslint-config-standard": {
       "version": "5.1.2",
@@ -3872,62 +3901,62 @@
       "dev": true
     },
     "@vue/reactivity": {
-      "version": "3.2.31",
-      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.31.tgz",
-      "integrity": "sha512-HVr0l211gbhpEKYr2hYe7hRsV91uIVGFYNHj73njbARVGHQvIojkImKMaZNDdoDZOIkMsBc9a1sMqR+WZwfSCw==",
+      "version": "3.2.37",
+      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.37.tgz",
+      "integrity": "sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A==",
       "requires": {
-        "@vue/shared": "3.2.31"
+        "@vue/shared": "3.2.37"
       }
     },
     "@vue/reactivity-transform": {
-      "version": "3.2.31",
-      "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.31.tgz",
-      "integrity": "sha512-uS4l4z/W7wXdI+Va5pgVxBJ345wyGFKvpPYtdSgvfJfX/x2Ymm6ophQlXXB6acqGHtXuBqNyyO3zVp9b1r0MOA==",
+      "version": "3.2.37",
+      "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz",
+      "integrity": "sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg==",
       "requires": {
         "@babel/parser": "^7.16.4",
-        "@vue/compiler-core": "3.2.31",
-        "@vue/shared": "3.2.31",
+        "@vue/compiler-core": "3.2.37",
+        "@vue/shared": "3.2.37",
         "estree-walker": "^2.0.2",
         "magic-string": "^0.25.7"
       }
     },
     "@vue/runtime-core": {
-      "version": "3.2.31",
-      "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.31.tgz",
-      "integrity": "sha512-Kcog5XmSY7VHFEMuk4+Gap8gUssYMZ2+w+cmGI6OpZWYOEIcbE0TPzzPHi+8XTzAgx1w/ZxDFcXhZeXN5eKWsA==",
+      "version": "3.2.37",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.37.tgz",
+      "integrity": "sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ==",
       "requires": {
-        "@vue/reactivity": "3.2.31",
-        "@vue/shared": "3.2.31"
+        "@vue/reactivity": "3.2.37",
+        "@vue/shared": "3.2.37"
       }
     },
     "@vue/runtime-dom": {
-      "version": "3.2.31",
-      "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.31.tgz",
-      "integrity": "sha512-N+o0sICVLScUjfLG7u9u5XCjvmsexAiPt17GNnaWHJUfsKed5e85/A3SWgKxzlxx2SW/Hw7RQxzxbXez9PtY3g==",
+      "version": "3.2.37",
+      "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.37.tgz",
+      "integrity": "sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw==",
       "requires": {
-        "@vue/runtime-core": "3.2.31",
-        "@vue/shared": "3.2.31",
+        "@vue/runtime-core": "3.2.37",
+        "@vue/shared": "3.2.37",
         "csstype": "^2.6.8"
       }
     },
     "@vue/server-renderer": {
-      "version": "3.2.31",
-      "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.31.tgz",
-      "integrity": "sha512-8CN3Zj2HyR2LQQBHZ61HexF5NReqngLT3oahyiVRfSSvak+oAvVmu8iNLSu6XR77Ili2AOpnAt1y8ywjjqtmkg==",
+      "version": "3.2.37",
+      "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.37.tgz",
+      "integrity": "sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA==",
       "requires": {
-        "@vue/compiler-ssr": "3.2.31",
-        "@vue/shared": "3.2.31"
+        "@vue/compiler-ssr": "3.2.37",
+        "@vue/shared": "3.2.37"
       }
     },
     "@vue/shared": {
-      "version": "3.2.31",
-      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.31.tgz",
-      "integrity": "sha512-ymN2pj6zEjiKJZbrf98UM2pfDd6F2H7ksKw7NDt/ZZ1fh5Ei39X5tABugtT03ZRlWd9imccoK0hE8hpjpU7irQ=="
+      "version": "3.2.37",
+      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.37.tgz",
+      "integrity": "sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw=="
     },
     "@vue/test-utils": {
-      "version": "2.0.0-rc.17",
-      "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.0.0-rc.17.tgz",
-      "integrity": "sha512-7LHZKsFRV/HqDoMVY+cJamFzgHgsrmQFalROHC5FMWrzPzd+utG5e11krj1tVsnxYufGA2ABShX4nlcHXED+zQ==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.0.0.tgz",
+      "integrity": "sha512-zL5kygNq7hONrO1CzaUGprEAklAX+pH8J1MPMCU3Rd2xtSYkZ+PmKU3oEDRg8VAGdL5lNJHzDgrud5amFPtirw==",
       "dev": true
     },
     "@vue/web-component-wrapper": {
@@ -4133,9 +4162,9 @@
       "dev": true
     },
     "abab": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
-      "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==",
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
+      "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
       "dev": true
     },
     "abbrev": {
@@ -4182,9 +4211,9 @@
       "dev": true
     },
     "address": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz",
-      "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/address/-/address-1.2.0.tgz",
+      "integrity": "sha512-tNEZYz5G/zYunxFm7sfhAxkXEuLj3K6BKwv6ZURlsF6yiUQ65z0Q2wZW9L5cPUl9ocofGvXOdFYbFHp0+6MOig==",
       "dev": true
     },
     "agent-base": {
@@ -4240,13 +4269,7 @@
     "alphanum-sort": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
-      "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
-      "dev": true
-    },
-    "amdefine": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
-      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+      "integrity": "sha512-0FcBfdcmaumGPQ0qPn7Q5qTgz/ooXgIyp1rf8ik5bGX8mpE2YHjC0P/eyQvxu1GURYQgq9ozf2mteQ5ZD9YiyQ==",
       "dev": true
     },
     "ansi-align": {
@@ -4319,7 +4342,7 @@
     "ansi-regex": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+      "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="
     },
     "ansi-styles": {
       "version": "4.3.0",
@@ -4330,21 +4353,22 @@
       }
     },
     "ant-design-vue": {
-      "version": "2.2.8",
-      "resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.2.8.tgz",
-      "integrity": "sha512-3graq9/gCfJQs6hznrHV6sa9oDmk/D1H3Oo0vLdVpPS/I61fZPk8NEyNKCHpNA6fT2cx6xx9U3QS63uuyikg/Q==",
+      "version": "3.2.9",
+      "resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-3.2.9.tgz",
+      "integrity": "sha512-fnZJpAf4tYAPGBALD9dv8VBmeqfJ+xPt87DfgY1/JI6x3hn6Gfge7voF1GkS0yVT0zLyzc2aTWkDVFWKB5iupA==",
       "requires": {
-        "@ant-design/icons-vue": "^6.0.0",
+        "@ant-design/colors": "^6.0.0",
+        "@ant-design/icons-vue": "^6.1.0",
         "@babel/runtime": "^7.10.5",
+        "@ctrl/tinycolor": "^3.4.0",
         "@simonwep/pickr": "~1.8.0",
         "array-tree-filter": "^2.1.0",
-        "async-validator": "^3.3.0",
+        "async-validator": "^4.0.0",
+        "dayjs": "^1.10.5",
         "dom-align": "^1.12.1",
         "dom-scroll-into-view": "^2.0.0",
         "lodash": "^4.17.21",
         "lodash-es": "^4.17.15",
-        "moment": "^2.27.0",
-        "omit.js": "^2.0.0",
         "resize-observer-polyfill": "^1.5.1",
         "scroll-into-view-if-needed": "^2.2.25",
         "shallow-equal": "^1.0.0",
@@ -4352,32 +4376,72 @@
         "warning": "^4.0.0"
       }
     },
+    "antd": {
+      "version": "4.21.4",
+      "resolved": "https://registry.npmjs.org/antd/-/antd-4.21.4.tgz",
+      "integrity": "sha512-seSXyzVwfOI0a9/HIxUQ41nVJpR8hHn+DbBlJTCOM92Q56Fvw0FlbtZuNMA2gaOkDzyPTnp4W7adlbaqkGsvog==",
+      "requires": {
+        "@ant-design/colors": "^6.0.0",
+        "@ant-design/icons": "^4.7.0",
+        "@ant-design/react-slick": "~0.29.1",
+        "@babel/runtime": "^7.18.3",
+        "@ctrl/tinycolor": "^3.4.0",
+        "classnames": "^2.2.6",
+        "copy-to-clipboard": "^3.2.0",
+        "lodash": "^4.17.21",
+        "memoize-one": "^6.0.0",
+        "moment": "^2.29.2",
+        "rc-cascader": "~3.6.0",
+        "rc-checkbox": "~2.3.0",
+        "rc-collapse": "~3.3.0",
+        "rc-dialog": "~8.9.0",
+        "rc-drawer": "~4.4.2",
+        "rc-dropdown": "~4.0.0",
+        "rc-field-form": "~1.26.1",
+        "rc-image": "~5.7.0",
+        "rc-input": "~0.0.1-alpha.5",
+        "rc-input-number": "~7.3.0",
+        "rc-mentions": "~1.8.0",
+        "rc-menu": "~9.6.0",
+        "rc-motion": "^2.5.1",
+        "rc-notification": "~4.6.0",
+        "rc-pagination": "~3.1.16",
+        "rc-picker": "~2.6.8",
+        "rc-progress": "~3.3.2",
+        "rc-rate": "~2.9.0",
+        "rc-resize-observer": "^1.2.0",
+        "rc-segmented": "~2.1.0",
+        "rc-select": "~14.1.1",
+        "rc-slider": "~10.0.0",
+        "rc-steps": "~4.1.0",
+        "rc-switch": "~3.2.0",
+        "rc-table": "~7.24.0",
+        "rc-tabs": "~11.16.0",
+        "rc-textarea": "~0.3.0",
+        "rc-tooltip": "~5.1.1",
+        "rc-tree": "~5.6.5",
+        "rc-tree-select": "~5.4.0",
+        "rc-trigger": "^5.2.10",
+        "rc-upload": "~4.3.0",
+        "rc-util": "^5.22.5",
+        "scroll-into-view-if-needed": "^2.2.25"
+      }
+    },
     "antd-theme-generator": {
-      "version": "1.2.10",
-      "resolved": "https://registry.npmjs.org/antd-theme-generator/-/antd-theme-generator-1.2.10.tgz",
-      "integrity": "sha512-Eh/5bJP7SejZCTOg1Rq4WB9PkfGXEKo3XWRCFj6Cf1Zsp76Jc9eiXUOijQ2YMtkhLMN2RJOnaNR+OOSpfAonDw==",
+      "version": "1.2.11",
+      "resolved": "https://registry.npmjs.org/antd-theme-generator/-/antd-theme-generator-1.2.11.tgz",
+      "integrity": "sha512-7A3lXyLb7eD7MXK7aSgZZ4DxQEdhZwyKhzIm70orUZPQJ8N8TWhZphyOWSGCe8yUqGQhi8PcpM2pLmTriZyKBw==",
       "requires": {
         "glob": "^7.1.3",
         "hash.js": "^1.1.5",
         "less": "^3.9.0",
-        "less-bundle-promise": "^1.0.7",
+        "less-bundle-promise": "^1.0.11",
         "less-plugin-npm-import": "^2.1.0",
         "postcss": "^6.0.21",
         "postcss-less": "^3.1.4",
         "strip-css-comments": "^4.1.0"
       },
       "dependencies": {
-        "ajv": {
-          "version": "6.6.2",
-          "bundled": true,
-          "optional": true,
-          "requires": {
-            "fast-deep-equal": "^2.0.1",
-            "fast-json-stable-stringify": "^2.0.0",
-            "json-schema-traverse": "^0.4.1",
-            "uri-js": "^4.2.2"
-          }
-        },
         "ansi-styles": {
           "version": "3.2.1",
           "bundled": true,
@@ -4527,11 +4591,6 @@
           "bundled": true,
           "optional": true
         },
-        "fast-deep-equal": {
-          "version": "2.0.1",
-          "bundled": true,
-          "optional": true
-        },
         "fast-json-stable-stringify": {
           "version": "2.0.0",
           "bundled": true,
@@ -4593,6 +4652,24 @@
           "requires": {
             "ajv": "^6.5.5",
             "har-schema": "^2.0.0"
+          },
+          "dependencies": {
+            "ajv": {
+              "version": "6.6.2",
+              "bundled": true,
+              "optional": true,
+              "requires": {
+                "fast-deep-equal": "^2.0.1",
+                "fast-json-stable-stringify": "^2.0.0",
+                "json-schema-traverse": "^0.4.1",
+                "uri-js": "^4.2.2"
+              }
+            },
+            "fast-deep-equal": {
+              "version": "2.0.1",
+              "bundled": true,
+              "optional": true
+            }
           }
         },
         "has-flag": {
@@ -4708,6 +4785,10 @@
               "requires": {
                 "asap": "~2.0.3"
               }
+            },
+            "resolve": {
+              "version": "1.1.7",
+              "bundled": true
             }
           }
         },
@@ -4781,12 +4862,6 @@
             "chalk": "^2.4.1",
             "source-map": "^0.6.1",
             "supports-color": "^5.4.0"
-          },
-          "dependencies": {
-            "source-map": {
-              "version": "0.6.1",
-              "bundled": true
-            }
           }
         },
         "promise": {
@@ -4844,10 +4919,6 @@
             "uuid": "^3.3.2"
           }
         },
-        "resolve": {
-          "version": "1.1.7",
-          "bundled": true
-        },
         "safe-buffer": {
           "version": "5.1.2",
           "bundled": true,
@@ -4860,8 +4931,7 @@
         },
         "source-map": {
           "version": "0.6.1",
-          "bundled": true,
-          "optional": true
+          "bundled": true
         },
         "sshpk": {
           "version": "1.15.2",
@@ -4963,7 +5033,7 @@
     "any-promise": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
-      "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=",
+      "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
       "dev": true
     },
     "anymatch": {
@@ -4997,9 +5067,9 @@
       }
     },
     "apollo-graphql": {
-      "version": "0.9.5",
-      "resolved": "https://registry.npmjs.org/apollo-graphql/-/apollo-graphql-0.9.5.tgz",
-      "integrity": "sha512-RGt5k2JeBqrmnwRM0VOgWFiGKlGJMfmiif/4JvdaEqhMJ+xqe/9cfDYzXfn33ke2eWixsAbjEbRfy8XbaN9nTw==",
+      "version": "0.9.7",
+      "resolved": "https://registry.npmjs.org/apollo-graphql/-/apollo-graphql-0.9.7.tgz",
+      "integrity": "sha512-bezL9ItUWUGHTm1bI/XzIgiiZbhXpsC7uxk4UxFPmcVJwJsDc3ayZ99oXxAaK+3Rbg/IoqrHckA6CwmkCsbaSA==",
       "dev": true,
       "requires": {
         "core-js-pure": "^3.10.2",
@@ -5038,9 +5108,9 @@
       }
     },
     "apollo-server-core": {
-      "version": "2.25.3",
-      "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.25.3.tgz",
-      "integrity": "sha512-Midow3uZoJ9TjFNeCNSiWElTVZlvmB7G7tG6PPoxIR9Px90/v16Q6EzunDIO0rTJHRC3+yCwZkwtf8w2AcP0sA==",
+      "version": "2.25.4",
+      "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.25.4.tgz",
+      "integrity": "sha512-1u3BnFKbCt6F9SPM7ZoWmtHK6ubme56H8hV5Mjv3KbfSairU76SU79IhO05BEJE57S6N+ddb1rm3Uk93X6YeGw==",
       "dev": true,
       "requires": {
         "@apollographql/apollo-tools": "^0.5.0",
@@ -5095,9 +5165,9 @@
       "dev": true
     },
     "apollo-server-express": {
-      "version": "2.25.3",
-      "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.25.3.tgz",
-      "integrity": "sha512-tTFYn0oKH2qqLwVj7Ez2+MiKleXACODiGh5IxsB7VuYCPMAi9Yl8iUSlwTjQUvgCWfReZjnf0vFL2k5YhDlrtQ==",
+      "version": "2.25.4",
+      "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.25.4.tgz",
+      "integrity": "sha512-1Yd9DscLlCP5BhfAkNxg+aGcaTKnL36FyezdL7Iqc+KelON5PAyX8qpAChKL8Z3L2YHJzIk/Haf4dFJLKUjx9w==",
       "dev": true,
       "requires": {
         "@apollographql/graphql-playground-html": "1.6.27",
@@ -5107,7 +5177,7 @@
         "@types/express": "^4.17.12",
         "@types/express-serve-static-core": "^4.17.21",
         "accepts": "^1.3.5",
-        "apollo-server-core": "^2.25.3",
+        "apollo-server-core": "^2.25.4",
         "apollo-server-types": "^0.9.0",
         "body-parser": "^1.18.3",
         "cors": "^2.8.5",
@@ -5175,7 +5245,7 @@
     "archive-type": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz",
-      "integrity": "sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA=",
+      "integrity": "sha512-zV4Ky0v1F8dBrdYElwTvQhweQ0P7Kwc1aluqJsYtOBP01jXcWCyW2IEfI1YiqsG+Iy7ZR+o5LF1N+PGECBxHWA==",
       "dev": true,
       "requires": {
         "file-type": "^4.2.0"
@@ -5184,7 +5254,7 @@
         "file-type": {
           "version": "4.4.0",
           "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz",
-          "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=",
+          "integrity": "sha512-f2UbFQEk7LXgWpi5ntcO86OeA/cC80fuDDDaX/fZ2ZGel+AF7leRQqBBW1eJNiiQkrZlAoM6P+VYP5P6bOlDEQ==",
           "dev": true
         }
       }
@@ -5209,7 +5279,7 @@
     "arr-diff": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
-      "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+      "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==",
       "dev": true
     },
     "arr-flatten": {
@@ -5221,42 +5291,36 @@
     "arr-union": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
-      "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+      "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
       "dev": true
     },
     "array-equal": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
-      "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
+      "integrity": "sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA==",
       "dev": true
     },
     "array-find": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz",
-      "integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=",
-      "dev": true
-    },
-    "array-find-index": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
-      "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
+      "integrity": "sha512-kO/vVCacW9mnpn3WPWbTVlEnOabK2L7LWi2HViURtCM46y1zb6I8UMjx4LgbiqadTgHnLInUronwn3ampNTJtQ==",
       "dev": true
     },
     "array-flatten": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
-      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
+      "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
       "dev": true
     },
     "array-includes": {
-      "version": "3.1.4",
-      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz",
-      "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==",
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz",
+      "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==",
       "dev": true,
       "requires": {
         "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.1",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.19.5",
         "get-intrinsic": "^1.1.1",
         "is-string": "^1.0.7"
       }
@@ -5269,7 +5333,7 @@
     "array-union": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
-      "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+      "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
       "dev": true,
       "requires": {
         "array-uniq": "^1.0.1"
@@ -5278,24 +5342,38 @@
     "array-uniq": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
-      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+      "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==",
       "dev": true
     },
     "array-unique": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
-      "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+      "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==",
       "dev": true
     },
     "array.prototype.flat": {
-      "version": "1.2.5",
-      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz",
-      "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==",
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz",
+      "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==",
       "dev": true,
       "requires": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.0"
+        "es-abstract": "^1.19.2",
+        "es-shim-unscopables": "^1.0.0"
+      }
+    },
+    "array.prototype.reduce": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.4.tgz",
+      "integrity": "sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.19.2",
+        "es-array-method-boxes-properly": "^1.0.0",
+        "is-string": "^1.0.7"
       }
     },
     "arrify": {
@@ -5345,13 +5423,13 @@
         "inherits": {
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
-          "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
+          "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==",
           "dev": true
         },
         "util": {
           "version": "0.10.3",
           "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
-          "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+          "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==",
           "dev": true,
           "requires": {
             "inherits": "2.0.1"
@@ -5362,12 +5440,12 @@
     "assert-plus": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
-      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+      "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="
     },
     "assign-symbols": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
-      "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+      "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==",
       "dev": true
     },
     "ast-types": {
@@ -5383,9 +5461,9 @@
       "dev": true
     },
     "async": {
-      "version": "2.6.3",
-      "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
-      "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
+      "version": "2.6.4",
+      "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
+      "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
       "dev": true,
       "requires": {
         "lodash": "^4.17.14"
@@ -5397,12 +5475,6 @@
       "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
       "dev": true
     },
-    "async-foreach": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
-      "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=",
-      "dev": true
-    },
     "async-limiter": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
@@ -5427,14 +5499,14 @@
       }
     },
     "async-validator": {
-      "version": "3.5.2",
-      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-3.5.2.tgz",
-      "integrity": "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ=="
+      "version": "4.2.5",
+      "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
+      "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
     },
     "asynckit": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
     },
     "atob": {
       "version": "2.1.2",
@@ -5460,7 +5532,7 @@
     "aws-sign2": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
-      "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+      "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA=="
     },
     "aws4": {
       "version": "1.11.0",
@@ -5478,7 +5550,7 @@
     "babel-code-frame": {
       "version": "6.26.0",
       "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
-      "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+      "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==",
       "dev": true,
       "requires": {
         "chalk": "^1.1.3",
@@ -5489,13 +5561,13 @@
         "ansi-styles": {
           "version": "2.2.1",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
-          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+          "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
           "dev": true
         },
         "chalk": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
-          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
           "dev": true,
           "requires": {
             "ansi-styles": "^2.2.1",
@@ -5508,13 +5580,13 @@
         "js-tokens": {
           "version": "3.0.2",
           "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
-          "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+          "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==",
           "dev": true
         },
         "supports-color": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
-          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+          "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
           "dev": true
         }
       }
@@ -5540,12 +5612,12 @@
       },
       "dependencies": {
         "resolve": {
-          "version": "1.22.0",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
-          "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
+          "version": "1.22.1",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+          "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
           "dev": true,
           "requires": {
-            "is-core-module": "^2.8.1",
+            "is-core-module": "^2.9.0",
             "path-parse": "^1.0.7",
             "supports-preserve-symlinks-flag": "^1.0.0"
           }
@@ -5688,9 +5760,9 @@
           "dev": true
         },
         "istanbul-lib-instrument": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz",
-          "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==",
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz",
+          "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==",
           "dev": true,
           "requires": {
             "@babel/core": "^7.12.3",
@@ -5764,13 +5836,13 @@
           }
         },
         "micromatch": {
-          "version": "4.0.4",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
-          "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
+          "version": "4.0.5",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+          "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
           "dev": true,
           "requires": {
-            "braces": "^3.0.1",
-            "picomatch": "^2.2.3"
+            "braces": "^3.0.2",
+            "picomatch": "^2.3.1"
           }
         },
         "semver": {
@@ -5802,9 +5874,9 @@
       }
     },
     "babel-loader": {
-      "version": "8.2.4",
-      "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.4.tgz",
-      "integrity": "sha512-8dytA3gcvPPPv4Grjhnt8b5IIiTcq/zeXOPk4iTYI0SVXcsmuGg7JtBRDp8S9X+gJfhQ8ektjXZlDu1Bb33U8A==",
+      "version": "8.2.5",
+      "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz",
+      "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==",
       "dev": true,
       "requires": {
         "find-cache-dir": "^3.3.1",
@@ -5838,7 +5910,7 @@
     "babel-messages": {
       "version": "6.23.0",
       "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
-      "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
+      "integrity": "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==",
       "dev": true,
       "requires": {
         "babel-runtime": "^6.22.0"
@@ -5854,13 +5926,12 @@
       }
     },
     "babel-plugin-import": {
-      "version": "1.13.3",
-      "resolved": "https://registry.npmjs.org/babel-plugin-import/-/babel-plugin-import-1.13.3.tgz",
-      "integrity": "sha512-1qCWdljJOrDRH/ybaCZuDgySii4yYrtQ8OJQwrcDqdt0y67N30ng3X3nABg6j7gR7qUJgcMa9OMhc4AGViDwWw==",
+      "version": "1.13.5",
+      "resolved": "https://registry.npmjs.org/babel-plugin-import/-/babel-plugin-import-1.13.5.tgz",
+      "integrity": "sha512-IkqnoV+ov1hdJVofly9pXRJmeDm9EtROfrc5i6eII0Hix2xMs5FEm8FG3ExMvazbnZBbgHIt6qdO8And6lCloQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-module-imports": "^7.0.0",
-        "@babel/runtime": "^7.0.0"
+        "@babel/helper-module-imports": "^7.0.0"
       }
     },
     "babel-plugin-istanbul": {
@@ -5906,7 +5977,7 @@
         "path-exists": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
           "dev": true
         }
       }
@@ -5978,7 +6049,7 @@
     "babel-plugin-transform-strict-mode": {
       "version": "6.24.1",
       "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
-      "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=",
+      "integrity": "sha512-j3KtSpjyLSJxNoCDrhwiJad8kw0gJ9REGj8/CqL0HeRyLnvUNYV9zcqluL6QJSXh3nfsLEmSLvwRfGzrgR96Pw==",
       "dev": true,
       "requires": {
         "babel-runtime": "^6.22.0",
@@ -6018,7 +6089,7 @@
     "babel-runtime": {
       "version": "6.26.0",
       "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
-      "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+      "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
       "dev": true,
       "requires": {
         "core-js": "^2.4.0",
@@ -6042,7 +6113,7 @@
     "babel-template": {
       "version": "6.26.0",
       "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
-      "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
+      "integrity": "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==",
       "dev": true,
       "requires": {
         "babel-runtime": "^6.26.0",
@@ -6055,7 +6126,7 @@
     "babel-traverse": {
       "version": "6.26.0",
       "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
-      "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+      "integrity": "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==",
       "dev": true,
       "requires": {
         "babel-code-frame": "^6.26.0",
@@ -6087,7 +6158,7 @@
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         }
       }
@@ -6095,7 +6166,7 @@
     "babel-types": {
       "version": "6.26.0",
       "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
-      "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+      "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==",
       "dev": true,
       "requires": {
         "babel-runtime": "^6.26.0",
@@ -6107,7 +6178,7 @@
         "to-fast-properties": {
           "version": "1.0.3",
           "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
-          "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
+          "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==",
           "dev": true
         }
       }
@@ -6121,7 +6192,7 @@
     "backo2": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
-      "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
+      "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==",
       "dev": true
     },
     "balanced-match": {
@@ -6147,7 +6218,7 @@
         "define-property": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
           "dev": true,
           "requires": {
             "is-descriptor": "^1.0.0"
@@ -6193,13 +6264,13 @@
     "batch": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
-      "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=",
+      "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==",
       "dev": true
     },
     "bcrypt-pbkdf": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
-      "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+      "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
       "requires": {
         "tweetnacl": "^0.14.3"
       }
@@ -6246,15 +6317,6 @@
         "safe-buffer": "^5.1.1"
       }
     },
-    "block-stream": {
-      "version": "0.0.9",
-      "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
-      "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
-      "dev": true,
-      "requires": {
-        "inherits": "~2.0.0"
-      }
-    },
     "bluebird": {
       "version": "3.7.2",
       "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@@ -6262,27 +6324,29 @@
       "dev": true
     },
     "bn.js": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
-      "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==",
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
+      "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
       "dev": true
     },
     "body-parser": {
-      "version": "1.19.2",
-      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz",
-      "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==",
+      "version": "1.20.0",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz",
+      "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==",
       "dev": true,
       "requires": {
         "bytes": "3.1.2",
         "content-type": "~1.0.4",
         "debug": "2.6.9",
-        "depd": "~1.1.2",
-        "http-errors": "1.8.1",
+        "depd": "2.0.0",
+        "destroy": "1.2.0",
+        "http-errors": "2.0.0",
         "iconv-lite": "0.4.24",
-        "on-finished": "~2.3.0",
-        "qs": "6.9.7",
-        "raw-body": "2.4.3",
-        "type-is": "~1.6.18"
+        "on-finished": "2.4.1",
+        "qs": "6.10.3",
+        "raw-body": "2.5.1",
+        "type-is": "~1.6.18",
+        "unpipe": "1.0.0"
       },
       "dependencies": {
         "debug": {
@@ -6294,6 +6358,25 @@
             "ms": "2.0.0"
           }
         },
+        "depd": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+          "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+          "dev": true
+        },
+        "http-errors": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+          "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+          "dev": true,
+          "requires": {
+            "depd": "2.0.0",
+            "inherits": "2.0.4",
+            "setprototypeof": "1.2.0",
+            "statuses": "2.0.1",
+            "toidentifier": "1.0.1"
+          }
+        },
         "iconv-lite": {
           "version": "0.4.24",
           "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -6306,13 +6389,22 @@
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         },
         "qs": {
-          "version": "6.9.7",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz",
-          "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==",
+          "version": "6.10.3",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
+          "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
+          "dev": true,
+          "requires": {
+            "side-channel": "^1.0.4"
+          }
+        },
+        "statuses": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+          "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
           "dev": true
         }
       }
@@ -6320,7 +6412,7 @@
     "bonjour": {
       "version": "3.5.0",
       "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",
-      "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=",
+      "integrity": "sha512-RaVTblr+OnEli0r/ud8InrU7D+G0y6aJhlxaLa6Pwty4+xoxboF1BsUI45tujvRpbj9dQVoglChqonGAsjEBYg==",
       "dev": true,
       "requires": {
         "array-flatten": "^2.1.0",
@@ -6342,7 +6434,7 @@
     "boolbase": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
-      "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
       "dev": true
     },
     "boxen": {
@@ -6429,7 +6521,7 @@
         "extend-shallow": {
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
           "dev": true,
           "requires": {
             "is-extendable": "^0.1.0"
@@ -6440,7 +6532,7 @@
     "brorand": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
-      "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
+      "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==",
       "dev": true
     },
     "browser-process-hrtime": {
@@ -6461,7 +6553,7 @@
         "resolve": {
           "version": "1.1.7",
           "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
-          "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
+          "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==",
           "dev": true
         }
       }
@@ -6559,24 +6651,15 @@
       }
     },
     "browserslist": {
-      "version": "4.20.2",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz",
-      "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==",
+      "version": "4.21.1",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.1.tgz",
+      "integrity": "sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==",
       "dev": true,
       "requires": {
-        "caniuse-lite": "^1.0.30001317",
-        "electron-to-chromium": "^1.4.84",
-        "escalade": "^3.1.1",
-        "node-releases": "^2.0.2",
-        "picocolors": "^1.0.0"
-      },
-      "dependencies": {
-        "picocolors": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
-          "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
-          "dev": true
-        }
+        "caniuse-lite": "^1.0.30001359",
+        "electron-to-chromium": "^1.4.172",
+        "node-releases": "^2.0.5",
+        "update-browserslist-db": "^1.0.4"
       }
     },
     "bs-logger": {
@@ -6626,13 +6709,13 @@
     "buffer-crc32": {
       "version": "0.2.13",
       "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
-      "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+      "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
       "dev": true
     },
     "buffer-fill": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
-      "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=",
+      "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==",
       "dev": true
     },
     "buffer-from": {
@@ -6656,19 +6739,19 @@
     "buffer-xor": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
-      "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
+      "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==",
       "dev": true
     },
     "builtin-status-codes": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
-      "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
+      "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==",
       "dev": true
     },
     "builtins": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz",
-      "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og="
+      "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ=="
     },
     "busboy": {
       "version": "0.3.1",
@@ -6834,13 +6917,13 @@
     "call-me-maybe": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz",
-      "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=",
+      "integrity": "sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw==",
       "dev": true
     },
     "caller-callsite": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
-      "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
+      "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==",
       "dev": true,
       "requires": {
         "callsites": "^2.0.0"
@@ -6849,7 +6932,7 @@
         "callsites": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
-          "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
+          "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==",
           "dev": true
         }
       }
@@ -6857,7 +6940,7 @@
     "caller-path": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
-      "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
+      "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==",
       "dev": true,
       "requires": {
         "caller-callsite": "^2.0.0"
@@ -6872,7 +6955,7 @@
     "camel-case": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
-      "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=",
+      "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==",
       "dev": true,
       "requires": {
         "no-case": "^2.2.0",
@@ -6884,24 +6967,6 @@
       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
       "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
     },
-    "camelcase-keys": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
-      "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
-      "dev": true,
-      "requires": {
-        "camelcase": "^2.0.0",
-        "map-obj": "^1.0.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
-          "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
-          "dev": true
-        }
-      }
-    },
     "caniuse-api": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
@@ -6915,9 +6980,9 @@
       }
     },
     "caniuse-lite": {
-      "version": "1.0.30001320",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz",
-      "integrity": "sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA==",
+      "version": "1.0.30001361",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001361.tgz",
+      "integrity": "sha512-ybhCrjNtkFji1/Wto6SSJKkWk6kZgVQsDq5QI83SafsF6FXv2JB4df9eEdH6g8sdGgqTXrFLjAxqBGgYoU3azQ==",
       "dev": true
     },
     "capture-exit": {
@@ -6938,7 +7003,7 @@
     "caseless": {
       "version": "0.12.0",
       "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
-      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+      "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
     },
     "caw": {
       "version": "2.0.1",
@@ -6961,12 +7026,6 @@
         "supports-color": "^7.1.0"
       }
     },
-    "charcodes": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/charcodes/-/charcodes-0.2.0.tgz",
-      "integrity": "sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==",
-      "dev": true
-    },
     "chardet": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
@@ -6976,7 +7035,7 @@
     "charenc": {
       "version": "0.0.2",
       "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
-      "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
+      "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA=="
     },
     "chart.js": {
       "version": "3.9.1",
@@ -7073,7 +7132,7 @@
     "cint": {
       "version": "8.2.1",
       "resolved": "https://registry.npmjs.org/cint/-/cint-8.2.1.tgz",
-      "integrity": "sha1-cDhrG0jidz0NYxZqVa/5TvRFahI="
+      "integrity": "sha512-gyWqJHXgDFPNx7PEyFJotutav+al92TTC3dWlMFyTETlOyKBQMZb7Cetqmj3GlrnSILHwSJRwf4mIGzc7C5lXw=="
     },
     "cipher-base": {
       "version": "1.0.4",
@@ -7100,7 +7159,7 @@
         "define-property": {
           "version": "0.2.5",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
           "dev": true,
           "requires": {
             "is-descriptor": "^0.1.0"
@@ -7108,6 +7167,11 @@
         }
       }
     },
+    "classnames": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
+      "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
+    },
     "clean-css": {
       "version": "4.2.4",
       "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz",
@@ -7130,7 +7194,7 @@
     "cli-cursor": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
-      "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+      "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==",
       "dev": true,
       "requires": {
         "restore-cursor": "^2.0.0"
@@ -7179,9 +7243,9 @@
       "dev": true
     },
     "clipboard": {
-      "version": "2.0.10",
-      "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.10.tgz",
-      "integrity": "sha512-cz3m2YVwFz95qSEbCDi2fzLN/epEN9zXBvfgAoGkvGOJZATMl9gtTDVOtBYkx2ODUJl2kvmud7n32sV2BpYR4g==",
+      "version": "2.0.11",
+      "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
+      "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
       "requires": {
         "good-listener": "^1.2.2",
         "select": "^1.1.2",
@@ -7258,7 +7322,7 @@
     "clone": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
-      "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
+      "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
       "dev": true
     },
     "clone-deep": {
@@ -7286,7 +7350,7 @@
     "clone-response": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
-      "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
+      "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==",
       "requires": {
         "mimic-response": "^1.0.0"
       }
@@ -7315,7 +7379,7 @@
     "co": {
       "version": "4.6.0",
       "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
-      "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
+      "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
       "dev": true
     },
     "coa": {
@@ -7361,13 +7425,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "supports-color": {
@@ -7384,12 +7448,12 @@
     "code-point-at": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
-      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+      "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA=="
     },
     "collection-visit": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
-      "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+      "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==",
       "dev": true,
       "requires": {
         "map-visit": "^1.0.0",
@@ -7418,7 +7482,7 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         }
       }
@@ -7437,9 +7501,9 @@
       "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
     },
     "color-string": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz",
-      "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==",
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+      "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
       "dev": true,
       "requires": {
         "color-name": "^1.0.0",
@@ -7449,7 +7513,7 @@
     "colors": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
-      "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs="
+      "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw=="
     },
     "combined-stream": {
       "version": "1.0.8",
@@ -7467,7 +7531,7 @@
     "commondir": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
-      "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+      "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
       "dev": true
     },
     "component-emitter": {
@@ -7503,7 +7567,7 @@
         "bytes": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
-          "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
+          "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==",
           "dev": true
         },
         "debug": {
@@ -7518,7 +7582,7 @@
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         }
       }
@@ -7531,7 +7595,7 @@
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
     },
     "concat-stream": {
       "version": "1.6.2",
@@ -7548,7 +7612,7 @@
     "condense-newlines": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/condense-newlines/-/condense-newlines-0.2.1.tgz",
-      "integrity": "sha1-PemFVTE5R10yUCyDsC9gaE0kxV8=",
+      "integrity": "sha512-P7X+QL9Hb9B/c8HI5BFFKmjgBu2XpQuF98WZ9XkO+dBGgk5XgwiQz7o1SmpglNWId3581UcS0SFAWfoIhMHPfg==",
       "dev": true,
       "requires": {
         "extend-shallow": "^2.0.1",
@@ -7559,7 +7623,7 @@
         "extend-shallow": {
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
           "dev": true,
           "requires": {
             "is-extendable": "^0.1.0"
@@ -7568,7 +7632,7 @@
         "kind-of": {
           "version": "3.2.2",
           "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
           "dev": true,
           "requires": {
             "is-buffer": "^1.1.5"
@@ -7614,7 +7678,7 @@
     "console-control-strings": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
-      "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+      "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="
     },
     "consolidate": {
       "version": "0.15.1",
@@ -7628,7 +7692,7 @@
     "constants-browserify": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
-      "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
+      "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==",
       "dev": true
     },
     "content-disposition": {
@@ -7664,15 +7728,15 @@
       }
     },
     "cookie": {
-      "version": "0.4.2",
-      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
-      "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+      "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
       "dev": true
     },
     "cookie-signature": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
-      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
+      "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
       "dev": true
     },
     "copy-anything": {
@@ -7699,12 +7763,12 @@
       },
       "dependencies": {
         "mkdirp": {
-          "version": "0.5.5",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
-          "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+          "version": "0.5.6",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+          "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
           "dev": true,
           "requires": {
-            "minimist": "^1.2.5"
+            "minimist": "^1.2.6"
           }
         },
         "rimraf": {
@@ -7721,9 +7785,17 @@
     "copy-descriptor": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
-      "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+      "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==",
       "dev": true
     },
+    "copy-to-clipboard": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz",
+      "integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==",
+      "requires": {
+        "toggle-selection": "^1.0.6"
+      }
+    },
     "copy-webpack-plugin": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz",
@@ -7776,7 +7848,7 @@
         "globby": {
           "version": "7.1.1",
           "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz",
-          "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=",
+          "integrity": "sha512-yANWAN2DUcBtuus5Cpd+SKROzXHs2iVXFZt/Ykrfz6SAXqacLX25NZpltE+39ceMexYF4TtEadjuSTw8+3wX4g==",
           "dev": true,
           "requires": {
             "array-union": "^1.0.1",
@@ -7854,7 +7926,7 @@
         "slash": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
-          "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
+          "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==",
           "dev": true
         },
         "ssri": {
@@ -7881,17 +7953,17 @@
       }
     },
     "core-js": {
-      "version": "3.21.1",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz",
-      "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig=="
+      "version": "3.23.3",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.23.3.tgz",
+      "integrity": "sha512-oAKwkj9xcWNBAvGbT//WiCdOMpb9XQG92/Fe3ABFM/R16BsHgePG00mFOgKf7IsCtfj8tA1kHtf/VwErhriz5Q=="
     },
     "core-js-compat": {
-      "version": "3.21.1",
-      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz",
-      "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==",
+      "version": "3.23.3",
+      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.23.3.tgz",
+      "integrity": "sha512-WSzUs2h2vvmKsacLHNTdpyOC9k43AEhcGoFlVgCY4L7aw98oSBKtPL6vD0/TqZjRWRQYdDSLkzZIni4Crbbiqw==",
       "dev": true,
       "requires": {
-        "browserslist": "^4.19.1",
+        "browserslist": "^4.21.0",
         "semver": "7.0.0"
       },
       "dependencies": {
@@ -7904,9 +7976,9 @@
       }
     },
     "core-js-pure": {
-      "version": "3.21.1",
-      "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz",
-      "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==",
+      "version": "3.23.3",
+      "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.23.3.tgz",
+      "integrity": "sha512-XpoouuqIj4P+GWtdyV8ZO3/u4KftkeDVMfvp+308eGMhCrA3lVDSmAxO0c6GGOcmgVlaKDrgWVMo49h2ab/TDA==",
       "dev": true
     },
     "core-util-is": {
@@ -7939,7 +8011,7 @@
         "parse-json": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
-          "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+          "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
           "dev": true,
           "requires": {
             "error-ex": "^1.3.1",
@@ -7993,6 +8065,11 @@
         "sha.js": "^2.4.8"
       }
     },
+    "cronstrue": {
+      "version": "2.26.0",
+      "resolved": "https://registry.npmjs.org/cronstrue/-/cronstrue-2.26.0.tgz",
+      "integrity": "sha512-M1VdV3hpBAsd1Zzvqcvf63wgDpcwCuS4WiNEVFpJ0s33MGO2sVDTfswYq0EPypCmESrCzmgL8h68DTzJuSDbVA=="
+    },
     "cross-spawn": {
       "version": "6.0.5",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
@@ -8026,7 +8103,7 @@
     "crypt": {
       "version": "0.0.2",
       "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
-      "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
+      "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow=="
     },
     "crypto-browserify": {
       "version": "3.12.0",
@@ -8067,7 +8144,7 @@
     "css-color-names": {
       "version": "0.0.4",
       "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
-      "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=",
+      "integrity": "sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==",
       "dev": true
     },
     "css-declaration-sorter": {
@@ -8172,7 +8249,7 @@
     "cssfilter": {
       "version": "0.0.10",
       "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
-      "integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=",
+      "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==",
       "dev": true
     },
     "cssnano": {
@@ -8228,13 +8305,13 @@
     "cssnano-util-get-arguments": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz",
-      "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=",
+      "integrity": "sha512-6RIcwmV3/cBMG8Aj5gucQRsJb4vv4I4rn6YjPbVWd5+Pn/fuG+YseGvXGk00XLkoZkaj31QOD7vMUpNPC4FIuw==",
       "dev": true
     },
     "cssnano-util-get-match": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz",
-      "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=",
+      "integrity": "sha512-JPMZ1TSMRUPVIqEalIBNoBtAYbi8okvcFns4O0YIhcdGebeYZK7dMyHJiQ6GqNBA9kE0Hym4Aqym5rPdsV/4Cw==",
       "dev": true
     },
     "cssnano-util-raw-cache": {
@@ -8314,25 +8391,16 @@
         "ndjson": "^1.4.0"
       }
     },
-    "currently-unhandled": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
-      "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
-      "dev": true,
-      "requires": {
-        "array-find-index": "^1.0.1"
-      }
-    },
     "cyclist": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
-      "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
+      "integrity": "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==",
       "dev": true
     },
     "dashdash": {
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
-      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+      "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
       "requires": {
         "assert-plus": "^1.0.0"
       }
@@ -8351,7 +8419,7 @@
         "tr46": {
           "version": "1.0.1",
           "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
-          "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
+          "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
           "dev": true,
           "requires": {
             "punycode": "^2.1.0"
@@ -8376,10 +8444,20 @@
         }
       }
     },
+    "date-fns": {
+      "version": "2.28.0",
+      "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz",
+      "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw=="
+    },
+    "dayjs": {
+      "version": "1.11.3",
+      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.3.tgz",
+      "integrity": "sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A=="
+    },
     "deasync": {
-      "version": "0.1.24",
-      "resolved": "https://registry.npmjs.org/deasync/-/deasync-0.1.24.tgz",
-      "integrity": "sha512-i98vg42xNfRZCymummMAN0rIcQ1gZFinSe3btvPIvy6JFTaeHcumeKybRo2HTv86nasfmT0nEgAn2ggLZhOCVA==",
+      "version": "0.1.26",
+      "resolved": "https://registry.npmjs.org/deasync/-/deasync-0.1.26.tgz",
+      "integrity": "sha512-YKw0BmJSWxkjtQsbgn6Q9CHSWB7DKMen8vKrgyC006zy0UZ6nWyGidB0IzZgqkVRkOglAeUaFtiRTeLyel72bg==",
       "dev": true,
       "requires": {
         "bindings": "^1.5.0",
@@ -8397,13 +8475,13 @@
     "decamelize": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
-      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+      "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
       "dev": true
     },
     "decode-uri-component": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
-      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+      "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==",
       "dev": true
     },
     "decompress": {
@@ -8434,7 +8512,7 @@
             "pify": {
               "version": "3.0.0",
               "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
-              "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+              "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
               "dev": true
             }
           }
@@ -8442,7 +8520,7 @@
         "pify": {
           "version": "2.3.0",
           "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+          "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
           "dev": true
         }
       }
@@ -8450,7 +8528,7 @@
     "decompress-response": {
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
-      "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
+      "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==",
       "requires": {
         "mimic-response": "^1.0.0"
       }
@@ -8469,7 +8547,7 @@
         "file-type": {
           "version": "5.2.0",
           "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz",
-          "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=",
+          "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==",
           "dev": true
         }
       }
@@ -8509,7 +8587,7 @@
         "file-type": {
           "version": "5.2.0",
           "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz",
-          "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=",
+          "integrity": "sha512-Iq1nJ6D2+yIO4c8HHg4fyVb8mAJieo1Oloy1mLLaB2PvezNedhBVm+QU7g0qM42aiMbRXTxKKwGD17rjKNJYVQ==",
           "dev": true
         }
       }
@@ -8517,7 +8595,7 @@
     "decompress-unzip": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz",
-      "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=",
+      "integrity": "sha512-1fqeluvxgnn86MOh66u8FjbtJpAFv5wgCT9Iw8rcBqQcCo5tO8eiJw7NNTrvt9n4CRBVq7CstiS922oPgyGLrw==",
       "dev": true,
       "requires": {
         "file-type": "^3.8.0",
@@ -8529,13 +8607,13 @@
         "file-type": {
           "version": "3.9.0",
           "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
-          "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=",
+          "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==",
           "dev": true
         },
         "get-stream": {
           "version": "2.3.1",
           "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz",
-          "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=",
+          "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==",
           "dev": true,
           "requires": {
             "object-assign": "^4.0.1",
@@ -8545,7 +8623,7 @@
         "pify": {
           "version": "2.3.0",
           "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+          "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
           "dev": true
         }
       }
@@ -8690,7 +8768,7 @@
     "defaults": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
-      "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
+      "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==",
       "dev": true,
       "requires": {
         "clone": "^1.0.2"
@@ -8702,12 +8780,13 @@
       "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ=="
     },
     "define-properties": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
-      "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
+      "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
       "dev": true,
       "requires": {
-        "object-keys": "^1.0.12"
+        "has-property-descriptors": "^1.0.0",
+        "object-keys": "^1.1.1"
       }
     },
     "define-property": {
@@ -8769,7 +8848,7 @@
         "globby": {
           "version": "6.1.0",
           "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
-          "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
+          "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==",
           "dev": true,
           "requires": {
             "array-union": "^1.0.1",
@@ -8782,7 +8861,7 @@
             "pify": {
               "version": "2.3.0",
               "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-              "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+              "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
               "dev": true
             }
           }
@@ -8813,7 +8892,7 @@
     "delayed-stream": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
-      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
     },
     "delegate": {
       "version": "3.2.0",
@@ -8823,17 +8902,17 @@
     "delegates": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
-      "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+      "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="
     },
     "depd": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
-      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+      "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="
     },
     "deprecated-decorator": {
       "version": "0.1.6",
       "resolved": "https://registry.npmjs.org/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz",
-      "integrity": "sha1-AJZjF7ehL+kvPMgx91g68ym4bDc=",
+      "integrity": "sha512-MHidOOnCHGlZDKsI21+mbIIhf4Fff+hhCTB7gtVg4uoIqjcrTZc5v6M+GS2zVI0sV7PqK415rb8XaOSQsQkHOw==",
       "dev": true
     },
     "des.js": {
@@ -8847,15 +8926,15 @@
       }
     },
     "destroy": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
-      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+      "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
       "dev": true
     },
     "detect-newline": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
-      "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=",
+      "integrity": "sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg==",
       "dev": true
     },
     "detect-node": {
@@ -8910,7 +8989,7 @@
     "dns-equal": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
-      "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=",
+      "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==",
       "dev": true
     },
     "dns-packet": {
@@ -8926,7 +9005,7 @@
     "dns-txt": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz",
-      "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=",
+      "integrity": "sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==",
       "dev": true,
       "requires": {
         "buffer-indexof": "^1.0.0"
@@ -8942,9 +9021,9 @@
       }
     },
     "dom-align": {
-      "version": "1.12.2",
-      "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.2.tgz",
-      "integrity": "sha512-pHuazgqrsTFrGU2WLDdXxCFabkdQDx72ddkraZNih1KsMcN5qsRSTR9O4VJRlwTPCPb5COYg3LOfiMHHcPInHg=="
+      "version": "1.12.3",
+      "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.3.tgz",
+      "integrity": "sha512-Gj9hZN3a07cbR6zviMUBOMPdWxYhbMI+x+WS0NAIu2zFZmbK8ys9R79g+iG9qLnlCwpFoaB+fKy8Pdv470GsPA=="
     },
     "dom-converter": {
       "version": "0.2.0",
@@ -8971,9 +9050,9 @@
       },
       "dependencies": {
         "domelementtype": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
-          "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+          "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
           "dev": true
         }
       }
@@ -9017,9 +9096,9 @@
       },
       "dependencies": {
         "domelementtype": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
-          "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+          "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
           "dev": true
         }
       }
@@ -9083,7 +9162,7 @@
         "cacheable-request": {
           "version": "2.1.4",
           "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz",
-          "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=",
+          "integrity": "sha512-vag0O2LKZ/najSoUwDbVlnlCFvhBE/7mGTY2B5FgCBDcRD+oVV1HYTOwM6JZfMg/hIcM6IwnTZ1uQQL5/X3xIQ==",
           "dev": true,
           "requires": {
             "clone-response": "1.0.2",
@@ -9098,7 +9177,7 @@
             "lowercase-keys": {
               "version": "1.0.0",
               "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz",
-              "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=",
+              "integrity": "sha512-RPlX0+PHuvxVDZ7xX+EBVAp4RsVxP/TdDSN2mJYdiq1Lc4Hz7EUSjUI7RZrKKlmrIzVhf6Jo2stj7++gVarS0A==",
               "dev": true
             }
           }
@@ -9106,7 +9185,7 @@
         "get-stream": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
-          "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
+          "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==",
           "dev": true
         },
         "got": {
@@ -9143,7 +9222,7 @@
         "into-stream": {
           "version": "3.1.0",
           "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz",
-          "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=",
+          "integrity": "sha512-TcdjPibTksa1NQximqep2r17ISRiNE9fwlfbg3F8ANdvP5/yrFTew86VcO//jk4QTaMlbjypPBq76HN2zaKfZQ==",
           "dev": true,
           "requires": {
             "from2": "^2.1.1",
@@ -9188,7 +9267,7 @@
         "sort-keys": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz",
-          "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=",
+          "integrity": "sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==",
           "dev": true,
           "requires": {
             "is-plain-obj": "^1.0.0"
@@ -9216,7 +9295,7 @@
     "duplexer3": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
-      "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI="
+      "integrity": "sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA=="
     },
     "duplexify": {
       "version": "3.7.1",
@@ -9239,7 +9318,7 @@
     "ecc-jsbn": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
-      "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+      "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
       "requires": {
         "jsbn": "~0.1.0",
         "safer-buffer": "^2.1.0"
@@ -9282,7 +9361,7 @@
         "yallist": {
           "version": "2.1.2",
           "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
-          "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+          "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
           "dev": true
         }
       }
@@ -9290,7 +9369,7 @@
     "ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
-      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+      "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
       "dev": true
     },
     "ejs": {
@@ -9300,9 +9379,9 @@
       "dev": true
     },
     "electron-to-chromium": {
-      "version": "1.4.92",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.92.tgz",
-      "integrity": "sha512-YAVbvQIcDE/IJ/vzDMjD484/hsRbFPW2qXJPaYTfOhtligmfYEYOep+5QojpaEU9kq6bMvNeC2aG7arYvTHYsA==",
+      "version": "1.4.176",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.176.tgz",
+      "integrity": "sha512-92JdgyRlcNDwuy75MjuFSb3clt6DGJ2IXSpg0MCjKd3JV9eSmuUAIyWiGAp/EtT0z2D4rqbYqThQLV90maH3Zw==",
       "dev": true
     },
     "elliptic": {
@@ -9341,7 +9420,7 @@
     "encodeurl": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
-      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+      "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
       "dev": true
     },
     "encoding": {
@@ -9387,7 +9466,7 @@
     "enquire.js": {
       "version": "2.1.6",
       "resolved": "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz",
-      "integrity": "sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ="
+      "integrity": "sha512-/KujNpO+PT63F7Hlpu4h3pE3TokKRHN26JYmQpPyjkRD/N57R7bPDNojMXdi7uveAKjYB7yQnartCxZnFWr0Xw=="
     },
     "entities": {
       "version": "2.2.0",
@@ -9430,40 +9509,58 @@
       }
     },
     "error-stack-parser": {
-      "version": "2.0.7",
-      "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.7.tgz",
-      "integrity": "sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA==",
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
+      "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
       "dev": true,
       "requires": {
-        "stackframe": "^1.1.1"
+        "stackframe": "^1.3.4"
       }
     },
     "es-abstract": {
-      "version": "1.19.1",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz",
-      "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==",
+      "version": "1.20.1",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz",
+      "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==",
       "dev": true,
       "requires": {
         "call-bind": "^1.0.2",
         "es-to-primitive": "^1.2.1",
         "function-bind": "^1.1.1",
+        "function.prototype.name": "^1.1.5",
         "get-intrinsic": "^1.1.1",
         "get-symbol-description": "^1.0.0",
         "has": "^1.0.3",
-        "has-symbols": "^1.0.2",
+        "has-property-descriptors": "^1.0.0",
+        "has-symbols": "^1.0.3",
         "internal-slot": "^1.0.3",
         "is-callable": "^1.2.4",
-        "is-negative-zero": "^2.0.1",
+        "is-negative-zero": "^2.0.2",
         "is-regex": "^1.1.4",
-        "is-shared-array-buffer": "^1.0.1",
+        "is-shared-array-buffer": "^1.0.2",
         "is-string": "^1.0.7",
-        "is-weakref": "^1.0.1",
-        "object-inspect": "^1.11.0",
+        "is-weakref": "^1.0.2",
+        "object-inspect": "^1.12.0",
         "object-keys": "^1.1.1",
         "object.assign": "^4.1.2",
-        "string.prototype.trimend": "^1.0.4",
-        "string.prototype.trimstart": "^1.0.4",
-        "unbox-primitive": "^1.0.1"
+        "regexp.prototype.flags": "^1.4.3",
+        "string.prototype.trimend": "^1.0.5",
+        "string.prototype.trimstart": "^1.0.5",
+        "unbox-primitive": "^1.0.2"
+      }
+    },
+    "es-array-method-boxes-properly": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
+      "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
+      "dev": true
+    },
+    "es-shim-unscopables": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
+      "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
+      "dev": true,
+      "requires": {
+        "has": "^1.0.3"
       }
     },
     "es-to-primitive": {
@@ -9491,13 +9588,13 @@
     "escape-html": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
-      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
       "dev": true
     },
     "escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
     },
     "escodegen": {
       "version": "1.14.3",
@@ -9595,7 +9692,7 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "eslint-scope": {
@@ -9629,7 +9726,7 @@
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "import-fresh": {
@@ -9715,12 +9812,12 @@
           }
         },
         "resolve": {
-          "version": "1.22.0",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
-          "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
+          "version": "1.22.1",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+          "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
           "dev": true,
           "requires": {
-            "is-core-module": "^2.8.1",
+            "is-core-module": "^2.9.0",
             "path-parse": "^1.0.7",
             "supports-preserve-symlinks-flag": "^1.0.0"
           }
@@ -9757,7 +9854,7 @@
         "enhanced-resolve": {
           "version": "0.9.1",
           "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz",
-          "integrity": "sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=",
+          "integrity": "sha512-kxpoMgrdtkXZ5h0SeraBS1iRntpTpQ3R8ussdb38+UAFnMGX5DDyJXePm+OCHOcoXvHDw7mc2erbJBpDnl7TPw==",
           "dev": true,
           "requires": {
             "graceful-fs": "^4.1.2",
@@ -9768,22 +9865,22 @@
         "memory-fs": {
           "version": "0.2.0",
           "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz",
-          "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=",
+          "integrity": "sha512-+y4mDxU4rvXXu5UDSGCGNiesFmwCHuefGMoPCO1WYucNYj7DsLqrFaa2fXVI0H+NNiPTwwzKwspn9yTZqUGqng==",
           "dev": true
         },
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         },
         "resolve": {
-          "version": "1.22.0",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
-          "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
+          "version": "1.22.1",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+          "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
           "dev": true,
           "requires": {
-            "is-core-module": "^2.8.1",
+            "is-core-module": "^2.9.0",
             "path-parse": "^1.0.7",
             "supports-preserve-symlinks-flag": "^1.0.0"
           }
@@ -9797,7 +9894,7 @@
         "tapable": {
           "version": "0.1.10",
           "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz",
-          "integrity": "sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=",
+          "integrity": "sha512-jX8Et4hHg57mug1/079yitEKWGB3LCwoxByLsNim89LABq8NqgiX+6iYVOsq0vX8uJHkU+DZ5fnq95f800bEsQ==",
           "dev": true
         }
       }
@@ -9868,7 +9965,7 @@
         "find-up": {
           "version": "2.1.0",
           "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
-          "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
+          "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==",
           "dev": true,
           "requires": {
             "locate-path": "^2.0.0"
@@ -9877,7 +9974,7 @@
         "locate-path": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
-          "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+          "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==",
           "dev": true,
           "requires": {
             "p-locate": "^2.0.0",
@@ -9896,7 +9993,7 @@
         "p-locate": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
-          "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+          "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
           "dev": true,
           "requires": {
             "p-limit": "^1.1.0"
@@ -9905,13 +10002,13 @@
         "p-try": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
-          "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+          "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
           "dev": true
         },
         "path-exists": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
           "dev": true
         }
       }
@@ -9944,9 +10041,9 @@
       }
     },
     "eslint-plugin-import": {
-      "version": "2.25.4",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz",
-      "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==",
+      "version": "2.26.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz",
+      "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==",
       "dev": true,
       "requires": {
         "array-includes": "^3.1.4",
@@ -9954,14 +10051,14 @@
         "debug": "^2.6.9",
         "doctrine": "^2.1.0",
         "eslint-import-resolver-node": "^0.3.6",
-        "eslint-module-utils": "^2.7.2",
+        "eslint-module-utils": "^2.7.3",
         "has": "^1.0.3",
-        "is-core-module": "^2.8.0",
+        "is-core-module": "^2.8.1",
         "is-glob": "^4.0.3",
-        "minimatch": "^3.0.4",
+        "minimatch": "^3.1.2",
         "object.values": "^1.1.5",
-        "resolve": "^1.20.0",
-        "tsconfig-paths": "^3.12.0"
+        "resolve": "^1.22.0",
+        "tsconfig-paths": "^3.14.1"
       },
       "dependencies": {
         "debug": {
@@ -9985,16 +10082,16 @@
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         },
         "resolve": {
-          "version": "1.22.0",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
-          "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
+          "version": "1.22.1",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+          "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
           "dev": true,
           "requires": {
-            "is-core-module": "^2.8.1",
+            "is-core-module": "^2.9.0",
             "path-parse": "^1.0.7",
             "supports-preserve-symlinks-flag": "^1.0.0"
           }
@@ -10031,12 +10128,12 @@
           "dev": true
         },
         "resolve": {
-          "version": "1.22.0",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
-          "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
+          "version": "1.22.1",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+          "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
           "dev": true,
           "requires": {
-            "is-core-module": "^2.8.1",
+            "is-core-module": "^2.9.0",
             "path-parse": "^1.0.7",
             "supports-preserve-symlinks-flag": "^1.0.0"
           }
@@ -10193,7 +10290,7 @@
     "etag": {
       "version": "1.8.1",
       "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
-      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+      "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
       "dev": true
     },
     "event-pubsub": {
@@ -10215,13 +10312,10 @@
       "dev": true
     },
     "eventsource": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz",
-      "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==",
-      "dev": true,
-      "requires": {
-        "original": "^1.0.0"
-      }
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz",
+      "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==",
+      "dev": true
     },
     "evp_bytestokey": {
       "version": "1.0.3",
@@ -10260,13 +10354,13 @@
     "exit": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
-      "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
+      "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
       "dev": true
     },
     "expand-brackets": {
       "version": "2.1.4",
       "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
-      "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+      "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==",
       "dev": true,
       "requires": {
         "debug": "^2.3.3",
@@ -10290,7 +10384,7 @@
         "define-property": {
           "version": "0.2.5",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
           "dev": true,
           "requires": {
             "is-descriptor": "^0.1.0"
@@ -10299,7 +10393,7 @@
         "extend-shallow": {
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
           "dev": true,
           "requires": {
             "is-extendable": "^0.1.0"
@@ -10308,7 +10402,7 @@
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         }
       }
@@ -10316,7 +10410,7 @@
     "expand-tilde": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
-      "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+      "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==",
       "dev": true,
       "requires": {
         "homedir-polyfill": "^1.0.1"
@@ -10357,44 +10451,45 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         }
       }
     },
     "express": {
-      "version": "4.17.3",
-      "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz",
-      "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==",
+      "version": "4.18.1",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz",
+      "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==",
       "dev": true,
       "requires": {
         "accepts": "~1.3.8",
         "array-flatten": "1.1.1",
-        "body-parser": "1.19.2",
+        "body-parser": "1.20.0",
         "content-disposition": "0.5.4",
         "content-type": "~1.0.4",
-        "cookie": "0.4.2",
+        "cookie": "0.5.0",
         "cookie-signature": "1.0.6",
         "debug": "2.6.9",
-        "depd": "~1.1.2",
+        "depd": "2.0.0",
         "encodeurl": "~1.0.2",
         "escape-html": "~1.0.3",
         "etag": "~1.8.1",
-        "finalhandler": "~1.1.2",
+        "finalhandler": "1.2.0",
         "fresh": "0.5.2",
+        "http-errors": "2.0.0",
         "merge-descriptors": "1.0.1",
         "methods": "~1.1.2",
-        "on-finished": "~2.3.0",
+        "on-finished": "2.4.1",
         "parseurl": "~1.3.3",
         "path-to-regexp": "0.1.7",
         "proxy-addr": "~2.0.7",
-        "qs": "6.9.7",
+        "qs": "6.10.3",
         "range-parser": "~1.2.1",
         "safe-buffer": "5.2.1",
-        "send": "0.17.2",
-        "serve-static": "1.14.2",
+        "send": "0.18.0",
+        "serve-static": "1.15.0",
         "setprototypeof": "1.2.0",
-        "statuses": "~1.5.0",
+        "statuses": "2.0.1",
         "type-is": "~1.6.18",
         "utils-merge": "1.0.1",
         "vary": "~1.1.2"
@@ -10409,30 +10504,58 @@
             "ms": "2.0.0"
           }
         },
+        "depd": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+          "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+          "dev": true
+        },
+        "http-errors": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+          "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+          "dev": true,
+          "requires": {
+            "depd": "2.0.0",
+            "inherits": "2.0.4",
+            "setprototypeof": "1.2.0",
+            "statuses": "2.0.1",
+            "toidentifier": "1.0.1"
+          }
+        },
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         },
         "qs": {
-          "version": "6.9.7",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz",
-          "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==",
-          "dev": true
+          "version": "6.10.3",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
+          "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
+          "dev": true,
+          "requires": {
+            "side-channel": "^1.0.4"
+          }
         },
         "safe-buffer": {
           "version": "5.2.1",
           "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
           "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
           "dev": true
+        },
+        "statuses": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+          "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+          "dev": true
         }
       }
     },
     "express-history-api-fallback": {
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/express-history-api-fallback/-/express-history-api-fallback-2.2.1.tgz",
-      "integrity": "sha1-OirSf3vryQ/FM9EQ18bYMJe80Fc=",
+      "integrity": "sha512-swxwm3aP8vrOOvlzOdZvHlSZtJGwHKaY94J6AkrAgCTmcbko3IRwbkhLv2wKV1WeZhjxX58aLMpP3atDBnKuZg==",
       "dev": true
     },
     "ext-list": {
@@ -10462,7 +10585,7 @@
     "extend-shallow": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
-      "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+      "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
       "dev": true,
       "requires": {
         "assign-symbols": "^1.0.0",
@@ -10530,7 +10653,7 @@
         "define-property": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
           "dev": true,
           "requires": {
             "is-descriptor": "^1.0.0"
@@ -10539,7 +10662,7 @@
         "extend-shallow": {
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
           "dev": true,
           "requires": {
             "is-extendable": "^0.1.0"
@@ -10579,7 +10702,7 @@
     "extract-from-css": {
       "version": "0.4.4",
       "resolved": "https://registry.npmjs.org/extract-from-css/-/extract-from-css-0.4.4.tgz",
-      "integrity": "sha1-HqffLnx8brmSL6COitrqSG9vj5I=",
+      "integrity": "sha512-41qWGBdtKp9U7sgBxAQ7vonYqSXzgW/SiAYzq4tdWSVhAShvpVCH1nyvPQgjse6EdgbW7Y7ERdT3674/lKr65A==",
       "dev": true,
       "requires": {
         "css": "^2.1.0"
@@ -10588,7 +10711,7 @@
     "extsprintf": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
-      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+      "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g=="
     },
     "fast-deep-equal": {
       "version": "3.1.3",
@@ -10617,7 +10740,7 @@
     "fast-levenshtein": {
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
       "dev": true
     },
     "fastq": {
@@ -10650,7 +10773,7 @@
     "fd-slicer": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
-      "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+      "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
       "dev": true,
       "requires": {
         "pend": "~1.2.0"
@@ -10726,7 +10849,7 @@
     "filename-reserved-regex": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
-      "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=",
+      "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==",
       "dev": true
     },
     "filenamify": {
@@ -10749,7 +10872,7 @@
     "fill-range": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
-      "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+      "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==",
       "dev": true,
       "requires": {
         "extend-shallow": "^2.0.1",
@@ -10761,7 +10884,7 @@
         "extend-shallow": {
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
           "dev": true,
           "requires": {
             "is-extendable": "^0.1.0"
@@ -10770,17 +10893,17 @@
       }
     },
     "finalhandler": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
-      "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+      "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
       "dev": true,
       "requires": {
         "debug": "2.6.9",
         "encodeurl": "~1.0.2",
         "escape-html": "~1.0.3",
-        "on-finished": "~2.3.0",
+        "on-finished": "2.4.1",
         "parseurl": "~1.3.3",
-        "statuses": "~1.5.0",
+        "statuses": "2.0.1",
         "unpipe": "~1.0.0"
       },
       "dependencies": {
@@ -10796,7 +10919,13 @@
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+          "dev": true
+        },
+        "statuses": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+          "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
           "dev": true
         }
       }
@@ -10814,13 +10943,13 @@
         "json5": {
           "version": "0.5.1",
           "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
-          "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
+          "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==",
           "dev": true
         },
         "path-exists": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
           "dev": true
         }
       }
@@ -10918,9 +11047,9 @@
       "dev": true
     },
     "flow-parser": {
-      "version": "0.174.1",
-      "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.174.1.tgz",
-      "integrity": "sha512-nDMOvlFR+4doLpB3OJpseHZ7uEr3ENptlF6qMas/kzQmNcLzMwfQeFX0gGJ/+em7UdldB/nGsk55tDTOvjbCuw==",
+      "version": "0.181.2",
+      "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.181.2.tgz",
+      "integrity": "sha512-+QzNZEmhYNF9SHrKI8M2lzT07UGkJW6Zoeg7wP+aGkFxh0Mh/wx8eyS/lcwY9bd3B4azS6K50ZjyIjzMWpowGg==",
       "dev": true
     },
     "flush-write-stream": {
@@ -10934,9 +11063,9 @@
       }
     },
     "follow-redirects": {
-      "version": "1.14.9",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
-      "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w=="
+      "version": "1.15.1",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
+      "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
     },
     "for-each": {
       "version": "0.3.3",
@@ -10950,13 +11079,13 @@
     "for-in": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
-      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+      "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==",
       "dev": true
     },
     "forever-agent": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
-      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+      "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw=="
     },
     "form-data": {
       "version": "2.3.3",
@@ -10977,7 +11106,7 @@
     "fragment-cache": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
-      "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+      "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==",
       "dev": true,
       "requires": {
         "map-cache": "^0.2.2"
@@ -10986,13 +11115,13 @@
     "fresh": {
       "version": "0.5.2",
       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
-      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+      "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
       "dev": true
     },
     "from2": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
-      "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
+      "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==",
       "dev": true,
       "requires": {
         "inherits": "^2.0.1",
@@ -11014,7 +11143,7 @@
     "fs-exists-sync": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz",
-      "integrity": "sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=",
+      "integrity": "sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==",
       "dev": true
     },
     "fs-extra": {
@@ -11039,7 +11168,7 @@
     "fs-write-stream-atomic": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
-      "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=",
+      "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==",
       "dev": true,
       "requires": {
         "graceful-fs": "^4.1.2",
@@ -11051,7 +11180,7 @@
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
     },
     "fsevents": {
       "version": "2.3.2",
@@ -11060,38 +11189,6 @@
       "dev": true,
       "optional": true
     },
-    "fstream": {
-      "version": "1.0.12",
-      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
-      "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "inherits": "~2.0.0",
-        "mkdirp": ">=0.5 0",
-        "rimraf": "2"
-      },
-      "dependencies": {
-        "mkdirp": {
-          "version": "0.5.6",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
-          "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.6"
-          }
-        },
-        "rimraf": {
-          "version": "2.7.1",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
-          "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
-          "dev": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        }
-      }
-    },
     "fswin": {
       "version": "2.17.1227",
       "resolved": "https://registry.npmjs.org/fswin/-/fswin-2.17.1227.tgz",
@@ -11104,16 +11201,34 @@
       "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
       "dev": true
     },
+    "function.prototype.name": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
+      "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.19.0",
+        "functions-have-names": "^1.2.2"
+      }
+    },
     "functional-red-black-tree": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
-      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+      "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
+      "dev": true
+    },
+    "functions-have-names": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
       "dev": true
     },
     "gauge": {
       "version": "2.7.4",
       "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
-      "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+      "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==",
       "requires": {
         "aproba": "^1.0.3",
         "console-control-strings": "^1.0.0",
@@ -11125,25 +11240,16 @@
         "wide-align": "^1.1.0"
       }
     },
-    "gaze": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
-      "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==",
-      "dev": true,
-      "requires": {
-        "globule": "^1.0.0"
-      }
-    },
     "generate-function": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-1.1.0.tgz",
-      "integrity": "sha1-VMIbCAGSsW2Yd3ecW7gWZudyNl8=",
+      "integrity": "sha512-Wv4qgYgt2m9QH7K+jklCX/o4gn1ijnS4nT+nxPYBbhdqZLDLtvNh2o26KP/nxN42Tk6AnrGftCLzjiMuckZeQw==",
       "dev": true
     },
     "generate-object-property": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
-      "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
+      "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==",
       "dev": true,
       "requires": {
         "is-property": "^1.0.0"
@@ -11162,14 +11268,14 @@
       "dev": true
     },
     "get-intrinsic": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
-      "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz",
+      "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==",
       "dev": true,
       "requires": {
         "function-bind": "^1.1.1",
         "has": "^1.0.3",
-        "has-symbols": "^1.0.1"
+        "has-symbols": "^1.0.3"
       }
     },
     "get-package-type": {
@@ -11213,13 +11319,13 @@
     "get-value": {
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
-      "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+      "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==",
       "dev": true
     },
     "getpass": {
       "version": "0.1.7",
       "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
-      "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+      "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
       "requires": {
         "assert-plus": "^1.0.0"
       }
@@ -11227,13 +11333,13 @@
     "git-clone": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/git-clone/-/git-clone-0.1.0.tgz",
-      "integrity": "sha1-DXYWN3gJOu9/HDAjjyqe8/B6Lrk=",
+      "integrity": "sha512-zs9rlfa7HyaJAKG9o+V7C6qfMzyc+tb1IIXdUFcOBcR1U7siKy/uPdauLlrH1mc0vOgUwIv4BF+QxPiiTYz3Rw==",
       "dev": true
     },
     "git-config-path": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/git-config-path/-/git-config-path-1.0.1.tgz",
-      "integrity": "sha1-bTP37WPbDQ4RgTFQO6s6ykfVRmQ=",
+      "integrity": "sha512-KcJ2dlrrP5DbBnYIZ2nlikALfRhKzNSX0stvv3ImJ+fvC4hXKoV+U+74SV0upg+jlQZbrtQzc0bu6/Zh+7aQbg==",
       "dev": true,
       "requires": {
         "extend-shallow": "^2.0.1",
@@ -11244,7 +11350,7 @@
         "extend-shallow": {
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
           "dev": true,
           "requires": {
             "is-extendable": "^0.1.0"
@@ -11253,14 +11359,14 @@
       }
     },
     "glob": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
-      "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
       "requires": {
         "fs.realpath": "^1.0.0",
         "inflight": "^1.0.4",
         "inherits": "2",
-        "minimatch": "^3.0.4",
+        "minimatch": "^3.1.1",
         "once": "^1.3.0",
         "path-is-absolute": "^1.0.0"
       }
@@ -11268,7 +11374,7 @@
     "glob-parent": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
-      "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+      "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
       "dev": true,
       "requires": {
         "is-glob": "^3.1.0",
@@ -11278,7 +11384,7 @@
         "is-glob": {
           "version": "3.1.0",
           "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
-          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+          "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==",
           "dev": true,
           "requires": {
             "is-extglob": "^2.1.0"
@@ -11289,7 +11395,7 @@
     "glob-to-regexp": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz",
-      "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=",
+      "integrity": "sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==",
       "dev": true
     },
     "global-dirs": {
@@ -11343,46 +11449,10 @@
         }
       }
     },
-    "globule": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.3.tgz",
-      "integrity": "sha512-mb1aYtDbIjTu4ShMB85m3UzjX9BVKe9WCzsnfMSZk+K5GpIbBOexgg4PPCt5eHDEG5/ZQAUX2Kct02zfiPLsKg==",
-      "dev": true,
-      "requires": {
-        "glob": "~7.1.1",
-        "lodash": "~4.17.10",
-        "minimatch": "~3.0.2"
-      },
-      "dependencies": {
-        "glob": {
-          "version": "7.1.7",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
-          "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "minimatch": {
-          "version": "3.0.8",
-          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz",
-          "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==",
-          "dev": true,
-          "requires": {
-            "brace-expansion": "^1.1.7"
-          }
-        }
-      }
-    },
     "good-listener": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
-      "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
+      "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==",
       "requires": {
         "delegate": "^3.1.2"
       }
@@ -11406,9 +11476,9 @@
       }
     },
     "graceful-fs": {
-      "version": "4.2.9",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
-      "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
+      "version": "4.2.10",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
     },
     "graphql": {
       "version": "14.7.0",
@@ -11449,9 +11519,9 @@
       },
       "dependencies": {
         "tslib": {
-          "version": "2.3.1",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
-          "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
+          "version": "2.4.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+          "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
           "dev": true
         }
       }
@@ -11478,7 +11548,7 @@
     "growly": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
-      "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
+      "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==",
       "dev": true
     },
     "gzip-size": {
@@ -11508,7 +11578,7 @@
     "har-schema": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
-      "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+      "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q=="
     },
     "har-validator": {
       "version": "5.1.5",
@@ -11531,15 +11601,15 @@
     "has-ansi": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
-      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+      "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
       "requires": {
         "ansi-regex": "^2.0.0"
       }
     },
     "has-bigints": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz",
-      "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
+      "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
       "dev": true
     },
     "has-flag": {
@@ -11547,6 +11617,15 @@
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
       "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
     },
+    "has-property-descriptors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
+      "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
+      "dev": true,
+      "requires": {
+        "get-intrinsic": "^1.1.1"
+      }
+    },
     "has-symbol-support-x": {
       "version": "1.4.2",
       "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz",
@@ -11580,12 +11659,12 @@
     "has-unicode": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
-      "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
+      "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
     },
     "has-value": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
-      "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+      "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==",
       "dev": true,
       "requires": {
         "get-value": "^2.0.6",
@@ -11596,7 +11675,7 @@
     "has-values": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
-      "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+      "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==",
       "dev": true,
       "requires": {
         "is-number": "^3.0.0",
@@ -11606,7 +11685,7 @@
         "kind-of": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
-          "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+          "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==",
           "dev": true,
           "requires": {
             "is-buffer": "^1.1.5"
@@ -11685,7 +11764,7 @@
     "hmac-drbg": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
-      "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+      "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==",
       "dev": true,
       "requires": {
         "hash.js": "^1.0.3",
@@ -11719,7 +11798,7 @@
     "hpack.js": {
       "version": "2.1.6",
       "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
-      "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=",
+      "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==",
       "dev": true,
       "requires": {
         "inherits": "^2.0.1",
@@ -11731,13 +11810,13 @@
     "hsl-regex": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz",
-      "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=",
+      "integrity": "sha512-M5ezZw4LzXbBKMruP+BNANf0k+19hDQMgpzBIYnya//Al+fjNct9Wf3b1WedLqdEs2hKBvxq/jh+DsHJLj0F9A==",
       "dev": true
     },
     "hsla-regex": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz",
-      "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=",
+      "integrity": "sha512-7Wn5GMLuHBjZCb2bTmnDOycho0p/7UVaAeqXZGbHrBCl6Yd/xDhQJAXe6Ga9AXJH2I5zY1dEdYw2u1UptnSBJA==",
       "dev": true
     },
     "html-encoding-sniffer": {
@@ -11785,15 +11864,15 @@
       }
     },
     "html-tags": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
-      "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==",
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz",
+      "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==",
       "dev": true
     },
     "html-webpack-plugin": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz",
-      "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=",
+      "integrity": "sha512-Br4ifmjQojUP4EmHnRBoUIYcZ9J7M4bTMcm7u6xoIAIuq2Nte4TzXX0533owvkQKQD1WeMTTTyD4Ni4QKxS0Bg==",
       "dev": true,
       "requires": {
         "html-minifier": "^3.2.3",
@@ -11814,19 +11893,19 @@
         "emojis-list": {
           "version": "2.1.0",
           "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
-          "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
+          "integrity": "sha512-knHEZMgs8BB+MInokmNTg/OyPlAddghe1YBgNwJBc5zsJi/uyIcXoSDsL/W9ymOsBoBGdPIHXYJ9+qKFwRwDng==",
           "dev": true
         },
         "json5": {
           "version": "0.5.1",
           "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
-          "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
+          "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==",
           "dev": true
         },
         "loader-utils": {
           "version": "0.2.17",
           "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz",
-          "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=",
+          "integrity": "sha512-tiv66G0SmiOx+pLWMtGEkfSEejxvb6N6uRrQjfWJIT79W9GMpgKeCAmm9aVBKtd4WEgntciI8CsGqjpDoCWJug==",
           "dev": true,
           "requires": {
             "big.js": "^3.1.3",
@@ -11860,9 +11939,9 @@
       },
       "dependencies": {
         "dom-serializer": {
-          "version": "1.3.2",
-          "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
-          "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==",
+          "version": "1.4.1",
+          "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+          "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
           "dev": true,
           "requires": {
             "domelementtype": "^2.0.1",
@@ -11871,9 +11950,9 @@
           }
         },
         "domelementtype": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
-          "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+          "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
           "dev": true
         },
         "domutils": {
@@ -11897,7 +11976,7 @@
     "http-deceiver": {
       "version": "1.2.7",
       "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
-      "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=",
+      "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==",
       "dev": true
     },
     "http-errors": {
@@ -11914,9 +11993,9 @@
       }
     },
     "http-parser-js": {
-      "version": "0.5.6",
-      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz",
-      "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==",
+      "version": "0.5.8",
+      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
+      "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==",
       "dev": true
     },
     "http-proxy": {
@@ -11992,13 +12071,13 @@
           "dev": true
         },
         "micromatch": {
-          "version": "4.0.4",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
-          "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
+          "version": "4.0.5",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+          "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
           "dev": true,
           "requires": {
-            "braces": "^3.0.1",
-            "picomatch": "^2.2.3"
+            "braces": "^3.0.2",
+            "picomatch": "^2.3.1"
           }
         },
         "to-regex-range": {
@@ -12015,7 +12094,7 @@
     "http-signature": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
-      "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+      "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
       "requires": {
         "assert-plus": "^1.0.0",
         "jsprim": "^1.2.2",
@@ -12025,13 +12104,13 @@
     "https-browserify": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
-      "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
+      "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==",
       "dev": true
     },
     "https-proxy-agent": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
-      "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
       "requires": {
         "agent-base": "6",
         "debug": "4"
@@ -12046,7 +12125,7 @@
     "humanize-ms": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
-      "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=",
+      "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
       "requires": {
         "ms": "^2.0.0"
       }
@@ -12078,7 +12157,7 @@
     "iferr": {
       "version": "0.1.5",
       "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
-      "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
+      "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==",
       "dev": true
     },
     "ignore": {
@@ -12098,20 +12177,20 @@
     "image-size": {
       "version": "0.5.5",
       "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
-      "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
+      "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==",
       "dev": true,
       "optional": true
     },
     "immutable": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz",
-      "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz",
+      "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==",
       "dev": true
     },
     "import-cwd": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
-      "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=",
+      "integrity": "sha512-Ew5AZzJQFqrOV5BTW3EIoHAnoie1LojZLXKcCQ/yTRyVZosBhK1x1ViYjHGf5pAFOq8ZyChZp6m/fSN7pJyZtg==",
       "dev": true,
       "requires": {
         "import-from": "^2.1.0"
@@ -12120,7 +12199,7 @@
     "import-fresh": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
-      "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
+      "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==",
       "dev": true,
       "requires": {
         "caller-path": "^2.0.0",
@@ -12130,7 +12209,7 @@
     "import-from": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz",
-      "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=",
+      "integrity": "sha512-0vdnLL2wSGnhlRmzHJAg5JHjt1l2vYhzJ7tNLGbeVg0fse56tpGaH0uzH+r9Slej+BSXXEHvBKDEnVSLLE9/+w==",
       "dev": true,
       "requires": {
         "resolve-from": "^3.0.0"
@@ -12139,7 +12218,7 @@
     "import-global": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/import-global/-/import-global-0.1.0.tgz",
-      "integrity": "sha1-l7OP1EQRTuwWgkqTX42ldbV6oc4=",
+      "integrity": "sha512-8+hPJLML+m1ym9NSeZXTXFkY5+ml0fYFAzO5yhZiaFQvk9kO0NkE7vd7e7kCVjkTmAxsDPbrWwLQACMwGTDgIg==",
       "dev": true,
       "requires": {
         "global-dirs": "^0.1.0"
@@ -12148,7 +12227,7 @@
         "global-dirs": {
           "version": "0.1.1",
           "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz",
-          "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=",
+          "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==",
           "dev": true,
           "requires": {
             "ini": "^1.3.4"
@@ -12159,7 +12238,7 @@
     "import-lazy": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
-      "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM="
+      "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A=="
     },
     "import-local": {
       "version": "2.0.0",
@@ -12174,13 +12253,7 @@
     "imurmurhash": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
-    },
-    "in-publish": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz",
-      "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==",
-      "dev": true
+      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="
     },
     "indent-string": {
       "version": "4.0.0",
@@ -12190,7 +12263,7 @@
     "indexes-of": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
-      "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
+      "integrity": "sha512-bup+4tap3Hympa+JBJUG7XuOsdNQ6fxt0MHyXMKuLBKn0OqsTfvUxkUrroEX1+B2VsSHvCjiIcZVxRtYa4nllA==",
       "dev": true
     },
     "infer-owner": {
@@ -12201,7 +12274,7 @@
     "inflight": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
       "requires": {
         "once": "^1.3.0",
         "wrappy": "1"
@@ -12348,7 +12421,7 @@
     "into-stream": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-2.0.1.tgz",
-      "integrity": "sha1-25sANpRFPq4JHYpchMwRUHt4HTE=",
+      "integrity": "sha512-7EHX+bSqaYHfWnrREpeGUKO6ox5tW6NgziFx7cZqxBZ3RNRir9cnPCDvJNjrROLP6guznhxMkyus0sK2qQzhrQ==",
       "dev": true,
       "requires": {
         "from2": "^2.1.1"
@@ -12364,14 +12437,14 @@
       }
     },
     "ip": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
-      "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
+      "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg=="
     },
     "ip-regex": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
-      "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=",
+      "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==",
       "dev": true
     },
     "ipaddr.js": {
@@ -12383,13 +12456,13 @@
     "is-absolute-url": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
-      "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=",
+      "integrity": "sha512-vOx7VprsKyllwjSkLV79NIhpyLfr3jAp7VaTCMXOJHu4m0Ew1CZ2fcjASwmV1jI3BWuWHB013M48eyeldk9gYg==",
       "dev": true
     },
     "is-accessor-descriptor": {
       "version": "0.1.6",
       "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
-      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+      "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==",
       "dev": true,
       "requires": {
         "kind-of": "^3.0.2"
@@ -12398,7 +12471,7 @@
         "kind-of": {
           "version": "3.2.2",
           "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
           "dev": true,
           "requires": {
             "is-buffer": "^1.1.5"
@@ -12419,7 +12492,7 @@
     "is-arrayish": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
-      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
       "dev": true
     },
     "is-bigint": {
@@ -12472,7 +12545,7 @@
     "is-color-stop": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz",
-      "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=",
+      "integrity": "sha512-H1U8Vz0cfXNujrJzEcvvwMDW9Ra+biSYA3ThdQvAnMLJkEHQXn6bWzLkxHtVYJ+Sdbx0b6finn3jZiaVe7MAHA==",
       "dev": true,
       "requires": {
         "css-color-names": "^0.0.4",
@@ -12484,9 +12557,9 @@
       }
     },
     "is-core-module": {
-      "version": "2.8.1",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz",
-      "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==",
+      "version": "2.9.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz",
+      "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==",
       "dev": true,
       "requires": {
         "has": "^1.0.3"
@@ -12495,7 +12568,7 @@
     "is-data-descriptor": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
-      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+      "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==",
       "dev": true,
       "requires": {
         "kind-of": "^3.0.2"
@@ -12504,7 +12577,7 @@
         "kind-of": {
           "version": "3.2.2",
           "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
           "dev": true,
           "requires": {
             "is-buffer": "^1.1.5"
@@ -12543,7 +12616,7 @@
     "is-directory": {
       "version": "0.3.1",
       "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
-      "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
+      "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==",
       "dev": true
     },
     "is-docker": {
@@ -12555,25 +12628,19 @@
     "is-extendable": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
-      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+      "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
       "dev": true
     },
     "is-extglob": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
-      "dev": true
-    },
-    "is-finite": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
-      "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
       "dev": true
     },
     "is-fullwidth-code-point": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
-      "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+      "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==",
       "requires": {
         "number-is-nan": "^1.0.0"
       }
@@ -12605,12 +12672,12 @@
     "is-lambda": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
-      "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU="
+      "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ=="
     },
     "is-natural-number": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz",
-      "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=",
+      "integrity": "sha512-Y4LTamMe0DDQIIAlaer9eKebAlDSV6huy+TWhJVPlzZh2o4tRP5SQWFlLn5N0To4mDD22/qdOq+veo1cSISLgQ==",
       "dev": true
     },
     "is-negative-zero": {
@@ -12627,7 +12694,7 @@
     "is-number": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
-      "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+      "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==",
       "dev": true,
       "requires": {
         "kind-of": "^3.0.2"
@@ -12636,7 +12703,7 @@
         "kind-of": {
           "version": "3.2.2",
           "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
           "dev": true,
           "requires": {
             "is-buffer": "^1.1.5"
@@ -12645,9 +12712,9 @@
       }
     },
     "is-number-object": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz",
-      "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==",
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
+      "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
       "dev": true,
       "requires": {
         "has-tostringtag": "^1.0.0"
@@ -12698,7 +12765,7 @@
     "is-plain-obj": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
-      "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
+      "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
       "dev": true
     },
     "is-plain-object": {
@@ -12715,7 +12782,7 @@
     "is-property": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
-      "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=",
+      "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
       "dev": true
     },
     "is-regex": {
@@ -12741,15 +12808,18 @@
       "dev": true
     },
     "is-shared-array-buffer": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz",
-      "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==",
-      "dev": true
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
+      "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.2"
+      }
     },
     "is-stream": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
-      "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
+      "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
       "dev": true
     },
     "is-string": {
@@ -12773,13 +12843,7 @@
     "is-typedarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
-      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
-    },
-    "is-utf8": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
-      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
-      "dev": true
+      "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
     },
     "is-weakref": {
       "version": "1.0.2",
@@ -12799,7 +12863,7 @@
     "is-whitespace": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/is-whitespace/-/is-whitespace-0.3.0.tgz",
-      "integrity": "sha1-Fjnssb4DauxppUy7QBz77XEUq38=",
+      "integrity": "sha512-RydPhl4S6JwAyj0JJjshWJEFG6hNye3pZFBRZaTUfZFwGHxzppNaNOVgQuS/E/SlhrApuMXrpnK1EEIXfdo3Dg==",
       "dev": true
     },
     "is-windows": {
@@ -12811,7 +12875,7 @@
     "is-wsl": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
-      "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=",
+      "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==",
       "dev": true
     },
     "is-yarn-global": {
@@ -12822,29 +12886,29 @@
     "isarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
     },
     "isbinaryfile": {
-      "version": "4.0.8",
-      "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz",
-      "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==",
+      "version": "4.0.10",
+      "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz",
+      "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==",
       "dev": true
     },
     "isexe": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
     },
     "isobject": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
       "dev": true
     },
     "isstream": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
-      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+      "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
     },
     "istanbul-lib-coverage": {
       "version": "2.0.5",
@@ -12889,7 +12953,7 @@
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "make-dir": {
@@ -12999,7 +13063,7 @@
     "javascript-stringify": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-1.6.0.tgz",
-      "integrity": "sha1-FC0RHzpuPa6PSpr9d9RYVbWpzOM=",
+      "integrity": "sha512-fnjC0up+0SjEJtgmmG+teeel68kutkvzfctO/KxE3qJlbunkJYAshgH3boU++gSBHP8z5/r0ts0qRIrHf0RTQQ==",
       "dev": true
     },
     "jest": {
@@ -13061,7 +13125,7 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "emoji-regex": {
@@ -13082,13 +13146,13 @@
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "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=",
+          "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
           "dev": true
         },
         "jest-cli": {
@@ -13134,7 +13198,7 @@
         "path-exists": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
           "dev": true
         },
         "string-width": {
@@ -13296,13 +13360,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "slash": {
@@ -13366,13 +13430,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "supports-color": {
@@ -13440,13 +13504,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "supports-color": {
@@ -13571,7 +13635,7 @@
         "tr46": {
           "version": "1.0.1",
           "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
-          "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
+          "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
           "dev": true,
           "requires": {
             "punycode": "^2.1.0"
@@ -13659,7 +13723,7 @@
         "normalize-path": {
           "version": "2.1.1",
           "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
-          "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+          "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
           "dev": true,
           "requires": {
             "remove-trailing-separator": "^1.0.1"
@@ -13723,13 +13787,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "supports-color": {
@@ -13797,13 +13861,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "supports-color": {
@@ -13865,13 +13929,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "slash": {
@@ -13957,13 +14021,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "supports-color": {
@@ -14047,13 +14111,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "supports-color": {
@@ -14147,7 +14211,7 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "emoji-regex": {
@@ -14168,13 +14232,13 @@
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "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=",
+          "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
           "dev": true
         },
         "locate-path": {
@@ -14199,7 +14263,7 @@
         "path-exists": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
           "dev": true
         },
         "slash": {
@@ -14293,7 +14357,7 @@
     "jest-serializer-vue": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/jest-serializer-vue/-/jest-serializer-vue-2.0.2.tgz",
-      "integrity": "sha1-sjjvKGNX7GtIBCG9RxRQUJh9WbM=",
+      "integrity": "sha512-nK/YIFo6qe3i9Ge+hr3h4PpRehuPPGZFt8LDBdTHYldMb7ZWlkanZS8Ls7D8h6qmQP2lBQVDLP0DKn5bJ9QApQ==",
       "dev": true,
       "requires": {
         "pretty": "2.0.0"
@@ -14352,13 +14416,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "mkdirp": {
@@ -14445,13 +14509,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "mkdirp": {
@@ -14526,13 +14590,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "supports-color": {
@@ -14599,13 +14663,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "string-length": {
@@ -14691,13 +14755,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "supports-color": {
@@ -14724,7 +14788,7 @@
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "supports-color": {
@@ -14741,21 +14805,15 @@
     "jju": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz",
-      "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo="
-    },
-    "js-base64": {
-      "version": "2.6.4",
-      "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
-      "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==",
-      "dev": true
+      "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA=="
     },
     "js-beautify": {
-      "version": "1.14.0",
-      "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.0.tgz",
-      "integrity": "sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ==",
+      "version": "1.14.4",
+      "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.4.tgz",
+      "integrity": "sha512-+b4A9c3glceZEmxyIbxDOYB0ZJdReLvyU1077RqKsO4dZx9FUHjTOJn8VHwpg33QoucIykOiYbh7MfqBOghnrA==",
       "dev": true,
       "requires": {
-        "config-chain": "^1.1.12",
+        "config-chain": "^1.1.13",
         "editorconfig": "^0.15.3",
         "glob": "^7.1.3",
         "nopt": "^5.0.0"
@@ -14789,7 +14847,7 @@
     "jsbn": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
-      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
+      "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
     },
     "jscodeshift": {
       "version": "0.11.0",
@@ -14846,9 +14904,9 @@
           }
         },
         "tslib": {
-          "version": "2.3.1",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
-          "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
+          "version": "2.4.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+          "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
           "dev": true
         },
         "write-file-atomic": {
@@ -14907,7 +14965,7 @@
         "tr46": {
           "version": "1.0.1",
           "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
-          "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
+          "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
           "dev": true,
           "requires": {
             "punycode": "^2.1.0"
@@ -14950,7 +15008,7 @@
     "json-buffer": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
-      "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg="
+      "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ=="
     },
     "json-parse-better-errors": {
       "version": "1.0.2",
@@ -14966,7 +15024,7 @@
     "json-parse-helpfulerror": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz",
-      "integrity": "sha1-E/FM4C7tTpgSl7ZOueO5MuLdE9w=",
+      "integrity": "sha512-XgP0FGR77+QhUxjXkwOMkC94k3WtqEBfcnjWqhRd82qTat4SWKRE+9kUnynz/shm3I4ea2+qISvTIeGTNU7kJg==",
       "requires": {
         "jju": "^1.1.0"
       }
@@ -14984,13 +15042,21 @@
     "json-stable-stringify-without-jsonify": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
-      "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
       "dev": true
     },
     "json-stringify-safe": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
-      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+      "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
+    },
+    "json2mq": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz",
+      "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==",
+      "requires": {
+        "string-convert": "^0.2.0"
+      }
     },
     "json5": {
       "version": "2.2.1",
@@ -15000,7 +15066,7 @@
     "jsonfile": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
-      "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+      "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
       "dev": true,
       "requires": {
         "graceful-fs": "^4.1.6"
@@ -15009,7 +15075,7 @@
     "jsonparse": {
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
-      "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA="
+      "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg=="
     },
     "jsprim": {
       "version": "1.4.2",
@@ -15056,9 +15122,9 @@
       }
     },
     "launch-editor": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.3.0.tgz",
-      "integrity": "sha512-3QrsCXejlWYHjBPFXTyGNhPj4rrQdB+5+r5r3wArpLH201aR+nWUgw/zKKkTmilCfY/sv6u8qo98pNvtg8LUTA==",
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.4.0.tgz",
+      "integrity": "sha512-mZ0BHeSn/ohL+Ib+b+JnxC59vcNz6v5IR9d0CuM8f0x8ni8oK3IIG6G0vMkpxc0gFsmvINkztGOHiWTaX4BmAg==",
       "dev": true,
       "requires": {
         "picocolors": "^1.0.0",
@@ -15074,12 +15140,12 @@
       }
     },
     "launch-editor-middleware": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.3.0.tgz",
-      "integrity": "sha512-GJR64trLdFFwCoL9DMn/d1SZX0OzTDPixu4mcfWTShQ4tIqCHCGvlg9fOEYQXyBlrSMQwylsJfUWncheShfV2w==",
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/launch-editor-middleware/-/launch-editor-middleware-2.4.0.tgz",
+      "integrity": "sha512-/M7AX/6xktZY60KE7j71XLrj9U6H5TBoP+mJzhYB3fcdAq8rcazit/K0qWiu1jvytUPXP4lJRd1VJFwvdMQ/uw==",
       "dev": true,
       "requires": {
-        "launch-editor": "^2.3.0"
+        "launch-editor": "^2.4.0"
       }
     },
     "left-pad": {
@@ -15133,9 +15199,9 @@
       }
     },
     "less-bundle-promise": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/less-bundle-promise/-/less-bundle-promise-1.0.7.tgz",
-      "integrity": "sha512-B4mN+YtkOxAPUHyorhup+ETVNZ9E1PO65sPhgPvDDHDVtR1oYRd87EbYVYOsU0Oev0MW/6MSouS5QYlhe7XrzA=="
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/less-bundle-promise/-/less-bundle-promise-1.0.11.tgz",
+      "integrity": "sha512-LozmEciljdXe0CwEH6uWTlpQDlOVM8d3kkj14P+Jeze/AUhaPZs02x6INJh4TYSeO5xw4RxkpzXTELZSkLKC6Q=="
     },
     "less-loader": {
       "version": "5.0.0",
@@ -15151,7 +15217,7 @@
         "clone": {
           "version": "2.1.2",
           "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
-          "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
+          "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
           "dev": true
         },
         "json5": {
@@ -15191,7 +15257,7 @@
     "levn": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
-      "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+      "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
       "dev": true,
       "requires": {
         "prelude-ls": "~1.1.2",
@@ -15236,7 +15302,7 @@
         "path-exists": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
+          "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="
         }
       }
     },
@@ -15249,7 +15315,7 @@
     "load-json-file": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
-      "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
+      "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==",
       "dev": true,
       "requires": {
         "graceful-fs": "^4.1.2",
@@ -15261,7 +15327,7 @@
         "parse-json": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
-          "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+          "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
           "dev": true,
           "requires": {
             "error-ex": "^1.3.1",
@@ -15283,7 +15349,7 @@
         "find-cache-dir": {
           "version": "0.1.1",
           "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz",
-          "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=",
+          "integrity": "sha512-Z9XSBoNE7xQiV6MSgPuCfyMokH2K7JdpRkOYE1+mu3d4BFJtx3GW+f6Bo4q8IX6rlf5MYbLBKW0pjl2cWdkm2A==",
           "dev": true,
           "requires": {
             "commondir": "^1.0.1",
@@ -15294,7 +15360,7 @@
         "find-up": {
           "version": "1.1.2",
           "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
-          "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+          "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==",
           "dev": true,
           "requires": {
             "path-exists": "^2.0.0",
@@ -15313,7 +15379,7 @@
         "path-exists": {
           "version": "2.1.0",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
-          "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+          "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==",
           "dev": true,
           "requires": {
             "pinkie-promise": "^2.0.0"
@@ -15322,7 +15388,7 @@
         "pkg-dir": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
-          "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=",
+          "integrity": "sha512-c6pv3OE78mcZ92ckebVDqg0aWSoKhOTbwCV6qbCWMk546mAL9pZln0+QsN/yQ7fkucd4+yJPLrCBXNt8Ruk+Eg==",
           "dev": true,
           "requires": {
             "find-up": "^1.0.0"
@@ -15367,13 +15433,13 @@
     "lodash.clonedeep": {
       "version": "4.5.0",
       "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
-      "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
+      "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
       "dev": true
     },
     "lodash.debounce": {
       "version": "4.0.8",
       "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
-      "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
+      "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
       "dev": true
     },
     "lodash.defaultsdeep": {
@@ -15385,19 +15451,19 @@
     "lodash.kebabcase": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
-      "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=",
+      "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==",
       "dev": true
     },
     "lodash.mapvalues": {
       "version": "4.6.0",
       "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz",
-      "integrity": "sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=",
+      "integrity": "sha512-JPFqXFeZQ7BfS00H58kClY7SPVeHertPE0lNuCyZ26/XlN8TvakYD7b9bGyNmXbT/D3BbtPAAmq90gPWqLkxlQ==",
       "dev": true
     },
     "lodash.memoize": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
-      "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
+      "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
       "dev": true
     },
     "lodash.merge": {
@@ -15409,19 +15475,19 @@
     "lodash.sortby": {
       "version": "4.7.0",
       "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
-      "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
+      "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==",
       "dev": true
     },
     "lodash.transform": {
       "version": "4.6.0",
       "resolved": "https://registry.npmjs.org/lodash.transform/-/lodash.transform-4.6.0.tgz",
-      "integrity": "sha1-EjBkIvYzJK7YSD0/ODMrX2cFR6A=",
+      "integrity": "sha512-LO37ZnhmBVx0GvOU/caQuipEh4GN82TcWv3yHlebGDgOxbxiwwzW5Pcx2AcvpIv2WmvmSMoC492yQFNhy/l/UQ==",
       "dev": true
     },
     "lodash.uniq": {
       "version": "4.5.0",
       "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
-      "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
+      "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
       "dev": true
     },
     "log-symbols": {
@@ -15465,13 +15531,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "supports-color": {
@@ -15505,16 +15571,6 @@
         "js-tokens": "^3.0.0 || ^4.0.0"
       }
     },
-    "loud-rejection": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
-      "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
-      "dev": true,
-      "requires": {
-        "currently-unhandled": "^0.4.1",
-        "signal-exit": "^3.0.0"
-      }
-    },
     "lowdb": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/lowdb/-/lowdb-1.0.0.tgz",
@@ -15531,7 +15587,7 @@
     "lower-case": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
-      "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=",
+      "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==",
       "dev": true
     },
     "lowercase-keys": {
@@ -15611,19 +15667,13 @@
     "map-cache": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
-      "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
-      "dev": true
-    },
-    "map-obj": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
-      "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+      "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==",
       "dev": true
     },
     "map-visit": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
-      "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+      "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==",
       "dev": true,
       "requires": {
         "object-visit": "^1.0.0"
@@ -15659,127 +15709,24 @@
     "media-typer": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
-      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+      "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
       "dev": true
     },
+    "memoize-one": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
+      "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
+    },
     "memory-fs": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
-      "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
+      "integrity": "sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==",
       "dev": true,
       "requires": {
         "errno": "^0.1.3",
         "readable-stream": "^2.0.1"
       }
     },
-    "meow": {
-      "version": "3.7.0",
-      "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
-      "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
-      "dev": true,
-      "requires": {
-        "camelcase-keys": "^2.0.0",
-        "decamelize": "^1.1.2",
-        "loud-rejection": "^1.0.0",
-        "map-obj": "^1.0.1",
-        "minimist": "^1.1.3",
-        "normalize-package-data": "^2.3.4",
-        "object-assign": "^4.0.1",
-        "read-pkg-up": "^1.0.1",
-        "redent": "^1.0.0",
-        "trim-newlines": "^1.0.0"
-      },
-      "dependencies": {
-        "find-up": {
-          "version": "1.1.2",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
-          "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
-          "dev": true,
-          "requires": {
-            "path-exists": "^2.0.0",
-            "pinkie-promise": "^2.0.0"
-          }
-        },
-        "load-json-file": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
-          "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.1.2",
-            "parse-json": "^2.2.0",
-            "pify": "^2.0.0",
-            "pinkie-promise": "^2.0.0",
-            "strip-bom": "^2.0.0"
-          }
-        },
-        "parse-json": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
-          "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
-          "dev": true,
-          "requires": {
-            "error-ex": "^1.2.0"
-          }
-        },
-        "path-exists": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
-          "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
-          "dev": true,
-          "requires": {
-            "pinkie-promise": "^2.0.0"
-          }
-        },
-        "path-type": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
-          "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.1.2",
-            "pify": "^2.0.0",
-            "pinkie-promise": "^2.0.0"
-          }
-        },
-        "pify": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-          "dev": true
-        },
-        "read-pkg": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
-          "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
-          "dev": true,
-          "requires": {
-            "load-json-file": "^1.0.0",
-            "normalize-package-data": "^2.3.2",
-            "path-type": "^1.0.0"
-          }
-        },
-        "read-pkg-up": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
-          "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
-          "dev": true,
-          "requires": {
-            "find-up": "^1.0.0",
-            "read-pkg": "^1.0.0"
-          }
-        },
-        "strip-bom": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
-          "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
-          "dev": true,
-          "requires": {
-            "is-utf8": "^0.2.0"
-          }
-        }
-      }
-    },
     "merge": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz",
@@ -15789,7 +15736,7 @@
     "merge-descriptors": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
-      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
+      "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
       "dev": true
     },
     "merge-source-map": {
@@ -15816,7 +15763,7 @@
     "methods": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
-      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+      "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
       "dev": true
     },
     "micromatch": {
@@ -15923,7 +15870,7 @@
         "normalize-url": {
           "version": "1.9.1",
           "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
-          "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
+          "integrity": "sha512-A48My/mtCklowHBlI8Fq2jFWK4tX4lJ5E6ytFsSOq1fzpvT0SQSgKhSg7lN5c2uYFOrUAOQp6zhhJnpp1eMloQ==",
           "dev": true,
           "requires": {
             "object-assign": "^4.0.1",
@@ -15935,13 +15882,13 @@
         "prepend-http": {
           "version": "1.0.4",
           "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
-          "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
+          "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==",
           "dev": true
         },
         "query-string": {
           "version": "4.3.4",
           "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
-          "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
+          "integrity": "sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==",
           "dev": true,
           "requires": {
             "object-assign": "^4.1.0",
@@ -15980,7 +15927,7 @@
     "minimalistic-crypto-utils": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
-      "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
+      "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==",
       "dev": true
     },
     "minimatch": {
@@ -15997,9 +15944,9 @@
       "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
     },
     "minipass": {
-      "version": "3.1.6",
-      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz",
-      "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==",
+      "version": "3.3.4",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz",
+      "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==",
       "requires": {
         "yallist": "^4.0.0"
       }
@@ -16124,14 +16071,29 @@
       "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
     },
     "moment": {
-      "version": "2.29.1",
-      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
-      "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
+      "version": "2.29.3",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz",
+      "integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw=="
+    },
+    "moment-timezone": {
+      "version": "0.5.43",
+      "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.43.tgz",
+      "integrity": "sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==",
+      "requires": {
+        "moment": "^2.29.4"
+      },
+      "dependencies": {
+        "moment": {
+          "version": "2.29.4",
+          "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+          "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
+        }
+      }
     },
     "move-concurrently": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
-      "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
+      "integrity": "sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==",
       "dev": true,
       "requires": {
         "aproba": "^1.1.1",
@@ -16143,12 +16105,12 @@
       },
       "dependencies": {
         "mkdirp": {
-          "version": "0.5.5",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
-          "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+          "version": "0.5.6",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+          "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
           "dev": true,
           "requires": {
-            "minimist": "^1.2.5"
+            "minimist": "^1.2.6"
           }
         },
         "rimraf": {
@@ -16180,9 +16142,14 @@
     "multicast-dns-service-types": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
-      "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
+      "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==",
       "dev": true
     },
+    "mustache": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
+      "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="
+    },
     "mute-stream": {
       "version": "0.0.8",
       "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
@@ -16201,15 +16168,16 @@
       }
     },
     "nan": {
-      "version": "2.15.0",
-      "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
-      "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==",
-      "dev": true
+      "version": "2.16.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz",
+      "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
+      "dev": true,
+      "optional": true
     },
     "nanoid": {
-      "version": "3.3.1",
-      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
-      "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw=="
+      "version": "3.3.4",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
+      "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw=="
     },
     "nanomatch": {
       "version": "1.2.13",
@@ -16245,13 +16213,13 @@
     "natural-compare": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
-      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
+      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
       "dev": true
     },
     "ndjson": {
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-1.5.0.tgz",
-      "integrity": "sha1-rmA7NrE0vOw0e0UkIrC/mNWDLsg=",
+      "integrity": "sha512-hUPLuaziboGjNF7wHngkgVc0FOclR8dDk/HfEvTtDr/iUrqBWiRcRSTK3/nLOqKH33th714BrMmTPtObI9gZxQ==",
       "dev": true,
       "requires": {
         "json-stringify-safe": "^5.0.1",
@@ -16263,7 +16231,7 @@
     "neat-csv": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/neat-csv/-/neat-csv-2.1.0.tgz",
-      "integrity": "sha1-BvWDYMTDuVW9Rn3cha5FEaOQekw=",
+      "integrity": "sha512-SRzLDeOV/RKF5Em08QWEEbfceBMTl9f+zkqupMqDbEa19ieeQ7UKz42mQBj6zNQaCC4u7uauG4dF8aUOWTnZ8w==",
       "dev": true,
       "requires": {
         "csv-parser": "^1.6.0",
@@ -16274,7 +16242,7 @@
         "get-stream": {
           "version": "2.3.1",
           "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz",
-          "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=",
+          "integrity": "sha512-AUGhbbemXxrZJRD5cDvKtQxLuYaIbNtDTK8YqupCI393Q2KSTreEsLUN3ZxAWFGiKTzL6nKuzfcIvieflUX9qA==",
           "dev": true,
           "requires": {
             "object-assign": "^4.0.1",
@@ -16323,7 +16291,7 @@
     "node-alias": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/node-alias/-/node-alias-1.0.4.tgz",
-      "integrity": "sha1-HxuRa1a56iQcATX5fO1pQPVW8pI=",
+      "integrity": "sha512-9uG48bfkbG9BlKe8QrlxuiPNaKl3wpQn6tJbrojVqgkJuWIO28ifRKrRDrrK+ee72rJ25EaE//PhSIo8E29lLw==",
       "requires": {
         "chalk": "^1.1.1",
         "lodash": "^4.2.0"
@@ -16332,12 +16300,12 @@
         "ansi-styles": {
           "version": "2.2.1",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
-          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+          "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA=="
         },
         "chalk": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
-          "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+          "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
           "requires": {
             "ansi-styles": "^2.2.1",
             "escape-string-regexp": "^1.0.2",
@@ -16349,7 +16317,7 @@
         "supports-color": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
-          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+          "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g=="
         }
       }
     },
@@ -16366,7 +16334,7 @@
         "clone": {
           "version": "2.1.2",
           "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
-          "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
+          "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
           "dev": true
         }
       }
@@ -16374,7 +16342,7 @@
     "node-dir": {
       "version": "0.1.17",
       "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz",
-      "integrity": "sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=",
+      "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==",
       "dev": true,
       "requires": {
         "minimatch": "^3.0.2"
@@ -16415,7 +16383,7 @@
     "node-int64": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
-      "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=",
+      "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
       "dev": true
     },
     "node-libs-browser": {
@@ -16463,7 +16431,7 @@
         "punycode": {
           "version": "1.4.1",
           "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+          "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
           "dev": true
         }
       }
@@ -16500,9 +16468,9 @@
       }
     },
     "node-releases": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz",
-      "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==",
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz",
+      "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==",
       "dev": true
     },
     "nopt": {
@@ -16532,12 +16500,12 @@
           "dev": true
         },
         "resolve": {
-          "version": "1.22.0",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
-          "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
+          "version": "1.22.1",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
+          "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
           "dev": true,
           "requires": {
-            "is-core-module": "^2.8.1",
+            "is-core-module": "^2.9.0",
             "path-parse": "^1.0.7",
             "supports-preserve-symlinks-flag": "^1.0.0"
           }
@@ -16559,7 +16527,7 @@
     "normalize-range": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
-      "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
+      "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
       "dev": true
     },
     "normalize-url": {
@@ -16673,7 +16641,7 @@
     "npm-run-path": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
-      "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+      "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
       "dev": true,
       "requires": {
         "path-key": "^2.0.0"
@@ -16693,7 +16661,7 @@
     "nprogress": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
-      "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E="
+      "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA=="
     },
     "nth-check": {
       "version": "1.0.2",
@@ -16707,18 +16675,18 @@
     "num2fraction": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
-      "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
+      "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==",
       "dev": true
     },
     "number-is-nan": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
-      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+      "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ=="
     },
     "nwsapi": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
-      "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.1.tgz",
+      "integrity": "sha512-JYOWTeFoS0Z93587vRJgASD5Ut11fYl5NyihP3KrYBvMe1FRRs6RN7m20SA/16GM4P6hTnZjT+UmDOt38UeXNg==",
       "dev": true
     },
     "oauth-sign": {
@@ -16729,12 +16697,12 @@
     "object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
     },
     "object-copy": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
-      "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+      "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==",
       "dev": true,
       "requires": {
         "copy-descriptor": "^0.1.0",
@@ -16745,7 +16713,7 @@
         "define-property": {
           "version": "0.2.5",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
           "dev": true,
           "requires": {
             "is-descriptor": "^0.1.0"
@@ -16754,7 +16722,7 @@
         "kind-of": {
           "version": "3.2.2",
           "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
           "dev": true,
           "requires": {
             "is-buffer": "^1.1.5"
@@ -16769,9 +16737,9 @@
       "dev": true
     },
     "object-inspect": {
-      "version": "1.12.0",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
-      "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==",
+      "version": "1.12.2",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
+      "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
       "dev": true
     },
     "object-is": {
@@ -16799,7 +16767,7 @@
     "object-visit": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
-      "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+      "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==",
       "dev": true,
       "requires": {
         "isobject": "^3.0.0"
@@ -16818,20 +16786,21 @@
       }
     },
     "object.getownpropertydescriptors": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz",
-      "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==",
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz",
+      "integrity": "sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ==",
       "dev": true,
       "requires": {
+        "array.prototype.reduce": "^1.0.4",
         "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.19.1"
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.1"
       }
     },
     "object.pick": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
-      "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+      "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==",
       "dev": true,
       "requires": {
         "isobject": "^3.0.1"
@@ -16854,15 +16823,10 @@
       "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
       "dev": true
     },
-    "omit.js": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/omit.js/-/omit.js-2.0.2.tgz",
-      "integrity": "sha512-hJmu9D+bNB40YpL9jYebQl4lsTW6yEHRTroJzNLqQJYHm7c+NQnJGfZmIWh8S3q3KoaxV1aLhV6B3+0N0/kyJg=="
-    },
     "on-finished": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
-      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+      "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
       "dev": true,
       "requires": {
         "ee-first": "1.1.1"
@@ -16877,7 +16841,7 @@
     "once": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
       "requires": {
         "wrappy": "1"
       }
@@ -16885,7 +16849,7 @@
     "onetime": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
-      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+      "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==",
       "dev": true,
       "requires": {
         "mimic-fn": "^1.0.0"
@@ -16981,13 +16945,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "strip-ansi": {
@@ -17010,43 +16974,18 @@
         }
       }
     },
-    "original": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
-      "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==",
-      "dev": true,
-      "requires": {
-        "url-parse": "^1.4.3"
-      }
-    },
     "os-browserify": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
-      "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
-      "dev": true
-    },
-    "os-homedir": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
-      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+      "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==",
       "dev": true
     },
     "os-tmpdir": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
-      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+      "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
       "dev": true
     },
-    "osenv": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
-      "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
-      "dev": true,
-      "requires": {
-        "os-homedir": "^1.0.0",
-        "os-tmpdir": "^1.0.0"
-      }
-    },
     "p-cancelable": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz",
@@ -17055,7 +16994,7 @@
     "p-each-series": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz",
-      "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=",
+      "integrity": "sha512-J/e9xiZZQNrt+958FFzJ+auItsBGq+UrQ7nE89AUP7UOTtjHnkISANXLdayhVzh538UnLMCSlf13lFfRIAKQOA==",
       "dev": true,
       "requires": {
         "p-reduce": "^1.0.0"
@@ -17073,13 +17012,13 @@
     "p-finally": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
-      "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
+      "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
       "dev": true
     },
     "p-is-promise": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz",
-      "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=",
+      "integrity": "sha512-zL7VE4JVS2IFSkR2GQKDSPEVxkoH43/p7oEnwpdCndKYJO0HVeRB7fA8TJwuLOTBREtK0ea8eHaxdwcpob5dmg==",
       "dev": true
     },
     "p-limit": {
@@ -17109,7 +17048,7 @@
     "p-reduce": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz",
-      "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=",
+      "integrity": "sha512-3Tx1T3oM1xO/Y8Gj0sWyE78EIJZ+t+aEmXUdvQgvGmSMri7aPTHoovbXEreWKkL5j21Er60XAWLTzKbAKYOujQ==",
       "dev": true
     },
     "p-retry": {
@@ -17199,7 +17138,7 @@
     "param-case": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
-      "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=",
+      "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==",
       "dev": true,
       "requires": {
         "no-case": "^2.2.0"
@@ -17253,7 +17192,7 @@
     "parse-passwd": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
-      "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+      "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==",
       "dev": true
     },
     "parse5": {
@@ -17288,7 +17227,7 @@
     "pascalcase": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
-      "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+      "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==",
       "dev": true
     },
     "path-browserify": {
@@ -17300,7 +17239,7 @@
     "path-dirname": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
-      "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
+      "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==",
       "dev": true
     },
     "path-exists": {
@@ -17311,18 +17250,18 @@
     "path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
     },
     "path-is-inside": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
-      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+      "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==",
       "dev": true
     },
     "path-key": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
-      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+      "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
       "dev": true
     },
     "path-parse": {
@@ -17333,7 +17272,7 @@
     "path-to-regexp": {
       "version": "0.1.7",
       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
-      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
+      "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
       "dev": true
     },
     "path-type": {
@@ -17361,13 +17300,13 @@
     "pend": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
-      "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+      "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
       "dev": true
     },
     "performance-now": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
-      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+      "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
     },
     "picocolors": {
       "version": "0.2.1",
@@ -17392,7 +17331,7 @@
         "cross-spawn": {
           "version": "5.1.0",
           "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
-          "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+          "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==",
           "dev": true,
           "requires": {
             "lru-cache": "^4.0.1",
@@ -17418,7 +17357,7 @@
         "get-stream": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
-          "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
+          "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==",
           "dev": true
         },
         "lru-cache": {
@@ -17443,7 +17382,7 @@
         "yallist": {
           "version": "2.1.2",
           "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
-          "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+          "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
           "dev": true
         }
       }
@@ -17451,19 +17390,19 @@
     "pify": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
-      "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+      "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
       "dev": true
     },
     "pinkie": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
-      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+      "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==",
       "dev": true
     },
     "pinkie-promise": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
-      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==",
       "dev": true,
       "requires": {
         "pinkie": "^2.0.0"
@@ -17515,7 +17454,7 @@
         "path-exists": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
           "dev": true
         }
       }
@@ -17569,7 +17508,7 @@
     "posix-character-classes": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
-      "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+      "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==",
       "dev": true
     },
     "postcss": {
@@ -18124,9 +18063,9 @@
       }
     },
     "postcss-selector-parser": {
-      "version": "6.0.9",
-      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz",
-      "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==",
+      "version": "6.0.10",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
+      "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
       "dev": true,
       "requires": {
         "cssesc": "^3.0.0",
@@ -18172,25 +18111,25 @@
     "prelude-ls": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
-      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+      "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
       "dev": true
     },
     "prepend-http": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
-      "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc="
+      "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA=="
     },
     "prettier": {
-      "version": "2.6.0",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.0.tgz",
-      "integrity": "sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A==",
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
+      "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
       "dev": true,
       "optional": true
     },
     "pretty": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/pretty/-/pretty-2.0.0.tgz",
-      "integrity": "sha1-rbx5YLe7/iiaVX3F9zdhmiINBqU=",
+      "integrity": "sha512-G9xUchgTEiNpormdYBl+Pha50gOUovT18IvAe7EYMZ1/f9W/WWMPRn+xI68yXNMUk3QXHDwo/1wV/4NejVNe1w==",
       "dev": true,
       "requires": {
         "condense-newlines": "^0.2.1",
@@ -18201,7 +18140,7 @@
         "extend-shallow": {
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
           "dev": true,
           "requires": {
             "is-extendable": "^0.1.0"
@@ -18258,15 +18197,15 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         }
       }
     },
     "prismjs": {
-      "version": "1.27.0",
-      "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz",
-      "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==",
+      "version": "1.28.0",
+      "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.28.0.tgz",
+      "integrity": "sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw==",
       "dev": true
     },
     "private": {
@@ -18278,7 +18217,7 @@
     "process": {
       "version": "0.11.10",
       "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
-      "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
+      "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
       "dev": true
     },
     "process-exists": {
@@ -18303,7 +18242,7 @@
     "promise-inflight": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
-      "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM="
+      "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g=="
     },
     "promise-retry": {
       "version": "2.0.1",
@@ -18326,7 +18265,7 @@
     "proto-list": {
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
-      "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=",
+      "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==",
       "dev": true
     },
     "proxy-addr": {
@@ -18342,7 +18281,7 @@
     "prr": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
-      "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
+      "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
       "dev": true
     },
     "ps-list": {
@@ -18358,7 +18297,7 @@
     "pseudomap": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
-      "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+      "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
       "dev": true
     },
     "psl": {
@@ -18436,7 +18375,7 @@
     "q": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
-      "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
+      "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
       "dev": true
     },
     "qrious": {
@@ -18463,13 +18402,13 @@
     "querystring": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
-      "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
+      "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==",
       "dev": true
     },
     "querystring-es3": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
-      "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
+      "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==",
       "dev": true
     },
     "querystringify": {
@@ -18510,17 +18449,36 @@
       "dev": true
     },
     "raw-body": {
-      "version": "2.4.3",
-      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz",
-      "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==",
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+      "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
       "dev": true,
       "requires": {
         "bytes": "3.1.2",
-        "http-errors": "1.8.1",
+        "http-errors": "2.0.0",
         "iconv-lite": "0.4.24",
         "unpipe": "1.0.0"
       },
       "dependencies": {
+        "depd": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+          "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+          "dev": true
+        },
+        "http-errors": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+          "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+          "dev": true,
+          "requires": {
+            "depd": "2.0.0",
+            "inherits": "2.0.4",
+            "setprototypeof": "1.2.0",
+            "statuses": "2.0.1",
+            "toidentifier": "1.0.1"
+          }
+        },
         "iconv-lite": {
           "version": "0.4.24",
           "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -18529,6 +18487,12 @@
           "requires": {
             "safer-buffer": ">= 2.1.2 < 3"
           }
+        },
+        "statuses": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+          "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+          "dev": true
         }
       }
     },
@@ -18543,6 +18507,53 @@
         "strip-json-comments": "~2.0.1"
       }
     },
+    "rc-align": {
+      "version": "4.0.12",
+      "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-4.0.12.tgz",
+      "integrity": "sha512-3DuwSJp8iC/dgHzwreOQl52soj40LchlfUHtgACOUtwGuoFIOVh6n/sCpfqCU8kO5+iz6qR0YKvjgB8iPdE3aQ==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "2.x",
+        "dom-align": "^1.7.0",
+        "lodash": "^4.17.21",
+        "rc-util": "^5.3.0",
+        "resize-observer-polyfill": "^1.5.1"
+      }
+    },
+    "rc-cascader": {
+      "version": "3.6.1",
+      "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.6.1.tgz",
+      "integrity": "sha512-+GmN2Z0IybKT45t0Z94jkjmsOHGxAliobR2tzt05/Gw0AKBYLHX5bdvsVXR7abPnarYyYzZ/cWe8CoFgDjAFNw==",
+      "requires": {
+        "@babel/runtime": "^7.12.5",
+        "array-tree-filter": "^2.1.0",
+        "classnames": "^2.3.1",
+        "rc-select": "~14.1.0",
+        "rc-tree": "~5.6.3",
+        "rc-util": "^5.6.1"
+      }
+    },
+    "rc-checkbox": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.3.2.tgz",
+      "integrity": "sha512-afVi1FYiGv1U0JlpNH/UaEXdh6WUJjcWokj/nUN2TgG80bfG+MDdbfHKlLcNNba94mbjy2/SXJ1HDgrOkXGAjg==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.1"
+      }
+    },
+    "rc-collapse": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.3.1.tgz",
+      "integrity": "sha512-cOJfcSe3R8vocrF8T+PgaHDrgeA1tX+lwfhwSj60NX9QVRidsILIbRNDLD6nAzmcvVC5PWiIRiR4S1OobxdhCg==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "2.x",
+        "rc-motion": "^2.3.4",
+        "rc-util": "^5.2.1",
+        "shallowequal": "^1.1.0"
+      }
+    },
     "rc-config-loader": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-3.0.0.tgz",
@@ -18554,11 +18565,366 @@
         "require-from-string": "^2.0.2"
       }
     },
+    "rc-dialog": {
+      "version": "8.9.0",
+      "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-8.9.0.tgz",
+      "integrity": "sha512-Cp0tbJnrvPchJfnwIvOMWmJ4yjX3HWFatO6oBFD1jx8QkgsQCR0p8nUWAKdd3seLJhEC39/v56kZaEjwp9muoQ==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.6",
+        "rc-motion": "^2.3.0",
+        "rc-util": "^5.21.0"
+      }
+    },
+    "rc-drawer": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-4.4.3.tgz",
+      "integrity": "sha512-FYztwRs3uXnFOIf1hLvFxIQP9MiZJA+0w+Os8dfDh/90X7z/HqP/Yg+noLCIeHEbKln1Tqelv8ymCAN24zPcfQ==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.6",
+        "rc-util": "^5.7.0"
+      }
+    },
+    "rc-dropdown": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.0.1.tgz",
+      "integrity": "sha512-OdpXuOcme1rm45cR0Jzgfl1otzmU4vuBVb+etXM8vcaULGokAKVpKlw8p6xzspG7jGd/XxShvq+N3VNEfk/l5g==",
+      "requires": {
+        "@babel/runtime": "^7.18.3",
+        "classnames": "^2.2.6",
+        "rc-trigger": "^5.3.1",
+        "rc-util": "^5.17.0"
+      }
+    },
+    "rc-field-form": {
+      "version": "1.26.7",
+      "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.26.7.tgz",
+      "integrity": "sha512-CIb7Gw+DG9R+g4HxaDGYHhOjhjQoU2mGU4y+UM2+KQ3uRz9HrrNgTspGvNynn3UamsYcYcaPWZJmiJ6VklkT/w==",
+      "requires": {
+        "@babel/runtime": "^7.18.0",
+        "async-validator": "^4.1.0",
+        "rc-util": "^5.8.0"
+      }
+    },
+    "rc-image": {
+      "version": "5.7.0",
+      "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-5.7.0.tgz",
+      "integrity": "sha512-v6dzSgYfYrH4liKmOZKZZO+x21sJ9KPXNinBfkAoQg2Ihcd5QZ+P/JjB7v60X981XTPGjegy8U17Z8VUX4V36g==",
+      "requires": {
+        "@babel/runtime": "^7.11.2",
+        "classnames": "^2.2.6",
+        "rc-dialog": "~8.9.0",
+        "rc-util": "^5.0.6"
+      }
+    },
+    "rc-input": {
+      "version": "0.0.1-alpha.7",
+      "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-0.0.1-alpha.7.tgz",
+      "integrity": "sha512-eozaqpCYWSY5LBMwlHgC01GArkVEP+XlJ84OMvdkwUnJBSv83Yxa15pZpn7vACAj84uDC4xOA2CoFdbLuqB08Q==",
+      "requires": {
+        "@babel/runtime": "^7.11.1",
+        "classnames": "^2.2.1",
+        "rc-util": "^5.18.1"
+      }
+    },
+    "rc-input-number": {
+      "version": "7.3.4",
+      "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-7.3.4.tgz",
+      "integrity": "sha512-W9uqSzuvJUnz8H8vsVY4kx+yK51SsAxNTwr8SNH4G3XqQNocLVmKIibKFRjocnYX1RDHMND9FFbgj2h7E7nvGA==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.5",
+        "rc-util": "^5.9.8"
+      }
+    },
+    "rc-mentions": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.8.0.tgz",
+      "integrity": "sha512-ch7yfMMvx2UXy+EvE4axm0Vp6VlVZ30WLrZtLtV/Eb1ty7rQQRzNzCwAHAMyw6tNKTMs9t9sF68AVjAzQ0rvJw==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.6",
+        "rc-menu": "~9.6.0",
+        "rc-textarea": "^0.3.0",
+        "rc-trigger": "^5.0.4",
+        "rc-util": "^5.0.1"
+      }
+    },
+    "rc-menu": {
+      "version": "9.6.0",
+      "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.6.0.tgz",
+      "integrity": "sha512-d26waws42U/rVwW/+rOE2FN9pX6wUc9bDy38vVQYoie6gE85auWIpl5oChGlnW6nE2epnTwUsgWl8ipOPgmnUA==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "2.x",
+        "rc-motion": "^2.4.3",
+        "rc-overflow": "^1.2.0",
+        "rc-trigger": "^5.1.2",
+        "rc-util": "^5.12.0",
+        "shallowequal": "^1.1.0"
+      }
+    },
+    "rc-motion": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.6.0.tgz",
+      "integrity": "sha512-1MDWA9+i174CZ0SIDenSYm2Wb9YbRkrexjZWR0CUFu7D6f23E8Y0KsTgk9NGOLJsGak5ELZK/Y5lOlf5wQdzbw==",
+      "requires": {
+        "@babel/runtime": "^7.11.1",
+        "classnames": "^2.2.1",
+        "rc-util": "^5.21.0"
+      }
+    },
+    "rc-notification": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-4.6.0.tgz",
+      "integrity": "sha512-xF3MKgIoynzjQAO4lqsoraiFo3UXNYlBfpHs0VWvwF+4pimen9/H1DYLN2mfRWhHovW6gRpla73m2nmyIqAMZQ==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "2.x",
+        "rc-motion": "^2.2.0",
+        "rc-util": "^5.20.1"
+      }
+    },
+    "rc-overflow": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.2.6.tgz",
+      "integrity": "sha512-YqbocgzuQxfq2wZy72vdAgrgzzEuM/5d4gF9TBEodCpXPbUeXGrUXNm1J6G1MSkCU2N0ePIgCEu5qD/0Ldi63Q==",
+      "requires": {
+        "@babel/runtime": "^7.11.1",
+        "classnames": "^2.2.1",
+        "rc-resize-observer": "^1.0.0",
+        "rc-util": "^5.19.2"
+      }
+    },
+    "rc-pagination": {
+      "version": "3.1.17",
+      "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-3.1.17.tgz",
+      "integrity": "sha512-/BQ5UxcBnW28vFAcP2hfh+Xg15W0QZn8TWYwdCApchMH1H0CxiaUUcULP8uXcFM1TygcdKWdt3JqsL9cTAfdkQ==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.1"
+      }
+    },
+    "rc-picker": {
+      "version": "2.6.10",
+      "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.6.10.tgz",
+      "integrity": "sha512-9wYtw0DFWs9FO92Qh2D76P0iojUr8ZhLOtScUeOit6ks/F+TBLrOC1uze3IOu+u9gbDAjmosNWLKbBzx/Yuv2w==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.1",
+        "date-fns": "2.x",
+        "dayjs": "1.x",
+        "moment": "^2.24.0",
+        "rc-trigger": "^5.0.4",
+        "rc-util": "^5.4.0",
+        "shallowequal": "^1.1.0"
+      }
+    },
+    "rc-progress": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-3.3.3.tgz",
+      "integrity": "sha512-MDVNVHzGanYtRy2KKraEaWeZLri2ZHWIRyaE1a9MQ2MuJ09m+Wxj5cfcaoaR6z5iRpHpA59YeUxAlpML8N4PJw==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.6",
+        "rc-util": "^5.16.1"
+      }
+    },
+    "rc-rate": {
+      "version": "2.9.2",
+      "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.9.2.tgz",
+      "integrity": "sha512-SaiZFyN8pe0Fgphv8t3+kidlej+cq/EALkAJAc3A0w0XcPaH2L1aggM8bhe1u6GAGuQNAoFvTLjw4qLPGRKV5g==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.5",
+        "rc-util": "^5.0.1"
+      }
+    },
+    "rc-resize-observer": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.2.0.tgz",
+      "integrity": "sha512-6W+UzT3PyDM0wVCEHfoW3qTHPTvbdSgiA43buiy8PzmeMnfgnDeb9NjdimMXMl3/TcrvvWl5RRVdp+NqcR47pQ==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.1",
+        "rc-util": "^5.15.0",
+        "resize-observer-polyfill": "^1.5.1"
+      }
+    },
+    "rc-segmented": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.1.0.tgz",
+      "integrity": "sha512-hUlonro+pYoZcwrH6Vm56B2ftLfQh046hrwif/VwLIw1j3zGt52p5mREBwmeVzXnSwgnagpOpfafspzs1asjGw==",
+      "requires": {
+        "@babel/runtime": "^7.11.1",
+        "classnames": "^2.2.1",
+        "rc-motion": "^2.4.4",
+        "rc-util": "^5.17.0"
+      }
+    },
+    "rc-select": {
+      "version": "14.1.8",
+      "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.1.8.tgz",
+      "integrity": "sha512-1kU/7ZCggyR5r5jVEQfAiN6Sq3LGLD2b6FNz5GWel3TOEQZYyDn0o4FAoIRqS6Y5ldWmkFxtd834ilPnG6NV6w==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "2.x",
+        "rc-motion": "^2.0.1",
+        "rc-overflow": "^1.0.0",
+        "rc-trigger": "^5.0.4",
+        "rc-util": "^5.16.1",
+        "rc-virtual-list": "^3.2.0"
+      }
+    },
+    "rc-slider": {
+      "version": "10.0.0",
+      "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-10.0.0.tgz",
+      "integrity": "sha512-Bk54UIKWW4wyhHcL8ehAxt+wX+n69dscnHTX6Uv0FMxSke/TGrlkZz1LSIWblCpfE2zr/dwR2Ca8nZGk3U+Tbg==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.5",
+        "rc-tooltip": "^5.0.1",
+        "rc-util": "^5.18.1",
+        "shallowequal": "^1.1.0"
+      }
+    },
+    "rc-steps": {
+      "version": "4.1.4",
+      "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-4.1.4.tgz",
+      "integrity": "sha512-qoCqKZWSpkh/b03ASGx1WhpKnuZcRWmvuW+ZUu4mvMdfvFzVxblTwUM+9aBd0mlEUFmt6GW8FXhMpHkK3Uzp3w==",
+      "requires": {
+        "@babel/runtime": "^7.10.2",
+        "classnames": "^2.2.3",
+        "rc-util": "^5.0.1"
+      }
+    },
+    "rc-switch": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-3.2.2.tgz",
+      "integrity": "sha512-+gUJClsZZzvAHGy1vZfnwySxj+MjLlGRyXKXScrtCTcmiYNPzxDFOxdQ/3pK1Kt/0POvwJ/6ALOR8gwdXGhs+A==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.1",
+        "rc-util": "^5.0.1"
+      }
+    },
+    "rc-table": {
+      "version": "7.24.3",
+      "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.24.3.tgz",
+      "integrity": "sha512-3Z74jeIpQ2t0i/PQ3iSKXsl1WGT809yzq3KzIDzEB7SIA0zat+rqwI+OnrwfhJVRp7GTjeT7sJyCatXpw1YJdg==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.5",
+        "rc-resize-observer": "^1.1.0",
+        "rc-util": "^5.14.0",
+        "shallowequal": "^1.1.0"
+      }
+    },
+    "rc-tabs": {
+      "version": "11.16.0",
+      "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-11.16.0.tgz",
+      "integrity": "sha512-CIDPv3lHaXSHTJevmFP2eHoD3Hq9psfKbOZYf6D4FYPACloNGHpz44y3RGeJgataQ7omFLrGBm3dOBMUki87tA==",
+      "requires": {
+        "@babel/runtime": "^7.11.2",
+        "classnames": "2.x",
+        "rc-dropdown": "~4.0.0",
+        "rc-menu": "~9.6.0",
+        "rc-resize-observer": "^1.0.0",
+        "rc-util": "^5.5.0"
+      }
+    },
+    "rc-textarea": {
+      "version": "0.3.7",
+      "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-0.3.7.tgz",
+      "integrity": "sha512-yCdZ6binKmAQB13hc/oehh0E/QRwoPP1pjF21aHBxlgXO3RzPF6dUu4LG2R4FZ1zx/fQd2L1faktulrXOM/2rw==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "^2.2.1",
+        "rc-resize-observer": "^1.0.0",
+        "rc-util": "^5.7.0",
+        "shallowequal": "^1.1.0"
+      }
+    },
+    "rc-tooltip": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-5.1.1.tgz",
+      "integrity": "sha512-alt8eGMJulio6+4/uDm7nvV+rJq9bsfxFDCI0ljPdbuoygUscbsMYb6EQgwib/uqsXQUvzk+S7A59uYHmEgmDA==",
+      "requires": {
+        "@babel/runtime": "^7.11.2",
+        "rc-trigger": "^5.0.0"
+      }
+    },
+    "rc-tree": {
+      "version": "5.6.5",
+      "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.6.5.tgz",
+      "integrity": "sha512-Bnyen46B251APyRZ9D/jYeTnSqbSEvK2AkU5B4vWkNYgUJNPrxO+VMgcDRedP/8N7YcsgdDT9hxqVvNOq7oCAQ==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "2.x",
+        "rc-motion": "^2.0.1",
+        "rc-util": "^5.16.1",
+        "rc-virtual-list": "^3.4.8"
+      }
+    },
+    "rc-tree-select": {
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.4.0.tgz",
+      "integrity": "sha512-reRbOqC7Ic/nQocJAJeCl4n6nJUY3NoqiwRXKvhjgZJU7NGr9vIccXEsY+Lghkw5UMpPoxGsIJB0jiAvM18XYA==",
+      "requires": {
+        "@babel/runtime": "^7.10.1",
+        "classnames": "2.x",
+        "rc-select": "~14.1.0",
+        "rc-tree": "~5.6.1",
+        "rc-util": "^5.16.1"
+      }
+    },
+    "rc-trigger": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.3.1.tgz",
+      "integrity": "sha512-5gaFbDkYSefZ14j2AdzucXzlWgU2ri5uEjkHvsf1ynRhdJbKxNOnw4PBZ9+FVULNGFiDzzlVF8RJnR9P/xrnKQ==",
+      "requires": {
+        "@babel/runtime": "^7.18.3",
+        "classnames": "^2.2.6",
+        "rc-align": "^4.0.0",
+        "rc-motion": "^2.0.0",
+        "rc-util": "^5.19.2"
+      }
+    },
+    "rc-upload": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.3.4.tgz",
+      "integrity": "sha512-uVbtHFGNjHG/RyAfm9fluXB6pvArAGyAx8z7XzXXyorEgVIWj6mOlriuDm0XowDHYz4ycNK0nE0oP3cbFnzxiQ==",
+      "requires": {
+        "@babel/runtime": "^7.18.3",
+        "classnames": "^2.2.5",
+        "rc-util": "^5.2.0"
+      }
+    },
+    "rc-util": {
+      "version": "5.22.5",
+      "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.22.5.tgz",
+      "integrity": "sha512-awD2TGMGU97OZftT2R3JwrHWjR8k/xIwqjwcivPskciweUdgXE7QsyXkBKVSBHXS+c17AWWMDWuKWsJSheQy8g==",
+      "requires": {
+        "@babel/runtime": "^7.18.3",
+        "react-is": "^16.12.0",
+        "shallowequal": "^1.1.0"
+      }
+    },
+    "rc-virtual-list": {
+      "version": "3.4.8",
+      "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.4.8.tgz",
+      "integrity": "sha512-qSN+Rv4i/E7RCTvTMr1uZo7f3crJJg/5DekoCagydo9zsXrxj07zsFSxqizqW+ldGA16lwa8So/bIbV9Ofjddg==",
+      "requires": {
+        "classnames": "^2.2.6",
+        "rc-resize-observer": "^1.0.0",
+        "rc-util": "^5.15.0"
+      }
+    },
     "react-is": {
       "version": "16.13.1",
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
-      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
-      "dev": true
+      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
     },
     "read-package-json-fast": {
       "version": "2.0.3",
@@ -18630,13 +18996,13 @@
         "path-exists": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
           "dev": true
         },
         "read-pkg": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
-          "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
+          "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==",
           "dev": true,
           "requires": {
             "load-json-file": "^4.0.0",
@@ -18690,42 +19056,6 @@
         "source-map": "~0.6.1"
       }
     },
-    "redent": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
-      "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
-      "dev": true,
-      "requires": {
-        "indent-string": "^2.1.0",
-        "strip-indent": "^1.0.1"
-      },
-      "dependencies": {
-        "get-stdin": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
-          "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
-          "dev": true
-        },
-        "indent-string": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
-          "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
-          "dev": true,
-          "requires": {
-            "repeating": "^2.0.0"
-          }
-        },
-        "strip-indent": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
-          "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
-          "dev": true,
-          "requires": {
-            "get-stdin": "^4.0.1"
-          }
-        }
-      }
-    },
     "regenerate": {
       "version": "1.4.2",
       "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -18747,9 +19077,9 @@
       "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
     },
     "regenerator-transform": {
-      "version": "0.14.5",
-      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz",
-      "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==",
+      "version": "0.15.0",
+      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz",
+      "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==",
       "dev": true,
       "requires": {
         "@babel/runtime": "^7.8.4"
@@ -18766,13 +19096,14 @@
       }
     },
     "regexp.prototype.flags": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz",
-      "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==",
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
+      "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
       "dev": true,
       "requires": {
         "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3"
+        "define-properties": "^1.1.3",
+        "functions-have-names": "^1.2.2"
       }
     },
     "regexpp": {
@@ -18782,9 +19113,9 @@
       "dev": true
     },
     "regexpu-core": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz",
-      "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.1.0.tgz",
+      "integrity": "sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA==",
       "dev": true,
       "requires": {
         "regenerate": "^1.4.2",
@@ -18796,11 +19127,11 @@
       }
     },
     "registry-auth-token": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz",
-      "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==",
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz",
+      "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==",
       "requires": {
-        "rc": "^1.2.8"
+        "rc": "1.2.8"
       }
     },
     "registry-url": {
@@ -18829,7 +19160,7 @@
         "jsesc": {
           "version": "0.5.0",
           "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
-          "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
+          "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
           "dev": true
         }
       }
@@ -18837,13 +19168,13 @@
     "relateurl": {
       "version": "0.2.7",
       "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
-      "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=",
+      "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==",
       "dev": true
     },
     "remove-trailing-separator": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
-      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+      "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==",
       "dev": true
     },
     "renderkid": {
@@ -18860,28 +19191,28 @@
       },
       "dependencies": {
         "css-select": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz",
-          "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==",
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
+          "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
           "dev": true,
           "requires": {
             "boolbase": "^1.0.0",
-            "css-what": "^5.1.0",
-            "domhandler": "^4.3.0",
+            "css-what": "^6.0.1",
+            "domhandler": "^4.3.1",
             "domutils": "^2.8.0",
             "nth-check": "^2.0.1"
           }
         },
         "css-what": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz",
-          "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==",
+          "version": "6.1.0",
+          "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+          "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
           "dev": true
         },
         "dom-serializer": {
-          "version": "1.3.2",
-          "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
-          "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==",
+          "version": "1.4.1",
+          "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+          "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
           "dev": true,
           "requires": {
             "domelementtype": "^2.0.1",
@@ -18890,9 +19221,9 @@
           }
         },
         "domelementtype": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
-          "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
+          "version": "2.3.0",
+          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+          "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
           "dev": true
         },
         "domutils": {
@@ -18907,9 +19238,9 @@
           }
         },
         "nth-check": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
-          "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+          "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
           "dev": true,
           "requires": {
             "boolbase": "^1.0.0"
@@ -18926,18 +19257,9 @@
     "repeat-string": {
       "version": "1.6.1",
       "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
-      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+      "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==",
       "dev": true
     },
-    "repeating": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
-      "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
-      "dev": true,
-      "requires": {
-        "is-finite": "^1.0.0"
-      }
-    },
     "request": {
       "version": "2.88.2",
       "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
@@ -18988,7 +19310,7 @@
     "require-directory": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
       "dev": true
     },
     "require-from-string": {
@@ -19015,7 +19337,7 @@
     "requires-port": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
-      "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+      "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
       "dev": true
     },
     "resize-observer-polyfill": {
@@ -19034,7 +19356,7 @@
     "resolve-cwd": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
-      "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=",
+      "integrity": "sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg==",
       "dev": true,
       "requires": {
         "resolve-from": "^3.0.0"
@@ -19043,19 +19365,19 @@
     "resolve-from": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
-      "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
+      "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==",
       "dev": true
     },
     "resolve-url": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
-      "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+      "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==",
       "dev": true
     },
     "responselike": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
-      "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=",
+      "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==",
       "requires": {
         "lowercase-keys": "^1.0.0"
       }
@@ -19063,7 +19385,7 @@
     "restore-cursor": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
-      "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+      "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==",
       "dev": true,
       "requires": {
         "onetime": "^2.0.0",
@@ -19079,7 +19401,7 @@
     "retry": {
       "version": "0.12.0",
       "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
-      "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs="
+      "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="
     },
     "reusify": {
       "version": "1.0.4",
@@ -19090,13 +19412,13 @@
     "rgb-regex": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
-      "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=",
+      "integrity": "sha512-gDK5mkALDFER2YLqH6imYvK6g02gpNGM4ILDZ472EwWfXZnC2ZEpoB2ECXTyOVUKuk/bPJZMzwQPBYICzP+D3w==",
       "dev": true
     },
     "rgba-regex": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz",
-      "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=",
+      "integrity": "sha512-zgn5OjNQXLUTdq8m17KdaicF6w89TZs8ZU8y0AYENIU6wG8GG6LLm0yLSiPY8DmaYmHdgRW8rnApjoT0fQRfMg==",
       "dev": true
     },
     "rimraf": {
@@ -19151,7 +19473,7 @@
     "run-queue": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
-      "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=",
+      "integrity": "sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==",
       "dev": true,
       "requires": {
         "aproba": "^1.1.1"
@@ -19174,7 +19496,7 @@
     "safe-regex": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
-      "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+      "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==",
       "dev": true,
       "requires": {
         "ret": "~0.1.10"
@@ -19231,7 +19553,7 @@
         "normalize-path": {
           "version": "2.1.1",
           "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
-          "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+          "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
           "dev": true,
           "requires": {
             "remove-trailing-separator": "^1.0.1"
@@ -19240,9 +19562,9 @@
       }
     },
     "sass": {
-      "version": "1.49.9",
-      "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.9.tgz",
-      "integrity": "sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==",
+      "version": "1.53.0",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.53.0.tgz",
+      "integrity": "sha512-zb/oMirbKhUgRQ0/GFz8TSAwRq2IlR29vOUJZOx0l8sV+CkHUfHa4u5nqrG+1VceZp7Jfj59SVW9ogdhTvJDcQ==",
       "dev": true,
       "requires": {
         "chokidar": ">=3.0.0 <4.0.0",
@@ -19250,172 +19572,6 @@
         "source-map-js": ">=0.6.2 <2.0.0"
       }
     },
-    "sass-graph": {
-      "version": "2.2.5",
-      "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz",
-      "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==",
-      "dev": true,
-      "requires": {
-        "glob": "^7.0.0",
-        "lodash": "^4.0.0",
-        "scss-tokenizer": "^0.2.3",
-        "yargs": "^13.3.2"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
-          "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
-          "dev": true
-        },
-        "ansi-styles": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^1.9.0"
-          }
-        },
-        "cliui": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
-          "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
-          "dev": true,
-          "requires": {
-            "string-width": "^3.1.0",
-            "strip-ansi": "^5.2.0",
-            "wrap-ansi": "^5.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "1.9.3",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-          "dev": true,
-          "requires": {
-            "color-name": "1.1.3"
-          }
-        },
-        "color-name": {
-          "version": "1.1.3",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-          "dev": true
-        },
-        "emoji-regex": {
-          "version": "7.0.3",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-          "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
-          "dev": true
-        },
-        "find-up": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
-          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^3.0.0"
-          }
-        },
-        "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
-        },
-        "locate-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
-          "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^3.0.0",
-            "path-exists": "^3.0.0"
-          }
-        },
-        "p-locate": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
-          "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.0.0"
-          }
-        },
-        "path-exists": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
-          "dev": true
-        },
-        "string-width": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^7.0.1",
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^5.1.0"
-          }
-        },
-        "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,
-          "requires": {
-            "ansi-regex": "^4.1.0"
-          }
-        },
-        "wrap-ansi": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
-          "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.0",
-            "string-width": "^3.0.0",
-            "strip-ansi": "^5.0.0"
-          }
-        },
-        "y18n": {
-          "version": "4.0.3",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
-          "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
-          "dev": true
-        },
-        "yargs": {
-          "version": "13.3.2",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
-          "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
-          "dev": true,
-          "requires": {
-            "cliui": "^5.0.0",
-            "find-up": "^3.0.0",
-            "get-caller-file": "^2.0.1",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^2.0.0",
-            "set-blocking": "^2.0.0",
-            "string-width": "^3.0.0",
-            "which-module": "^2.0.0",
-            "y18n": "^4.0.0",
-            "yargs-parser": "^13.1.2"
-          }
-        },
-        "yargs-parser": {
-          "version": "13.1.2",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
-          "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
-          "dev": true,
-          "requires": {
-            "camelcase": "^5.0.0",
-            "decamelize": "^1.2.0"
-          }
-        }
-      }
-    },
     "sass-loader": {
       "version": "8.0.2",
       "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.2.tgz",
@@ -19491,31 +19647,10 @@
         "compute-scroll-into-view": "^1.0.17"
       }
     },
-    "scss-tokenizer": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
-      "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=",
-      "dev": true,
-      "requires": {
-        "js-base64": "^2.1.8",
-        "source-map": "^0.4.2"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.4.4",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
-          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
-          "dev": true,
-          "requires": {
-            "amdefine": ">=0.0.4"
-          }
-        }
-      }
-    },
     "sec": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/sec/-/sec-1.0.0.tgz",
-      "integrity": "sha1-Az1go60g7PLgCUDRT5eCNGV3QzU=",
+      "integrity": "sha512-rVnXtdy9keLxyssT6xung9WwtdB+kha3De93w50RNzwOslyLaDGhqoOqrh4InPoOhhqUZ4JOnovGd3BvLZ+f7A==",
       "dev": true
     },
     "seek-bzip": {
@@ -19538,12 +19673,12 @@
     "select": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
-      "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0="
+      "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA=="
     },
     "select-hose": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
-      "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=",
+      "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==",
       "dev": true
     },
     "selfsigned": {
@@ -19556,9 +19691,9 @@
       }
     },
     "semver": {
-      "version": "7.3.5",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
-      "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+      "version": "7.3.7",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
       "requires": {
         "lru-cache": "^6.0.0"
       }
@@ -19584,24 +19719,24 @@
       "integrity": "sha512-EjnoLE5OGmDAVV/8YDoN5KiajNadjzIp9BAHOhYeQHt7j0UWxjmgsx4YD48wp4Ue1Qogq38F1GNUJNqF1kKKxA=="
     },
     "send": {
-      "version": "0.17.2",
-      "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz",
-      "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==",
+      "version": "0.18.0",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+      "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
       "dev": true,
       "requires": {
         "debug": "2.6.9",
-        "depd": "~1.1.2",
-        "destroy": "~1.0.4",
+        "depd": "2.0.0",
+        "destroy": "1.2.0",
         "encodeurl": "~1.0.2",
         "escape-html": "~1.0.3",
         "etag": "~1.8.1",
         "fresh": "0.5.2",
-        "http-errors": "1.8.1",
+        "http-errors": "2.0.0",
         "mime": "1.6.0",
         "ms": "2.1.3",
-        "on-finished": "~2.3.0",
+        "on-finished": "2.4.1",
         "range-parser": "~1.2.1",
-        "statuses": "~1.5.0"
+        "statuses": "2.0.1"
       },
       "dependencies": {
         "debug": {
@@ -19616,16 +19751,41 @@
             "ms": {
               "version": "2.0.0",
               "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+              "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
               "dev": true
             }
           }
         },
+        "depd": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+          "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+          "dev": true
+        },
+        "http-errors": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+          "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+          "dev": true,
+          "requires": {
+            "depd": "2.0.0",
+            "inherits": "2.0.4",
+            "setprototypeof": "1.2.0",
+            "statuses": "2.0.1",
+            "toidentifier": "1.0.1"
+          }
+        },
         "ms": {
           "version": "2.1.3",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
           "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
           "dev": true
+        },
+        "statuses": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+          "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+          "dev": true
         }
       }
     },
@@ -19641,7 +19801,7 @@
     "serve-index": {
       "version": "1.9.1",
       "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
-      "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
+      "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==",
       "dev": true,
       "requires": {
         "accepts": "~1.3.4",
@@ -19665,7 +19825,7 @@
         "http-errors": {
           "version": "1.6.3",
           "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
-          "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
+          "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==",
           "dev": true,
           "requires": {
             "depd": "~1.1.2",
@@ -19677,13 +19837,13 @@
         "inherits": {
           "version": "2.0.3",
           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+          "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
           "dev": true
         },
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         },
         "setprototypeof": {
@@ -19695,21 +19855,21 @@
       }
     },
     "serve-static": {
-      "version": "1.14.2",
-      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz",
-      "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==",
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+      "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
       "dev": true,
       "requires": {
         "encodeurl": "~1.0.2",
         "escape-html": "~1.0.3",
         "parseurl": "~1.3.3",
-        "send": "0.17.2"
+        "send": "0.18.0"
       }
     },
     "set-blocking": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
     },
     "set-value": {
       "version": "2.0.1",
@@ -19726,7 +19886,7 @@
         "extend-shallow": {
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
           "dev": true,
           "requires": {
             "is-extendable": "^0.1.0"
@@ -19746,7 +19906,7 @@
     "setimmediate": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
-      "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
+      "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
       "dev": true
     },
     "setprototypeof": {
@@ -19779,10 +19939,15 @@
       "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz",
       "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA=="
     },
+    "shallowequal": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
+      "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
+    },
     "shebang-command": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
-      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
       "dev": true,
       "requires": {
         "shebang-regex": "^1.0.0"
@@ -19791,7 +19956,7 @@
     "shebang-regex": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
-      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+      "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
       "dev": true
     },
     "shell-quote": {
@@ -19837,7 +20002,7 @@
     "sigmund": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
-      "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=",
+      "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==",
       "dev": true
     },
     "signal-exit": {
@@ -19848,7 +20013,7 @@
     "simple-swizzle": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
-      "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
+      "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
       "dev": true,
       "requires": {
         "is-arrayish": "^0.3.1"
@@ -19905,13 +20070,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "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=",
+          "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
           "dev": true
         }
       }
@@ -19949,7 +20114,7 @@
         "define-property": {
           "version": "0.2.5",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
           "dev": true,
           "requires": {
             "is-descriptor": "^0.1.0"
@@ -19958,7 +20123,7 @@
         "extend-shallow": {
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
           "dev": true,
           "requires": {
             "is-extendable": "^0.1.0"
@@ -19967,13 +20132,13 @@
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         },
         "source-map": {
           "version": "0.5.7",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
           "dev": true
         }
       }
@@ -19992,7 +20157,7 @@
         "define-property": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==",
           "dev": true,
           "requires": {
             "is-descriptor": "^1.0.0"
@@ -20041,7 +20206,7 @@
         "kind-of": {
           "version": "3.2.2",
           "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
           "dev": true,
           "requires": {
             "is-buffer": "^1.1.5"
@@ -20069,13 +20234,13 @@
       }
     },
     "sockjs-client": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.6.0.tgz",
-      "integrity": "sha512-qVHJlyfdHFht3eBFZdKEXKTlb7I4IV41xnVNo8yUKA1UHcPJwgW2SvTq9LhnjjCywSkSK7c/e4nghU0GOoMCRQ==",
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.6.1.tgz",
+      "integrity": "sha512-2g0tjOR+fRs0amxENLi/q5TiJTqY+WXFOzb5UwXndlK6TO3U/mirZznpx6w34HVMoc3g7cY24yC/ZMIYnDlfkw==",
       "dev": true,
       "requires": {
         "debug": "^3.2.7",
-        "eventsource": "^1.1.0",
+        "eventsource": "^2.0.2",
         "faye-websocket": "^0.11.4",
         "inherits": "^2.0.4",
         "url-parse": "^1.5.10"
@@ -20102,19 +20267,19 @@
       }
     },
     "socks-proxy-agent": {
-      "version": "6.1.1",
-      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz",
-      "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==",
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz",
+      "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==",
       "requires": {
         "agent-base": "^6.0.2",
-        "debug": "^4.3.1",
-        "socks": "^2.6.1"
+        "debug": "^4.3.3",
+        "socks": "^2.6.2"
       }
     },
     "sort-keys": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
-      "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
+      "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==",
       "dev": true,
       "requires": {
         "is-plain-obj": "^1.0.0"
@@ -20123,7 +20288,7 @@
     "sort-keys-length": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz",
-      "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=",
+      "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==",
       "dev": true,
       "requires": {
         "sort-keys": "^1.0.0"
@@ -20186,7 +20351,7 @@
     "spawn-please": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/spawn-please/-/spawn-please-0.3.0.tgz",
-      "integrity": "sha1-2zOOxM/2Orxp8dDgjO6euL69nRE="
+      "integrity": "sha512-gf9GJwAWhW0gnQp0dGui+nhIVICx1lGM1Ox95HzfaDBOQTauqlvHFLpo4vtAB3E377SA0YMIyRCh1w0S6R5m2w=="
     },
     "spdx-correct": {
       "version": "3.1.1",
@@ -20281,7 +20446,7 @@
     "sprintf-js": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+      "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
     },
     "sshpk": {
       "version": "1.17.0",
@@ -20331,15 +20496,15 @@
       }
     },
     "stackframe": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.1.tgz",
-      "integrity": "sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg==",
+      "version": "1.3.4",
+      "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
+      "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==",
       "dev": true
     },
     "static-extend": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
-      "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+      "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==",
       "dev": true,
       "requires": {
         "define-property": "^0.2.5",
@@ -20349,7 +20514,7 @@
         "define-property": {
           "version": "0.2.5",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==",
           "dev": true,
           "requires": {
             "is-descriptor": "^0.1.0"
@@ -20360,28 +20525,19 @@
     "statuses": {
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
-      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+      "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
       "dev": true
     },
-    "stdout-stream": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz",
-      "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==",
-      "dev": true,
-      "requires": {
-        "readable-stream": "^2.0.1"
-      }
-    },
     "stealthy-require": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
-      "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
+      "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==",
       "dev": true
     },
     "steno": {
       "version": "0.4.4",
       "resolved": "https://registry.npmjs.org/steno/-/steno-0.4.4.tgz",
-      "integrity": "sha1-BxEFvfwobmYVwEA8J+nXtdy4Vcs=",
+      "integrity": "sha512-EEHMVYHNXFHfGtgjNITnka0aHhiAlo93F7z2/Pwd+g0teG9CnM3JIINM7hVVB5/rhw9voufD7Wukwgtw2uqh6w==",
       "dev": true,
       "requires": {
         "graceful-fs": "^4.1.3"
@@ -20429,19 +20585,24 @@
     "streamsearch": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
-      "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=",
+      "integrity": "sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==",
       "dev": true
     },
     "strict-uri-encode": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
-      "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
+      "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==",
       "dev": true
     },
+    "string-convert": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz",
+      "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A=="
+    },
     "string-length": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz",
-      "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=",
+      "integrity": "sha512-Qka42GGrS8Mm3SZ+7cH8UXiIWI867/b/Z/feQSpQx/rbfB8UGknGEZVaUQMOUVj+soY6NpWAxily63HI1OckVQ==",
       "dev": true,
       "requires": {
         "astral-regex": "^1.0.0",
@@ -20449,15 +20610,15 @@
       },
       "dependencies": {
         "ansi-regex": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
+          "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
           "dev": true
         },
         "strip-ansi": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==",
           "dev": true,
           "requires": {
             "ansi-regex": "^3.0.0"
@@ -20468,7 +20629,7 @@
     "string-width": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+      "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==",
       "requires": {
         "code-point-at": "^1.0.0",
         "is-fullwidth-code-point": "^1.0.0",
@@ -20476,23 +20637,25 @@
       }
     },
     "string.prototype.trimend": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
-      "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
+      "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==",
       "dev": true,
       "requires": {
         "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3"
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.19.5"
       }
     },
     "string.prototype.trimstart": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
-      "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz",
+      "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==",
       "dev": true,
       "requires": {
         "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3"
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.19.5"
       }
     },
     "string_decoder": {
@@ -20506,7 +20669,7 @@
     "strip-ansi": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
-      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+      "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
       "requires": {
         "ansi-regex": "^2.0.0"
       }
@@ -20514,7 +20677,7 @@
     "strip-bom": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-      "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+      "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
       "dev": true
     },
     "strip-dirs": {
@@ -20529,7 +20692,7 @@
     "strip-eof": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
-      "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
+      "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==",
       "dev": true
     },
     "strip-final-newline": {
@@ -20541,13 +20704,13 @@
     "strip-indent": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz",
-      "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=",
+      "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==",
       "dev": true
     },
     "strip-json-comments": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
-      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+      "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="
     },
     "strip-outer": {
       "version": "1.0.1",
@@ -20612,7 +20775,7 @@
     "svg-tags": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
-      "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=",
+      "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==",
       "dev": true
     },
     "svgo": {
@@ -20668,13 +20831,13 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "mkdirp": {
@@ -20748,7 +20911,7 @@
         "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=",
+          "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
           "dev": true
         },
         "string-width": {
@@ -20928,7 +21091,7 @@
         "pify": {
           "version": "2.3.0",
           "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+          "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
           "dev": true
         }
       }
@@ -21033,12 +21196,12 @@
           }
         },
         "mkdirp": {
-          "version": "0.5.5",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
-          "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+          "version": "0.5.6",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+          "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
           "dev": true,
           "requires": {
-            "minimist": "^1.2.5"
+            "minimist": "^1.2.6"
           }
         },
         "rimraf": {
@@ -21109,7 +21272,7 @@
     "text-table": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
       "dev": true
     },
     "thenify": {
@@ -21124,7 +21287,7 @@
     "thenify-all": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
-      "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
+      "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
       "dev": true,
       "requires": {
         "thenify": ">= 3.1.0 < 4"
@@ -21166,13 +21329,13 @@
     "throat": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz",
-      "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=",
+      "integrity": "sha512-wCVxLDcFxw7ujDxaeJC6nfl2XfHJNYs8yUYJnvMgtPEFlttP9tHSfRUv2vBe6C4hkVFPWoP1P6ZccbYjmSEkKA==",
       "dev": true
     },
     "through": {
       "version": "2.3.8",
       "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
-      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+      "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
       "dev": true
     },
     "through2": {
@@ -21194,7 +21357,7 @@
     "timed-out": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
-      "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=",
+      "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==",
       "dev": true
     },
     "timers-browserify": {
@@ -21209,7 +21372,7 @@
     "timsort": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
-      "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
+      "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==",
       "dev": true
     },
     "tiny-emitter": {
@@ -21235,7 +21398,7 @@
     "to-arraybuffer": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
-      "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
+      "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==",
       "dev": true
     },
     "to-buffer": {
@@ -21247,13 +21410,13 @@
     "to-fast-properties": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
-      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
+      "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
       "dev": true
     },
     "to-object-path": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
-      "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+      "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==",
       "dev": true,
       "requires": {
         "kind-of": "^3.0.2"
@@ -21262,7 +21425,7 @@
         "kind-of": {
           "version": "3.2.2",
           "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==",
           "dev": true,
           "requires": {
             "is-buffer": "^1.1.5"
@@ -21290,13 +21453,18 @@
     "to-regex-range": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
-      "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+      "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==",
       "dev": true,
       "requires": {
         "is-number": "^3.0.0",
         "repeat-string": "^1.6.1"
       }
     },
+    "toggle-selection": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
+      "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
+    },
     "toidentifier": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@@ -21306,7 +21474,7 @@
     "toposort": {
       "version": "1.0.7",
       "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz",
-      "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=",
+      "integrity": "sha512-FclLrw8b9bMWf4QlCJuHBEVhSRsqDj6u3nIjAzPeJvgl//1hBlffdlk0MALceL14+koWEdU4ofRAXofbODxQzg==",
       "dev": true
     },
     "tough-cookie": {
@@ -21321,33 +21489,18 @@
     "tr46": {
       "version": "0.0.3",
       "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
-      "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
-      "dev": true
-    },
-    "trim-newlines": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
-      "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
       "dev": true
     },
     "trim-repeated": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
-      "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
+      "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==",
       "dev": true,
       "requires": {
         "escape-string-regexp": "^1.0.2"
       }
     },
-    "true-case-path": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
-      "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==",
-      "dev": true,
-      "requires": {
-        "glob": "^7.1.2"
-      }
-    },
     "tryer": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
@@ -21384,7 +21537,7 @@
         "camelcase": {
           "version": "4.1.0",
           "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
-          "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
+          "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==",
           "dev": true
         },
         "mkdirp": {
@@ -21463,13 +21616,13 @@
     "tty-browserify": {
       "version": "0.0.0",
       "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
-      "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
+      "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==",
       "dev": true
     },
     "tunnel-agent": {
       "version": "0.6.0",
       "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
-      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
       "requires": {
         "safe-buffer": "^5.0.1"
       }
@@ -21477,12 +21630,12 @@
     "tweetnacl": {
       "version": "0.14.5",
       "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
-      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+      "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
     },
     "type-check": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
-      "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+      "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
       "dev": true,
       "requires": {
         "prelude-ls": "~1.1.2"
@@ -21506,7 +21659,7 @@
     "typedarray": {
       "version": "0.0.6",
       "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
-      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+      "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
       "dev": true
     },
     "typedarray-to-buffer": {
@@ -21641,9 +21794,9 @@
           }
         },
         "uglify-js": {
-          "version": "3.15.3",
-          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.3.tgz",
-          "integrity": "sha512-6iCVm2omGJbsu3JWac+p6kUiOpg3wFO2f8lIXjfEb8RrmLjzog1wTPMmwKB7swfzzqxj9YM+sGUM++u1qN4qJg==",
+          "version": "3.16.1",
+          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.1.tgz",
+          "integrity": "sha512-X5BGTIDH8U6IQ1TIRP62YC36k+ULAa1d59BxlWvPUJ1NkW5L3FwcGfEzuVvGmhJFBu0YJ5Ge25tmRISqCmLiRQ==",
           "dev": true
         },
         "webpack-sources": {
@@ -21671,14 +21824,14 @@
       }
     },
     "unbox-primitive": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
-      "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
+      "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
       "dev": true,
       "requires": {
-        "function-bind": "^1.1.1",
-        "has-bigints": "^1.0.1",
-        "has-symbols": "^1.0.2",
+        "call-bind": "^1.0.2",
+        "has-bigints": "^1.0.2",
+        "has-symbols": "^1.0.3",
         "which-boxed-primitive": "^1.0.2"
       }
     },
@@ -21735,13 +21888,13 @@
     "uniq": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
-      "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
+      "integrity": "sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==",
       "dev": true
     },
     "uniqs": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz",
-      "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=",
+      "integrity": "sha512-mZdDpf3vBV5Efh29kMw5tXoup/buMgxLzOt/XKFKcVmi+15ManNQWr6HfZ2aiZTYlYixbdNJ0KFmIZIv52tHSQ==",
       "dev": true
     },
     "unique-filename": {
@@ -21777,19 +21930,19 @@
     "unpipe": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
-      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+      "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
       "dev": true
     },
     "unquote": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz",
-      "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=",
+      "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==",
       "dev": true
     },
     "unset-value": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
-      "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+      "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==",
       "dev": true,
       "requires": {
         "has-value": "^0.3.1",
@@ -21799,7 +21952,7 @@
         "has-value": {
           "version": "0.3.1",
           "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
-          "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+          "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==",
           "dev": true,
           "requires": {
             "get-value": "^2.0.3",
@@ -21810,7 +21963,7 @@
             "isobject": {
               "version": "2.1.0",
               "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
-              "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+              "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==",
               "dev": true,
               "requires": {
                 "isarray": "1.0.0"
@@ -21821,7 +21974,7 @@
         "has-values": {
           "version": "0.1.4",
           "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
-          "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+          "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==",
           "dev": true
         }
       }
@@ -21832,6 +21985,24 @@
       "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
       "dev": true
     },
+    "update-browserslist-db": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz",
+      "integrity": "sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==",
+      "dev": true,
+      "requires": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      },
+      "dependencies": {
+        "picocolors": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+          "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+          "dev": true
+        }
+      }
+    },
     "update-notifier": {
       "version": "4.1.3",
       "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz",
@@ -21866,7 +22037,7 @@
     "upper-case": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
-      "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=",
+      "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==",
       "dev": true
     },
     "uri-js": {
@@ -21880,13 +22051,13 @@
     "urix": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
-      "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+      "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==",
       "dev": true
     },
     "url": {
       "version": "0.11.0",
       "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
-      "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+      "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==",
       "dev": true,
       "requires": {
         "punycode": "1.3.2",
@@ -21896,7 +22067,7 @@
         "punycode": {
           "version": "1.3.2",
           "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
-          "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
+          "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==",
           "dev": true
         }
       }
@@ -21953,7 +22124,7 @@
     "url-parse-lax": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
-      "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=",
+      "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==",
       "requires": {
         "prepend-http": "^2.0.0"
       }
@@ -21961,7 +22132,7 @@
     "url-to-options": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz",
-      "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=",
+      "integrity": "sha512-0kQLIzG4fdk/G5NONku64rSH/x32NOA39LVQqlK8Le6lvTF6GGRJpqaQFGgU+CLwySIqBSMdwYM0sYcW9f6P4A==",
       "dev": true
     },
     "use": {
@@ -21982,7 +22153,7 @@
         "inherits": {
           "version": "2.0.3",
           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+          "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
           "dev": true
         }
       }
@@ -21990,7 +22161,7 @@
     "util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
     },
     "util.promisify": {
       "version": "1.1.1",
@@ -22008,13 +22179,13 @@
     "utila": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz",
-      "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=",
+      "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==",
       "dev": true
     },
     "utils-merge": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
-      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+      "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
       "dev": true
     },
     "uuid": {
@@ -22041,7 +22212,7 @@
     "validate-npm-package-name": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz",
-      "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=",
+      "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==",
       "requires": {
         "builtins": "^1.0.3"
       }
@@ -22049,7 +22220,7 @@
     "vary": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
-      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+      "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
       "dev": true
     },
     "vendors": {
@@ -22061,7 +22232,7 @@
     "verror": {
       "version": "1.10.0",
       "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
-      "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+      "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
       "requires": {
         "assert-plus": "^1.0.0",
         "core-util-is": "1.0.2",
@@ -22071,7 +22242,7 @@
         "core-util-is": {
           "version": "1.0.2",
           "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
-          "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+          "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
         }
       }
     },
@@ -22082,15 +22253,15 @@
       "dev": true
     },
     "vue": {
-      "version": "3.2.31",
-      "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.31.tgz",
-      "integrity": "sha512-odT3W2tcffTiQCy57nOT93INw1auq5lYLLYtWpPYQQYQOOdHiqFct9Xhna6GJ+pJQaF67yZABraH47oywkJgFw==",
+      "version": "3.2.37",
+      "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.37.tgz",
+      "integrity": "sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==",
       "requires": {
-        "@vue/compiler-dom": "3.2.31",
-        "@vue/compiler-sfc": "3.2.31",
-        "@vue/runtime-dom": "3.2.31",
-        "@vue/server-renderer": "3.2.31",
-        "@vue/shared": "3.2.31"
+        "@vue/compiler-dom": "3.2.37",
+        "@vue/compiler-sfc": "3.2.37",
+        "@vue/runtime-dom": "3.2.37",
+        "@vue/server-renderer": "3.2.37",
+        "@vue/shared": "3.2.37"
       }
     },
     "vue-chartjs": {
@@ -22215,13 +22386,13 @@
           "dev": true
         },
         "micromatch": {
-          "version": "4.0.4",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
-          "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
+          "version": "4.0.5",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+          "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
           "dev": true,
           "requires": {
-            "braces": "^3.0.1",
-            "picomatch": "^2.2.3"
+            "braces": "^3.0.2",
+            "picomatch": "^2.3.1"
           }
         },
         "path-type": {
@@ -22286,14 +22457,63 @@
       "dev": true
     },
     "vue-i18n": {
-      "version": "9.1.9",
-      "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.9.tgz",
-      "integrity": "sha512-JeRdNVxS2OGp1E+pye5XB6+M6BBkHwAv9C80Q7+kzoMdUDGRna06tjC0vCB/jDX9aWrl5swxOMFcyAr7or8XTA==",
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.2.2.tgz",
+      "integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==",
       "requires": {
-        "@intlify/core-base": "9.1.9",
-        "@intlify/shared": "9.1.9",
-        "@intlify/vue-devtools": "9.1.9",
-        "@vue/devtools-api": "^6.0.0-beta.7"
+        "@intlify/core-base": "9.2.2",
+        "@intlify/shared": "9.2.2",
+        "@intlify/vue-devtools": "9.2.2",
+        "@vue/devtools-api": "^6.2.1"
+      },
+      "dependencies": {
+        "@intlify/core-base": {
+          "version": "9.2.2",
+          "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.2.2.tgz",
+          "integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==",
+          "requires": {
+            "@intlify/devtools-if": "9.2.2",
+            "@intlify/message-compiler": "9.2.2",
+            "@intlify/shared": "9.2.2",
+            "@intlify/vue-devtools": "9.2.2"
+          }
+        },
+        "@intlify/devtools-if": {
+          "version": "9.2.2",
+          "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.2.2.tgz",
+          "integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==",
+          "requires": {
+            "@intlify/shared": "9.2.2"
+          }
+        },
+        "@intlify/message-compiler": {
+          "version": "9.2.2",
+          "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.2.2.tgz",
+          "integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==",
+          "requires": {
+            "@intlify/shared": "9.2.2",
+            "source-map": "0.6.1"
+          }
+        },
+        "@intlify/shared": {
+          "version": "9.2.2",
+          "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz",
+          "integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q=="
+        },
+        "@intlify/vue-devtools": {
+          "version": "9.2.2",
+          "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz",
+          "integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==",
+          "requires": {
+            "@intlify/core-base": "9.2.2",
+            "@intlify/shared": "9.2.2"
+          }
+        },
+        "@vue/devtools-api": {
+          "version": "6.5.0",
+          "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz",
+          "integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q=="
+        }
       }
     },
     "vue-jest": {
@@ -22342,19 +22562,19 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "source-map": {
           "version": "0.5.6",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
-          "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=",
+          "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==",
           "dev": true
         },
         "supports-color": {
@@ -22394,9 +22614,9 @@
       }
     },
     "vue-router": {
-      "version": "4.0.14",
-      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.14.tgz",
-      "integrity": "sha512-wAO6zF9zxA3u+7AkMPqw9LjoUCjSxfFvINQj3E/DceTt6uEz1XZLraDhdg2EYmvVwTBSGlLYsUw8bDmx0754Mw==",
+      "version": "4.0.16",
+      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.16.tgz",
+      "integrity": "sha512-JcO7cb8QJLBWE+DfxGUL3xUDOae/8nhM1KVdnudadTAORbuxIC/xAydC5Zr/VLHUDQi1ppuTF5/rjBGzgzrJNA==",
       "requires": {
         "@vue/devtools-api": "^6.0.0"
       }
@@ -22414,7 +22634,7 @@
         "hash-sum": {
           "version": "1.0.2",
           "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
-          "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=",
+          "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
           "dev": true
         },
         "json5": {
@@ -22557,7 +22777,7 @@
     "watch": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz",
-      "integrity": "sha1-NApxe952Vyb6CqB9ch4BR6VR3ww=",
+      "integrity": "sha512-1u+Z5n9Jc1E2c7qDO8SinPoZuHj7FgbgU1olSFoyaklduDvvtX7GMMtlE6OC9FTXq4KvNAOfj6Zu4vI1e9bAKA==",
       "dev": true,
       "requires": {
         "exec-sh": "^0.2.0",
@@ -22600,7 +22820,7 @@
             "normalize-path": {
               "version": "2.1.1",
               "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
-              "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+              "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -22651,7 +22871,7 @@
         "is-binary-path": {
           "version": "1.0.1",
           "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
-          "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+          "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -22684,7 +22904,7 @@
     "wcwidth": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
-      "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=",
+      "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
       "dev": true,
       "requires": {
         "defaults": "^1.0.3"
@@ -22693,7 +22913,7 @@
     "webidl-conversions": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
-      "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
       "dev": true
     },
     "webpack": {
@@ -22748,12 +22968,12 @@
           }
         },
         "mkdirp": {
-          "version": "0.5.5",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
-          "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+          "version": "0.5.6",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+          "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
           "dev": true,
           "requires": {
-            "minimist": "^1.2.5"
+            "minimist": "^1.2.6"
           }
         },
         "schema-utils": {
@@ -22844,7 +23064,7 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "commander": {
@@ -22856,7 +23076,7 @@
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "mkdirp": {
@@ -23011,7 +23231,7 @@
             "normalize-path": {
               "version": "2.1.1",
               "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
-              "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+              "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==",
               "dev": true,
               "requires": {
                 "remove-trailing-separator": "^1.0.1"
@@ -23079,7 +23299,7 @@
         "color-name": {
           "version": "1.1.3",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
           "dev": true
         },
         "emoji-regex": {
@@ -23111,7 +23331,7 @@
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
           "dev": true
         },
         "http-proxy-middleware": {
@@ -23135,7 +23355,7 @@
         "is-binary-path": {
           "version": "1.0.1",
           "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
-          "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+          "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==",
           "dev": true,
           "requires": {
             "binary-extensions": "^1.0.0"
@@ -23144,7 +23364,7 @@
         "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=",
+          "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
           "dev": true
         },
         "locate-path": {
@@ -23169,7 +23389,7 @@
         "path-exists": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+          "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
           "dev": true
         },
         "readdirp": {
@@ -23372,7 +23592,7 @@
     "whatwg-url": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
-      "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
       "dev": true,
       "requires": {
         "tr46": "~0.0.3",
@@ -23403,7 +23623,7 @@
     "which-module": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+      "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
       "dev": true
     },
     "wide-align": {
@@ -23515,7 +23735,7 @@
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
     },
     "write": {
       "version": "1.0.3",
@@ -23549,9 +23769,9 @@
       }
     },
     "ws": {
-      "version": "7.5.7",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
-      "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
+      "version": "7.5.8",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.8.tgz",
+      "integrity": "sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw==",
       "dev": true
     },
     "xdg-basedir": {
@@ -23588,9 +23808,9 @@
       "dev": true
     },
     "xss": {
-      "version": "1.0.11",
-      "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.11.tgz",
-      "integrity": "sha512-EimjrjThZeK2MO7WKR9mN5ZC1CSqivSl55wvUK5EtU6acf0rzEE1pN+9ZDrFXJ82BRp3JL38pPE6S4o/rpp1zQ==",
+      "version": "1.0.13",
+      "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.13.tgz",
+      "integrity": "sha512-clu7dxTm1e8Mo5fz3n/oW3UCXBfV89xZ72jM8yzo1vR/pIS0w3sgB3XV2H8Vm6zfGnHL0FzvLJPJEBhd86/z4Q==",
       "dev": true,
       "requires": {
         "commander": "^2.20.3",
@@ -23625,7 +23845,7 @@
     "yaml-front-matter": {
       "version": "3.4.1",
       "resolved": "https://registry.npmjs.org/yaml-front-matter/-/yaml-front-matter-3.4.1.tgz",
-      "integrity": "sha1-5S6E/qaYO5N1XpsVZNupibAGtaU=",
+      "integrity": "sha512-/sDeHR8GD6JIJ8j/2h28QsjXS9XsWp2WnjU8RQODri/u6INSEF9Q5w4mZVl0KtXsM1UCBYQhOwTvJKTsnmusBQ==",
       "dev": true,
       "requires": {
         "commander": "1.0.0",
@@ -23635,7 +23855,7 @@
         "commander": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/commander/-/commander-1.0.0.tgz",
-          "integrity": "sha1-XmqI5wcP9ZCINurRkWlUjDD5C80=",
+          "integrity": "sha512-ypAKENwAvjA+utibuxSPeduXV/tIX73+9IyWMkFNnbxiJTeY2xdcM8C2KZo3KEGlDnO5tSm2BVZ65QfuRcR8DQ==",
           "dev": true
         }
       }
@@ -23698,7 +23918,7 @@
     "yauzl": {
       "version": "2.10.0",
       "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
-      "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+      "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
       "dev": true,
       "requires": {
         "buffer-crc32": "~0.2.3",
@@ -23726,7 +23946,7 @@
         "cross-spawn": {
           "version": "5.1.0",
           "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
-          "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+          "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==",
           "dev": true,
           "requires": {
             "lru-cache": "^4.0.1",
@@ -23737,7 +23957,7 @@
         "execa": {
           "version": "0.8.0",
           "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz",
-          "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=",
+          "integrity": "sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==",
           "dev": true,
           "requires": {
             "cross-spawn": "^5.0.1",
@@ -23752,7 +23972,7 @@
         "get-stream": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
-          "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
+          "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==",
           "dev": true
         },
         "is-ci": {
@@ -23777,7 +23997,7 @@
         "normalize-path": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-1.0.0.tgz",
-          "integrity": "sha1-MtDkcvkf80VwHBWoMRAY07CpA3k=",
+          "integrity": "sha512-7WyT0w8jhpDStXRq5836AMmihQwq2nrUVQrgjvUo/p/NZf9uy/MeJ246lBJVmWuYXMlJuG9BNZHF0hWjfTbQUA==",
           "dev": true
         },
         "which": {
@@ -23792,7 +24012,7 @@
         "yallist": {
           "version": "2.1.2",
           "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
-          "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+          "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
           "dev": true
         }
       }
diff --git a/ui/package.json b/ui/package.json
index 55a9c96..1bc174a 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -38,19 +38,24 @@
     "@fortawesome/free-brands-svg-icons": "^5.15.2",
     "@fortawesome/free-solid-svg-icons": "^5.15.2",
     "@fortawesome/vue-fontawesome": "^3.0.0-4",
-    "ant-design-vue": "^2.2.3",
+    "@vue-js-cron/ant": "^1.1.3",
+    "@vue-js-cron/core": "^3.7.1",
+    "ant-design-vue": "^3.2.9",
+    "antd": "^4.21.4",
     "antd-theme-webpack-plugin": "^1.3.9",
     "axios": "^0.21.1",
     "babel-plugin-require-context-hook": "^1.0.0",
     "chart.js": "^3.7.1",
     "chartjs-adapter-moment": "^1.0.0",
     "core-js": "^3.21.1",
+    "cronstrue": "^2.26.0",
     "enquire.js": "^2.1.6",
     "js-cookie": "^2.2.1",
     "lodash": "^4.17.15",
     "md5": "^2.2.1",
     "mitt": "^2.1.0",
     "moment": "^2.26.0",
+    "moment-timezone": "^0.5.43",
     "npm-check-updates": "^6.0.1",
     "nprogress": "^0.2.0",
     "qrious": "^4.0.2",
diff --git a/ui/public/assets/banner.svg b/ui/public/assets/banner.svg
index 23eefed..d9a3e51 100644
--- a/ui/public/assets/banner.svg
+++ b/ui/public/assets/banner.svg
@@ -316,4 +316,4 @@
          id="path184"
          style="fill:#69afd8;fill-opacity:1;fill-rule:nonzero;stroke:none"
          d="m 0,0 h 15.311 v -47.158 l 16.944,19.598 h 18.781 l -19.7,-22.354 20.211,-27.253 H 32.255 l -16.74,25.109 H 15.311 V -77.167 H 0 Z"
-         inkscape:connector-curvature="0" /></g></g></g></g></g></svg>
\ No newline at end of file
+         inkscape:connector-curvature="0" /></g></g></g></g></g></svg>
diff --git a/ui/public/assets/logo.svg b/ui/public/assets/logo.svg
index ed6cb89..5a60be9 100644
--- a/ui/public/assets/logo.svg
+++ b/ui/public/assets/logo.svg
@@ -329,4 +329,4 @@
          id="path184"
          style="fill:#69afd8;fill-opacity:1;fill-rule:nonzero;stroke:none"
          d="m 0,0 h 15.311 v -47.158 l 16.944,19.598 h 18.781 l -19.7,-22.354 20.211,-27.253 H 32.255 l -16.74,25.109 H 15.311 V -77.167 H 0 Z"
-         inkscape:connector-curvature="0" /></g></g></g></g></g></svg>
\ No newline at end of file
+         inkscape:connector-curvature="0" /></g></g></g></g></g></svg>
diff --git a/ui/public/assets/mini-logo.svg b/ui/public/assets/mini-logo.svg
index 72b4df7..e59b434 100644
--- a/ui/public/assets/mini-logo.svg
+++ b/ui/public/assets/mini-logo.svg
@@ -218,4 +218,4 @@
 </g>
 </g>
 </g>
-</svg>
\ No newline at end of file
+</svg>
diff --git a/ui/public/config.json b/ui/public/config.json
index 6c3acb9..82d7c9a 100644
--- a/ui/public/config.json
+++ b/ui/public/config.json
@@ -64,4 +64,4 @@
   "multipleServer": false,
   "allowSettingTheme": true,
   "docHelpMappings": {}
-}
\ No newline at end of file
+}
diff --git a/ui/public/js/less.min.js b/ui/public/js/less.min.js
index 6319704..3605915 100644
--- a/ui/public/js/less.min.js
+++ b/ui/public/js/less.min.js
@@ -14,4 +14,4 @@
 "../tree/quoted":73,"./function-registry":22}],28:[function(a,b,c){b.exports=function(b){var c=a("../tree/dimension"),d=a("../tree/color"),e=a("../tree/expression"),f=a("../tree/quoted"),g=a("../tree/url"),h=a("./function-registry");h.add("svg-gradient",function(a){function b(){throw{type:"Argument",message:"svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position] or direction, color list"}}var h,i,j,k,l,m,n,o,p="linear",q='x="0" y="0" width="1" height="1"',r={compress:!1},s=a.toCSS(r);switch(2==arguments.length?(arguments[1].value.length<2&&b(),h=arguments[1].value):arguments.length<3?b():h=Array.prototype.slice.call(arguments,1),s){case"to bottom":i='x1="0%" y1="0%" x2="0%" y2="100%"';break;case"to right":i='x1="0%" y1="0%" x2="100%" y2="0%"';break;case"to bottom right":i='x1="0%" y1="0%" x2="100%" y2="100%"';break;case"to top right":i='x1="0%" y1="100%" x2="100%" y2="0%"';break;case"ellipse":case"ellipse at center":p="radial",i='cx="50%" cy="50%" r="75%"',q='x="-50" y="-50" width="101" height="101"';break;default:throw{type:"Argument",message:"svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'"}}for(j='<?xml version="1.0" ?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none"><'+p+'Gradient id="gradient" gradientUnits="userSpaceOnUse" '+i+">",k=0;k<h.length;k+=1)h[k]instanceof e?(l=h[k].value[0],m=h[k].value[1]):(l=h[k],m=void 0),l instanceof d&&((0===k||k+1===h.length)&&void 0===m||m instanceof c)||b(),n=m?m.toCSS(r):0===k?"0%":"100%",o=l.alpha,j+='<stop offset="'+n+'" stop-color="'+l.toRGB()+'"'+(o<1?' stop-opacity="'+o+'"':"")+"/>";return j+="</"+p+"Gradient><rect "+q+' fill="url(#gradient)" /></svg>',j=encodeURIComponent(j),j="data:image/svg+xml,"+j,new g(new f("'"+j+"'",j,(!1),this.index,this.currentFileInfo),this.index,this.currentFileInfo)})}},{"../tree/color":50,"../tree/dimension":56,"../tree/expression":59,"../tree/quoted":73,"../tree/url":80,"./function-registry":22}],29:[function(a,b,c){var d=a("../tree/keyword"),e=a("../tree/detached-ruleset"),f=a("../tree/dimension"),g=a("../tree/color"),h=a("../tree/quoted"),i=a("../tree/anonymous"),j=a("../tree/url"),k=a("../tree/operation"),l=a("./function-registry"),m=function(a,b){return a instanceof b?d.True:d.False},n=function(a,b){if(void 0===b)throw{type:"Argument",message:"missing the required second argument to isunit."};if(b="string"==typeof b.value?b.value:b,"string"!=typeof b)throw{type:"Argument",message:"Second argument to isunit should be a unit or a string."};return a instanceof f&&a.unit.is(b)?d.True:d.False},o=function(a){var b=Array.isArray(a.value)?a.value:Array(a);return b};l.addMultiple({isruleset:function(a){return m(a,e)},iscolor:function(a){return m(a,g)},isnumber:function(a){return m(a,f)},isstring:function(a){return m(a,h)},iskeyword:function(a){return m(a,d)},isurl:function(a){return m(a,j)},ispixel:function(a){return n(a,"px")},ispercentage:function(a){return n(a,"%")},isem:function(a){return n(a,"em")},isunit:n,unit:function(a,b){if(!(a instanceof f))throw{type:"Argument",message:"the first argument to unit must be a number"+(a instanceof k?". Have you forgotten parenthesis?":"")};return b=b?b instanceof d?b.value:b.toCSS():"",new f(a.value,b)},"get-unit":function(a){return new i(a.unit)},extract:function(a,b){return b=b.value-1,o(a)[b]},length:function(a){return new f(o(a).length)}})},{"../tree/anonymous":46,"../tree/color":50,"../tree/detached-ruleset":55,"../tree/dimension":56,"../tree/keyword":65,"../tree/operation":71,"../tree/quoted":73,"../tree/url":80,"./function-registry":22}],30:[function(a,b,c){var d=a("./contexts"),e=a("./parser/parser"),f=a("./plugins/function-importer");b.exports=function(a){var b=function(a,b){this.rootFilename=b.filename,this.paths=a.paths||[],this.contents={},this.contentsIgnoredChars={},this.mime=a.mime,this.error=null,this.context=a,this.queue=[],this.files={}};return b.prototype.push=function(b,c,g,h,i){var j=this;this.queue.push(b);var k=function(a,c,d){j.queue.splice(j.queue.indexOf(b),1);var e=d===j.rootFilename;h.optional&&a?i(null,{rules:[]},!1,null):(j.files[d]=c,a&&!j.error&&(j.error=a),i(a,c,e,d))},l={relativeUrls:this.context.relativeUrls,entryPath:g.entryPath,rootpath:g.rootpath,rootFilename:g.rootFilename},m=a.getFileManager(b,g.currentDirectory,this.context,a);if(!m)return void k({message:"Could not find a file-manager for "+b});c&&(b=m.tryAppendExtension(b,h.plugin?".js":".less"));var n=function(a){var b=a.filename,c=a.contents.replace(/^\uFEFF/,"");l.currentDirectory=m.getPath(b),l.relativeUrls&&(l.rootpath=m.join(j.context.rootpath||"",m.pathDiff(l.currentDirectory,l.entryPath)),!m.isPathAbsolute(l.rootpath)&&m.alwaysMakePathsAbsolute()&&(l.rootpath=m.join(l.entryPath,l.rootpath))),l.filename=b;var i=new d.Parse(j.context);i.processImports=!1,j.contents[b]=c,(g.reference||h.reference)&&(l.reference=!0),h.plugin?new f(i,l).eval(c,function(a,c){k(a,c,b)}):h.inline?k(null,c,b):new e(i,j,l).parse(c,function(a,c){k(a,c,b)})},o=m.loadFile(b,g.currentDirectory,this.context,a,function(a,b){a?k(a):n(b)});o&&o.then(n,k)},b}},{"./contexts":11,"./parser/parser":38,"./plugins/function-importer":40}],31:[function(a,b,c){b.exports=function(b,c){var d,e,f,g,h,i={version:[2,7,2],data:a("./data"),tree:a("./tree"),Environment:h=a("./environment/environment"),AbstractFileManager:a("./environment/abstract-file-manager"),environment:b=new h(b,c),visitors:a("./visitors"),Parser:a("./parser/parser"),functions:a("./functions")(b),contexts:a("./contexts"),SourceMapOutput:d=a("./source-map-output")(b),SourceMapBuilder:e=a("./source-map-builder")(d,b),ParseTree:f=a("./parse-tree")(e),ImportManager:g=a("./import-manager")(b),render:a("./render")(b,f,g),parse:a("./parse")(b,f,g),LessError:a("./less-error"),transformTree:a("./transform-tree"),utils:a("./utils"),PluginManager:a("./plugin-manager"),logger:a("./logger")};return i}},{"./contexts":11,"./data":13,"./environment/abstract-file-manager":15,"./environment/environment":16,"./functions":23,"./import-manager":30,"./less-error":32,"./logger":33,"./parse":35,"./parse-tree":34,"./parser/parser":38,"./plugin-manager":39,"./render":41,"./source-map-builder":42,"./source-map-output":43,"./transform-tree":44,"./tree":62,"./utils":83,"./visitors":87}],32:[function(a,b,c){var d=a("./utils"),e=b.exports=function(a,b,c){Error.call(this);var e=a.filename||c;if(b&&e){var f=b.contents[e],g=d.getLocation(a.index,f),h=g.line,i=g.column,j=a.call&&d.getLocation(a.call,f).line,k=f.split("\n");this.type=a.type||"Syntax",this.filename=e,this.index=a.index,this.line="number"==typeof h?h+1:null,this.callLine=j+1,this.callExtract=k[j],this.column=i,this.extract=[k[h-1],k[h],k[h+1]]}this.message=a.message,this.stack=a.stack};if("undefined"==typeof Object.create){var f=function(){};f.prototype=Error.prototype,e.prototype=new f}else e.prototype=Object.create(Error.prototype);e.prototype.constructor=e},{"./utils":83}],33:[function(a,b,c){b.exports={error:function(a){this._fireEvent("error",a)},warn:function(a){this._fireEvent("warn",a)},info:function(a){this._fireEvent("info",a)},debug:function(a){this._fireEvent("debug",a)},addListener:function(a){this._listeners.push(a)},removeListener:function(a){for(var b=0;b<this._listeners.length;b++)if(this._listeners[b]===a)return void this._listeners.splice(b,1)},_fireEvent:function(a,b){for(var c=0;c<this._listeners.length;c++){var d=this._listeners[c][a];d&&d(b)}},_listeners:[]}},{}],34:[function(a,b,c){var d=a("./less-error"),e=a("./transform-tree"),f=a("./logger");b.exports=function(a){var b=function(a,b){this.root=a,this.imports=b};return b.prototype.toCSS=function(b){var c,g,h={};try{c=e(this.root,b)}catch(i){throw new d(i,this.imports)}try{var j=Boolean(b.compress);j&&f.warn("The compress option has been deprecated. We recommend you use a dedicated css minifier, for instance see less-plugin-clean-css.");var k={compress:j,dumpLineNumbers:b.dumpLineNumbers,strictUnits:Boolean(b.strictUnits),numPrecision:8};b.sourceMap?(g=new a(b.sourceMap),h.css=g.toCSS(c,k,this.imports)):h.css=c.toCSS(k)}catch(i){throw new d(i,this.imports)}if(b.pluginManager)for(var l=b.pluginManager.getPostProcessors(),m=0;m<l.length;m++)h.css=l[m].process(h.css,{sourceMap:g,options:b,imports:this.imports});b.sourceMap&&(h.map=g.getExternalSourceMap()),h.imports=[];for(var n in this.imports.files)this.imports.files.hasOwnProperty(n)&&n!==this.imports.rootFilename&&h.imports.push(n);return h},b}},{"./less-error":32,"./logger":33,"./transform-tree":44}],35:[function(a,b,c){var d,e=a("./contexts"),f=a("./parser/parser"),g=a("./plugin-manager");b.exports=function(b,c,h){var i=function(b,c,j){if(c=c||{},"function"==typeof c&&(j=c,c={}),!j){d||(d="undefined"==typeof Promise?a("promise"):Promise);var k=this;return new d(function(a,d){i.call(k,b,c,function(b,c){b?d(b):a(c)})})}var l,m,n=new g(this);if(n.addPlugins(c.plugins),c.pluginManager=n,l=new e.Parse(c),c.rootFileInfo)m=c.rootFileInfo;else{var o=c.filename||"input",p=o.replace(/[^\/\\]*$/,"");m={filename:o,relativeUrls:l.relativeUrls,rootpath:l.rootpath||"",currentDirectory:p,entryPath:p,rootFilename:o},m.rootpath&&"/"!==m.rootpath.slice(-1)&&(m.rootpath+="/")}var q=new h(l,m);new f(l,q,m).parse(b,function(a,b){return a?j(a):void j(null,b,q,c)},c)};return i}},{"./contexts":11,"./parser/parser":38,"./plugin-manager":39,promise:void 0}],36:[function(a,b,c){b.exports=function(a,b){function c(b){var c=h-q;c<512&&!b||!c||(p.push(a.slice(q,h+1)),q=h+1)}var d,e,f,g,h,i,j,k,l,m=a.length,n=0,o=0,p=[],q=0;for(h=0;h<m;h++)if(j=a.charCodeAt(h),!(j>=97&&j<=122||j<34))switch(j){case 40:o++,e=h;continue;case 41:if(--o<0)return b("missing opening `(`",h);continue;case 59:o||c();continue;case 123:n++,d=h;continue;case 125:if(--n<0)return b("missing opening `{`",h);n||o||c();continue;case 92:if(h<m-1){h++;continue}return b("unescaped `\\`",h);case 34:case 39:case 96:for(l=0,i=h,h+=1;h<m;h++)if(k=a.charCodeAt(h),!(k>96)){if(k==j){l=1;break}if(92==k){if(h==m-1)return b("unescaped `\\`",h);h++}}if(l)continue;return b("unmatched `"+String.fromCharCode(j)+"`",i);case 47:if(o||h==m-1)continue;if(k=a.charCodeAt(h+1),47==k)for(h+=2;h<m&&(k=a.charCodeAt(h),!(k<=13)||10!=k&&13!=k);h++);else if(42==k){for(f=i=h,h+=2;h<m-1&&(k=a.charCodeAt(h),125==k&&(g=h),42!=k||47!=a.charCodeAt(h+1));h++);if(h==m-1)return b("missing closing `*/`",i);h++}continue;case 42:if(h<m-1&&47==a.charCodeAt(h+1))return b("unmatched `/*`",h);continue}return 0!==n?f>d&&g>f?b("missing closing `}` or `*/`",d):b("missing closing `}`",d):0!==o?b("missing closing `)`",e):(c(!0),p)}},{}],37:[function(a,b,c){var d=a("./chunker");b.exports=function(){function a(d){for(var e,f,j,p=k.i,q=c,s=k.i-i,t=k.i+h.length-s,u=k.i+=d,v=b;k.i<t;k.i++){if(e=v.charCodeAt(k.i),k.autoCommentAbsorb&&e===r){if(f=v.charAt(k.i+1),"/"===f){j={index:k.i,isLineComment:!0};var w=v.indexOf("\n",k.i+2);w<0&&(w=t),k.i=w,j.text=v.substr(j.index,k.i-j.index),k.commentStore.push(j);continue}if("*"===f){var x=v.indexOf("*/",k.i+2);if(x>=0){j={index:k.i,text:v.substr(k.i,x+2-k.i),isLineComment:!1},k.i+=j.text.length-1,k.commentStore.push(j);continue}}break}if(e!==l&&e!==n&&e!==m&&e!==o)break}if(h=h.slice(d+k.i-u+s),i=k.i,!h.length){if(c<g.length-1)return h=g[++c],a(0),!0;k.finished=!0}return p!==k.i||q!==c}var b,c,e,f,g,h,i,j=[],k={},l=32,m=9,n=10,o=13,p=43,q=44,r=47,s=57;return k.save=function(){i=k.i,j.push({current:h,i:k.i,j:c})},k.restore=function(a){(k.i>e||k.i===e&&a&&!f)&&(e=k.i,f=a);var b=j.pop();h=b.current,i=k.i=b.i,c=b.j},k.forget=function(){j.pop()},k.isWhitespace=function(a){var c=k.i+(a||0),d=b.charCodeAt(c);return d===l||d===o||d===m||d===n},k.$re=function(b){k.i>i&&(h=h.slice(k.i-i),i=k.i);var c=b.exec(h);return c?(a(c[0].length),"string"==typeof c?c:1===c.length?c[0]:c):null},k.$char=function(c){return b.charAt(k.i)!==c?null:(a(1),c)},k.$str=function(c){for(var d=c.length,e=0;e<d;e++)if(b.charAt(k.i+e)!==c.charAt(e))return null;return a(d),c},k.$quoted=function(){var c=b.charAt(k.i);if("'"===c||'"'===c){for(var d=b.length,e=k.i,f=1;f+e<d;f++){var g=b.charAt(f+e);switch(g){case"\\":f++;continue;case"\r":case"\n":break;case c:var h=b.substr(e,f+1);return a(f+1),h}}return null}},k.autoCommentAbsorb=!0,k.commentStore=[],k.finished=!1,k.peek=function(a){if("string"==typeof a){for(var c=0;c<a.length;c++)if(b.charAt(k.i+c)!==a.charAt(c))return!1;return!0}return a.test(h)},k.peekChar=function(a){return b.charAt(k.i)===a},k.currentChar=function(){return b.charAt(k.i)},k.getInput=function(){return b},k.peekNotNumeric=function(){var a=b.charCodeAt(k.i);return a>s||a<p||a===r||a===q},k.start=function(f,j,l){b=f,k.i=c=i=e=0,g=j?d(f,l):[f],h=g[0],a(0)},k.end=function(){var a,c=k.i>=b.length;return k.i<e&&(a=f,k.i=e),{isFinished:c,furthest:k.i,furthestPossibleErrorMessage:a,furthestReachedEnd:k.i>=b.length-1,furthestChar:b[k.i]}},k}},{"./chunker":36}],38:[function(a,b,c){var d=a("../less-error"),e=a("../tree"),f=a("../visitors"),g=a("./parser-input"),h=a("../utils"),i=function j(a,b,c){function i(a,e){throw new d({index:o.i,filename:c.filename,type:e||"Syntax",message:a},b)}function k(a,b,c){var d=a instanceof Function?a.call(n):o.$re(a);return d?d:void i(b||("string"==typeof a?"expected '"+a+"' got '"+o.currentChar()+"'":"unexpected token"))}function l(a,b){return o.$char(a)?a:void i(b||"expected '"+a+"' got '"+o.currentChar()+"'")}function m(a){var b=c.filename;return{lineNumber:h.getLocation(a,o.getInput()).line+1,fileName:b}}var n,o=g();return{parse:function(g,h,i){var k,l,m,n,p=null,q="";if(l=i&&i.globalVars?j.serializeVars(i.globalVars)+"\n":"",m=i&&i.modifyVars?"\n"+j.serializeVars(i.modifyVars):"",a.pluginManager)for(var r=a.pluginManager.getPreProcessors(),s=0;s<r.length;s++)g=r[s].process(g,{context:a,imports:b,fileInfo:c});(l||i&&i.banner)&&(q=(i&&i.banner?i.banner:"")+l,n=b.contentsIgnoredChars,n[c.filename]=n[c.filename]||0,n[c.filename]+=q.length),g=g.replace(/\r\n?/g,"\n"),g=q+g.replace(/^\uFEFF/,"")+m,b.contents[c.filename]=g;try{o.start(g,a.chunkInput,function(a,e){throw new d({index:e,type:"Parse",message:a,filename:c.filename},b)}),k=new e.Ruleset(null,this.parsers.primary()),k.root=!0,k.firstRoot=!0}catch(t){return h(new d(t,b,c.filename))}var u=o.end();if(!u.isFinished){var v=u.furthestPossibleErrorMessage;v||(v="Unrecognised input","}"===u.furthestChar?v+=". Possibly missing opening '{'":")"===u.furthestChar?v+=". Possibly missing opening '('":u.furthestReachedEnd&&(v+=". Possibly missing something")),p=new d({type:"Parse",message:v,index:u.furthest,filename:c.filename},b)}var w=function(a){return a=p||a||b.error,a?(a instanceof d||(a=new d(a,b,c.filename)),h(a)):h(null,k)};return a.processImports===!1?w():void new f.ImportVisitor(b,w).run(k)},parsers:n={primary:function(){for(var a,b=this.mixin,c=[];;){for(;;){if(a=this.comment(),!a)break;c.push(a)}if(o.finished)break;if(o.peek("}"))break;if(a=this.extendRule())c=c.concat(a);else if(a=b.definition()||this.rule()||this.ruleset()||b.call()||this.rulesetCall()||this.entities.call()||this.directive())c.push(a);else{for(var d=!1;o.$char(";");)d=!0;if(!d)break}}return c},comment:function(){if(o.commentStore.length){var a=o.commentStore.shift();return new e.Comment(a.text,a.isLineComment,a.index,c)}},entities:{quoted:function(){var a,b=o.i,d=!1;return o.save(),o.$char("~")&&(d=!0),(a=o.$quoted())?(o.forget(),new e.Quoted(a.charAt(0),a.substr(1,a.length-2),d,b,c)):void o.restore()},keyword:function(){var a=o.$char("%")||o.$re(/^[_A-Za-z-][_A-Za-z0-9-]*/);if(a)return e.Color.fromKeyword(a)||new e.Keyword(a)},call:function(){var a,b,d,f,g=o.i;if(!o.peek(/^url\(/i))return o.save(),(a=o.$re(/^([\w-]+|%|progid:[\w\.]+)\(/))?(a=a[1],b=a.toLowerCase(),"alpha"===b&&(f=n.alpha())?(o.forget(),f):(d=this.arguments(),o.$char(")")?(o.forget(),new e.Call(a,d,g,c)):void o.restore("Could not parse call arguments or missing ')'"))):void o.forget()},arguments:function(){var a,b,c,d=[],f=[],g=[];for(o.save();;){if(c=n.detachedRuleset()||this.assignment()||n.expression(),!c)break;b=c,c.value&&1==c.value.length&&(b=c.value[0]),b&&g.push(b),f.push(b),o.$char(",")||(o.$char(";")||a)&&(a=!0,g.length>1&&(b=new e.Value(g)),d.push(b),g=[])}return o.forget(),a?d:f},literal:function(){return this.dimension()||this.color()||this.quoted()||this.unicodeDescriptor()},assignment:function(){var a,b;return o.save(),(a=o.$re(/^\w+(?=\s?=)/i))&&o.$char("=")&&(b=n.entity())?(o.forget(),new e.Assignment(a,b)):void o.restore()},url:function(){var a,b=o.i;return o.autoCommentAbsorb=!1,o.$str("url(")?(a=this.quoted()||this.variable()||o.$re(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/)||"",o.autoCommentAbsorb=!0,l(")"),new e.URL(null!=a.value||a instanceof e.Variable?a:new e.Anonymous(a),b,c)):void(o.autoCommentAbsorb=!0)},variable:function(){var a,b=o.i;if("@"===o.currentChar()&&(a=o.$re(/^@@?[\w-]+/)))return new e.Variable(a,b,c)},variableCurly:function(){var a,b=o.i;if("@"===o.currentChar()&&(a=o.$re(/^@\{([\w-]+)\}/)))return new e.Variable("@"+a[1],b,c)},color:function(){var a;if("#"===o.currentChar()&&(a=o.$re(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))){var b=a.input.match(/^#([\w]+).*/);return b=b[1],b.match(/^[A-Fa-f0-9]+$/)||i("Invalid HEX color code"),new e.Color(a[1],(void 0),"#"+b)}},colorKeyword:function(){o.save();var a=o.autoCommentAbsorb;o.autoCommentAbsorb=!1;var b=o.$re(/^[_A-Za-z-][_A-Za-z0-9-]+/);if(o.autoCommentAbsorb=a,!b)return void o.forget();o.restore();var c=e.Color.fromKeyword(b);return c?(o.$str(b),c):void 0},dimension:function(){if(!o.peekNotNumeric()){var a=o.$re(/^([+-]?\d*\.?\d+)(%|[a-z_]+)?/i);return a?new e.Dimension(a[1],a[2]):void 0}},unicodeDescriptor:function(){var a;if(a=o.$re(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/))return new e.UnicodeDescriptor(a[0])},javascript:function(){var a,b=o.i;o.save();var d=o.$char("~"),f=o.$char("`");return f?(a=o.$re(/^[^`]*`/))?(o.forget(),new e.JavaScript(a.substr(0,a.length-1),Boolean(d),b,c)):void o.restore("invalid javascript definition"):void o.restore()}},variable:function(){var a;if("@"===o.currentChar()&&(a=o.$re(/^(@[\w-]+)\s*:/)))return a[1]},rulesetCall:function(){var a;if("@"===o.currentChar()&&(a=o.$re(/^(@[\w-]+)\(\s*\)\s*;/)))return new e.RulesetCall(a[1])},extend:function(a){var b,d,f,g,h,j=o.i;if(o.$str(a?"&:extend(":":extend(")){do{for(f=null,b=null;!(f=o.$re(/^(all)(?=\s*(\)|,))/))&&(d=this.element());)b?b.push(d):b=[d];f=f&&f[1],b||i("Missing target selector for :extend()."),h=new e.Extend(new e.Selector(b),f,j,c),g?g.push(h):g=[h]}while(o.$char(","));return k(/^\)/),a&&k(/^;/),g}},extendRule:function(){return this.extend(!0)},mixin:{call:function(){var a,b,d,f,g,h,i=o.currentChar(),j=!1,k=o.i;if("."===i||"#"===i){for(o.save();;){if(a=o.i,f=o.$re(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/),!f)break;d=new e.Element(g,f,a,c),b?b.push(d):b=[d],g=o.$char(">")}return b&&(o.$char("(")&&(h=this.args(!0).args,l(")")),n.important()&&(j=!0),n.end())?(o.forget(),new e.mixin.Call(b,h,k,c,j)):void o.restore()}},args:function(a){var b,c,d,f,g,h,j,k=n.entities,l={args:null,variadic:!1},m=[],p=[],q=[];for(o.save();;){if(a)h=n.detachedRuleset()||n.expression();else{if(o.commentStore.length=0,o.$str("...")){l.variadic=!0,o.$char(";")&&!b&&(b=!0),(b?p:q).push({variadic:!0});break}h=k.variable()||k.literal()||k.keyword()}if(!h)break;f=null,h.throwAwayComments&&h.throwAwayComments(),g=h;var r=null;if(a?h.value&&1==h.value.length&&(r=h.value[0]):r=h,r&&r instanceof e.Variable)if(o.$char(":")){if(m.length>0&&(b&&i("Cannot mix ; and , as delimiter types"),c=!0),g=n.detachedRuleset()||n.expression(),!g){if(!a)return o.restore(),l.args=[],l;i("could not understand value for named argument")}f=d=r.name}else if(o.$str("...")){if(!a){l.variadic=!0,o.$char(";")&&!b&&(b=!0),(b?p:q).push({name:h.name,variadic:!0});break}j=!0}else a||(d=f=r.name,g=null);g&&m.push(g),q.push({name:f,value:g,expand:j}),o.$char(",")||(o.$char(";")||b)&&(c&&i("Cannot mix ; and , as delimiter types"),b=!0,m.length>1&&(g=new e.Value(m)),p.push({name:d,value:g,expand:j}),d=null,m=[],c=!1)}return o.forget(),l.args=b?p:q,l},definition:function(){var a,b,c,d,f=[],g=!1;if(!("."!==o.currentChar()&&"#"!==o.currentChar()||o.peek(/^[^{]*\}/)))if(o.save(),b=o.$re(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)){a=b[1];var h=this.args(!1);if(f=h.args,g=h.variadic,!o.$char(")"))return void o.restore("Missing closing ')'");if(o.commentStore.length=0,o.$str("when")&&(d=k(n.conditions,"expected condition")),c=n.block())return o.forget(),new e.mixin.Definition(a,f,c,d,g);o.restore()}else o.forget()}},entity:function(){var a=this.entities;return this.comment()||a.literal()||a.variable()||a.url()||a.call()||a.keyword()||a.javascript()},end:function(){return o.$char(";")||o.peek("}")},alpha:function(){var a;if(o.$re(/^opacity=/i))return a=o.$re(/^\d+/),a||(a=k(this.entities.variable,"Could not parse alpha")),l(")"),new e.Alpha(a)},element:function(){var a,b,d,f=o.i;if(b=this.combinator(),a=o.$re(/^(?:\d+\.\d+|\d+)%/)||o.$re(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)||o.$char("*")||o.$char("&")||this.attribute()||o.$re(/^\([^&()@]+\)/)||o.$re(/^[\.#:](?=@)/)||this.entities.variableCurly(),a||(o.save(),o.$char("(")?(d=this.selector())&&o.$char(")")?(a=new e.Paren(d),o.forget()):o.restore("Missing closing ')'"):o.forget()),a)return new e.Element(b,a,f,c)},combinator:function(){var a=o.currentChar();if("/"===a){o.save();var b=o.$re(/^\/[a-z]+\//i);if(b)return o.forget(),new e.Combinator(b);o.restore()}if(">"===a||"+"===a||"~"===a||"|"===a||"^"===a){for(o.i++,"^"===a&&"^"===o.currentChar()&&(a="^^",o.i++);o.isWhitespace();)o.i++;return new e.Combinator(a)}return new e.Combinator(o.isWhitespace(-1)?" ":null)},lessSelector:function(){return this.selector(!0)},selector:function(a){for(var b,d,f,g,h,j,l,m=o.i;(a&&(d=this.extend())||a&&(j=o.$str("when"))||(g=this.element()))&&(j?l=k(this.conditions,"expected condition"):l?i("CSS guard can only be used at the end of selector"):d?h=h?h.concat(d):d:(h&&i("Extend can only be used at the end of selector"),f=o.currentChar(),b?b.push(g):b=[g],g=null),"{"!==f&&"}"!==f&&";"!==f&&","!==f&&")"!==f););return b?new e.Selector(b,h,l,m,c):void(h&&i("Extend must be used to extend a selector, it cannot be used on its own"))},attribute:function(){if(o.$char("[")){var a,b,c,d=this.entities;return(a=d.variableCurly())||(a=k(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/)),c=o.$re(/^[|~*$^]?=/),c&&(b=d.quoted()||o.$re(/^[0-9]+%/)||o.$re(/^[\w-]+/)||d.variableCurly()),l("]"),new e.Attribute(a,c,b)}},block:function(){var a;if(o.$char("{")&&(a=this.primary())&&o.$char("}"))return a},blockRuleset:function(){var a=this.block();return a&&(a=new e.Ruleset(null,a)),a},detachedRuleset:function(){var a=this.blockRuleset();if(a)return new e.DetachedRuleset(a)},ruleset:function(){var b,c,d,f;for(o.save(),a.dumpLineNumbers&&(f=m(o.i));;){if(c=this.lessSelector(),!c)break;if(b?b.push(c):b=[c],o.commentStore.length=0,c.condition&&b.length>1&&i("Guards are only currently allowed on a single selector."),!o.$char(","))break;c.condition&&i("Guards are only currently allowed on a single selector."),o.commentStore.length=0}if(b&&(d=this.block())){o.forget();var g=new e.Ruleset(b,d,a.strictImports);return a.dumpLineNumbers&&(g.debugInfo=f),g}o.restore()},rule:function(b){var d,f,g,h,i,j=o.i,k=o.currentChar();if("."!==k&&"#"!==k&&"&"!==k&&":"!==k)if(o.save(),d=this.variable()||this.ruleProperty()){if(i="string"==typeof d,i&&(f=this.detachedRuleset()),o.commentStore.length=0,!f){h=!i&&d.length>1&&d.pop().value;var l=!b&&(a.compress||i);if(l&&(f=this.value()),!f&&(f=this.anonymousValue()))return o.forget(),new e.Rule(d,f,(!1),h,j,c);l||f||(f=this.value()),g=this.important()}if(f&&this.end())return o.forget(),new e.Rule(d,f,g,h,j,c);if(o.restore(),f&&!b)return this.rule(!0)}else o.forget()},anonymousValue:function(){var a=o.$re(/^([^@+\/'"*`(;{}-]*);/);if(a)return new e.Anonymous(a[1])},"import":function(){var a,b,d=o.i,f=o.$re(/^@import?\s+/);if(f){var g=(f?this.importOptions():null)||{};if(a=this.entities.quoted()||this.entities.url())return b=this.mediaFeatures(),o.$char(";")||(o.i=d,i("missing semi-colon or unrecognised media features on import")),b=b&&new e.Value(b),new e.Import(a,b,g,d,c);o.i=d,i("malformed import statement")}},importOptions:function(){var a,b,c,d={};if(!o.$char("("))return null;do if(a=this.importOption()){switch(b=a,c=!0,b){case"css":b="less",c=!1;break;case"once":b="multiple",c=!1}if(d[b]=c,!o.$char(","))break}while(a);return l(")"),d},importOption:function(){var a=o.$re(/^(less|css|multiple|once|inline|reference|optional)/);if(a)return a[1]},mediaFeature:function(){var a,b,d=this.entities,f=[];o.save();do a=d.keyword()||d.variable(),a?f.push(a):o.$char("(")&&(b=this.property(),a=this.value(),o.$char(")")?b&&a?f.push(new e.Paren(new e.Rule(b,a,null,null,o.i,c,(!0)))):a?f.push(new e.Paren(a)):i("badly formed media feature definition"):i("Missing closing ')'","Parse"));while(a);if(o.forget(),f.length>0)return new e.Expression(f)},mediaFeatures:function(){var a,b=this.entities,c=[];do if(a=this.mediaFeature()){if(c.push(a),!o.$char(","))break}else if(a=b.variable(),a&&(c.push(a),!o.$char(",")))break;while(a);return c.length>0?c:null},media:function(){var b,d,f,g,h=o.i;return a.dumpLineNumbers&&(g=m(h)),o.save(),o.$str("@media")?(b=this.mediaFeatures(),d=this.block(),d||i("media definitions require block statements after any features"),o.forget(),f=new e.Media(d,b,h,c),a.dumpLineNumbers&&(f.debugInfo=g),f):void o.restore()},plugin:function(){var a,b=o.i,d=o.$re(/^@plugin?\s+/);if(d){var f={plugin:!0};if(a=this.entities.quoted()||this.entities.url())return o.$char(";")||(o.i=b,i("missing semi-colon on plugin")),new e.Import(a,null,f,b,c);o.i=b,i("malformed plugin statement")}},directive:function(){var b,d,f,g,h,j,k,l=o.i,n=!0,p=!0;if("@"===o.currentChar()){if(d=this["import"]()||this.plugin()||this.media())return d;if(o.save(),b=o.$re(/^@[a-z-]+/)){switch(g=b,"-"==b.charAt(1)&&b.indexOf("-",2)>0&&(g="@"+b.slice(b.indexOf("-",2)+1)),g){case"@charset":h=!0,n=!1;break;case"@namespace":j=!0,n=!1;break;case"@keyframes":case"@counter-style":h=!0;break;case"@document":case"@supports":k=!0,p=!1;break;default:k=!0}return o.commentStore.length=0,h?(d=this.entity(),d||i("expected "+b+" identifier")):j?(d=this.expression(),d||i("expected "+b+" expression")):k&&(d=(o.$re(/^[^{;]+/)||"").trim(),n="{"==o.currentChar(),d&&(d=new e.Anonymous(d))),n&&(f=this.blockRuleset()),f||!n&&d&&o.$char(";")?(o.forget(),new e.Directive(b,d,f,l,c,a.dumpLineNumbers?m(l):null,p)):void o.restore("directive options not recognised")}}},value:function(){var a,b=[];do if(a=this.expression(),a&&(b.push(a),!o.$char(",")))break;while(a);if(b.length>0)return new e.Value(b)},important:function(){if("!"===o.currentChar())return o.$re(/^! *important/)},sub:function(){var a,b;return o.save(),o.$char("(")?(a=this.addition(),a&&o.$char(")")?(o.forget(),b=new e.Expression([a]),b.parens=!0,b):void o.restore("Expected ')'")):void o.restore()},multiplication:function(){var a,b,c,d,f;if(a=this.operand()){for(f=o.isWhitespace(-1);;){if(o.peek(/^\/[*\/]/))break;if(o.save(),c=o.$char("/")||o.$char("*"),!c){o.forget();break}if(b=this.operand(),!b){o.restore();break}o.forget(),a.parensInOp=!0,b.parensInOp=!0,d=new e.Operation(c,[d||a,b],f),f=o.isWhitespace(-1)}return d||a}},addition:function(){var a,b,c,d,f;if(a=this.multiplication()){for(f=o.isWhitespace(-1);;){if(c=o.$re(/^[-+]\s+/)||!f&&(o.$char("+")||o.$char("-")),!c)break;if(b=this.multiplication(),!b)break;a.parensInOp=!0,b.parensInOp=!0,d=new e.Operation(c,[d||a,b],f),f=o.isWhitespace(-1)}return d||a}},conditions:function(){var a,b,c,d=o.i;if(a=this.condition()){for(;;){if(!o.peek(/^,\s*(not\s*)?\(/)||!o.$char(","))break;if(b=this.condition(),!b)break;c=new e.Condition("or",c||a,b,d)}return c||a}},condition:function(){function a(){return o.$str("or")}var b,c,d;if(b=this.conditionAnd(this)){if(c=a()){if(d=this.condition(),!d)return;b=new e.Condition(c,b,d)}return b}},conditionAnd:function(){function a(a){return a.negatedCondition()||a.parenthesisCondition()}function b(){return o.$str("and")}var c,d,f;if(c=a(this)){if(d=b()){if(f=this.conditionAnd(),!f)return;c=new e.Condition(d,c,f)}return c}},negatedCondition:function(){if(o.$str("not")){var a=this.parenthesisCondition();return a&&(a.negate=!a.negate),a}},parenthesisCondition:function(){function a(a){var b;return o.save(),(b=a.condition())&&o.$char(")")?(o.forget(),b):void o.restore()}var b;return o.save(),o.$str("(")?(b=a(this))?(o.forget(),b):(b=this.atomicCondition())?o.$char(")")?(o.forget(),b):void o.restore("expected ')' got '"+o.currentChar()+"'"):void o.restore():void o.restore()},atomicCondition:function(){var a,b,c,d,f=this.entities,g=o.i;if(a=this.addition()||f.keyword()||f.quoted())return o.$char(">")?d=o.$char("=")?">=":">":o.$char("<")?d=o.$char("=")?"<=":"<":o.$char("=")&&(d=o.$char(">")?"=>":o.$char("<")?"=<":"="),d?(b=this.addition()||f.keyword()||f.quoted(),b?c=new e.Condition(d,a,b,g,(!1)):i("expected expression")):c=new e.Condition("=",a,new e.Keyword("true"),g,(!1)),c},operand:function(){var a,b=this.entities;o.peek(/^-[@\(]/)&&(a=o.$char("-"));var c=this.sub()||b.dimension()||b.color()||b.variable()||b.call()||b.colorKeyword();return a&&(c.parensInOp=!0,c=new e.Negative(c)),c},expression:function(){var a,b,c=[];do a=this.comment(),a?c.push(a):(a=this.addition()||this.entity(),a&&(c.push(a),o.peek(/^\/[\/*]/)||(b=o.$char("/"),b&&c.push(new e.Anonymous(b)))));while(a);if(c.length>0)return new e.Expression(c)},property:function(){var a=o.$re(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/);if(a)return a[1]},ruleProperty:function(){function a(a){var b=o.i,c=o.$re(a);if(c)return g.push(b),f.push(c[1])}var b,d,f=[],g=[];o.save();var h=o.$re(/^([_a-zA-Z0-9-]+)\s*:/);if(h)return f=[new e.Keyword(h[1])],o.forget(),f;for(a(/^(\*?)/);;)if(!a(/^((?:[\w-]+)|(?:@\{[\w-]+\}))/))break;if(f.length>1&&a(/^((?:\+_|\+)?)\s*:/)){for(o.forget(),""===f[0]&&(f.shift(),g.shift()),d=0;d<f.length;d++)b=f[d],f[d]="@"!==b.charAt(0)?new e.Keyword(b):new e.Variable("@"+b.slice(2,-1),g[d],c);return f}o.restore()}}}};i.serializeVars=function(a){var b="";for(var c in a)if(Object.hasOwnProperty.call(a,c)){var d=a[c];b+=("@"===c[0]?"":"@")+c+": "+d+(";"===String(d).slice(-1)?"":";")}return b},b.exports=i},{"../less-error":32,"../tree":62,"../utils":83,"../visitors":87,"./parser-input":37}],39:[function(a,b,c){var d=function(a){this.less=a,this.visitors=[],this.preProcessors=[],this.postProcessors=[],this.installedPlugins=[],this.fileManagers=[]};d.prototype.addPlugins=function(a){if(a)for(var b=0;b<a.length;b++)this.addPlugin(a[b])},d.prototype.addPlugin=function(a){this.installedPlugins.push(a),a.install(this.less,this)},d.prototype.addVisitor=function(a){this.visitors.push(a)},d.prototype.addPreProcessor=function(a,b){var c;for(c=0;c<this.preProcessors.length&&!(this.preProcessors[c].priority>=b);c++);this.preProcessors.splice(c,0,{preProcessor:a,priority:b})},d.prototype.addPostProcessor=function(a,b){var c;for(c=0;c<this.postProcessors.length&&!(this.postProcessors[c].priority>=b);c++);this.postProcessors.splice(c,0,{postProcessor:a,priority:b})},d.prototype.addFileManager=function(a){this.fileManagers.push(a)},d.prototype.getPreProcessors=function(){for(var a=[],b=0;b<this.preProcessors.length;b++)a.push(this.preProcessors[b].preProcessor);return a},d.prototype.getPostProcessors=function(){for(var a=[],b=0;b<this.postProcessors.length;b++)a.push(this.postProcessors[b].postProcessor);return a},d.prototype.getVisitors=function(){return this.visitors},d.prototype.getFileManagers=function(){return this.fileManagers},b.exports=d},{}],40:[function(a,b,c){var d=a("../less-error"),e=a("../tree"),f=b.exports=function(a,b){this.fileInfo=b};f.prototype.eval=function(a,b){var c,f,g={};f={add:function(a,b){g[a]=b},addMultiple:function(a){Object.keys(a).forEach(function(b){g[b]=a[b]})}};try{c=new Function("functions","tree","fileInfo",a),
 c(f,e,this.fileInfo)}catch(h){b(new d({message:"Plugin evaluation error: '"+h.name+": "+h.message.replace(/["]/g,"'")+"'",filename:this.fileInfo.filename}),null)}b(null,{functions:g})}},{"../less-error":32,"../tree":62}],41:[function(a,b,c){var d;b.exports=function(b,c,e){var f=function(b,e,g){if("function"==typeof e&&(g=e,e={}),!g){d||(d="undefined"==typeof Promise?a("promise"):Promise);var h=this;return new d(function(a,c){f.call(h,b,e,function(b,d){b?c(b):a(d)})})}this.parse(b,e,function(a,b,d,e){if(a)return g(a);var f;try{var h=new c(b,d);f=h.toCSS(e)}catch(a){return g(a)}g(null,f)})};return f}},{promise:void 0}],42:[function(a,b,c){b.exports=function(a,b){var c=function(a){this.options=a};return c.prototype.toCSS=function(b,c,d){var e=new a({contentsIgnoredCharsMap:d.contentsIgnoredChars,rootNode:b,contentsMap:d.contents,sourceMapFilename:this.options.sourceMapFilename,sourceMapURL:this.options.sourceMapURL,outputFilename:this.options.sourceMapOutputFilename,sourceMapBasepath:this.options.sourceMapBasepath,sourceMapRootpath:this.options.sourceMapRootpath,outputSourceFiles:this.options.outputSourceFiles,sourceMapGenerator:this.options.sourceMapGenerator,sourceMapFileInline:this.options.sourceMapFileInline}),f=e.toCSS(c);return this.sourceMap=e.sourceMap,this.sourceMapURL=e.sourceMapURL,this.options.sourceMapInputFilename&&(this.sourceMapInputFilename=e.normalizeFilename(this.options.sourceMapInputFilename)),f+this.getCSSAppendage()},c.prototype.getCSSAppendage=function(){var a=this.sourceMapURL;if(this.options.sourceMapFileInline){if(void 0===this.sourceMap)return"";a="data:application/json;base64,"+b.encodeBase64(this.sourceMap)}return a?"/*# sourceMappingURL="+a+" */":""},c.prototype.getExternalSourceMap=function(){return this.sourceMap},c.prototype.setExternalSourceMap=function(a){this.sourceMap=a},c.prototype.isInline=function(){return this.options.sourceMapFileInline},c.prototype.getSourceMapURL=function(){return this.sourceMapURL},c.prototype.getOutputFilename=function(){return this.options.sourceMapOutputFilename},c.prototype.getInputFilename=function(){return this.sourceMapInputFilename},c}},{}],43:[function(a,b,c){b.exports=function(a){var b=function(b){this._css=[],this._rootNode=b.rootNode,this._contentsMap=b.contentsMap,this._contentsIgnoredCharsMap=b.contentsIgnoredCharsMap,b.sourceMapFilename&&(this._sourceMapFilename=b.sourceMapFilename.replace(/\\/g,"/")),this._outputFilename=b.outputFilename,this.sourceMapURL=b.sourceMapURL,b.sourceMapBasepath&&(this._sourceMapBasepath=b.sourceMapBasepath.replace(/\\/g,"/")),b.sourceMapRootpath?(this._sourceMapRootpath=b.sourceMapRootpath.replace(/\\/g,"/"),"/"!==this._sourceMapRootpath.charAt(this._sourceMapRootpath.length-1)&&(this._sourceMapRootpath+="/")):this._sourceMapRootpath="",this._outputSourceFiles=b.outputSourceFiles,this._sourceMapGeneratorConstructor=a.getSourceMapGenerator(),this._lineNumber=0,this._column=0};return b.prototype.normalizeFilename=function(a){return a=a.replace(/\\/g,"/"),this._sourceMapBasepath&&0===a.indexOf(this._sourceMapBasepath)&&(a=a.substring(this._sourceMapBasepath.length),"\\"!==a.charAt(0)&&"/"!==a.charAt(0)||(a=a.substring(1))),(this._sourceMapRootpath||"")+a},b.prototype.add=function(a,b,c,d){if(a){var e,f,g,h,i;if(b){var j=this._contentsMap[b.filename];this._contentsIgnoredCharsMap[b.filename]&&(c-=this._contentsIgnoredCharsMap[b.filename],c<0&&(c=0),j=j.slice(this._contentsIgnoredCharsMap[b.filename])),j=j.substring(0,c),f=j.split("\n"),h=f[f.length-1]}if(e=a.split("\n"),g=e[e.length-1],b)if(d)for(i=0;i<e.length;i++)this._sourceMapGenerator.addMapping({generated:{line:this._lineNumber+i+1,column:0===i?this._column:0},original:{line:f.length+i,column:0===i?h.length:0},source:this.normalizeFilename(b.filename)});else this._sourceMapGenerator.addMapping({generated:{line:this._lineNumber+1,column:this._column},original:{line:f.length,column:h.length},source:this.normalizeFilename(b.filename)});1===e.length?this._column+=g.length:(this._lineNumber+=e.length-1,this._column=g.length),this._css.push(a)}},b.prototype.isEmpty=function(){return 0===this._css.length},b.prototype.toCSS=function(a){if(this._sourceMapGenerator=new this._sourceMapGeneratorConstructor({file:this._outputFilename,sourceRoot:null}),this._outputSourceFiles)for(var b in this._contentsMap)if(this._contentsMap.hasOwnProperty(b)){var c=this._contentsMap[b];this._contentsIgnoredCharsMap[b]&&(c=c.slice(this._contentsIgnoredCharsMap[b])),this._sourceMapGenerator.setSourceContent(this.normalizeFilename(b),c)}if(this._rootNode.genCSS(a,this),this._css.length>0){var d,e=JSON.stringify(this._sourceMapGenerator.toJSON());this.sourceMapURL?d=this.sourceMapURL:this._sourceMapFilename&&(d=this._sourceMapFilename),this.sourceMapURL=d,this.sourceMap=e}return this._css.join("")},b}},{}],44:[function(a,b,c){var d=a("./contexts"),e=a("./visitors"),f=a("./tree");b.exports=function(a,b){b=b||{};var c,g=b.variables,h=new d.Eval(b);"object"!=typeof g||Array.isArray(g)||(g=Object.keys(g).map(function(a){var b=g[a];return b instanceof f.Value||(b instanceof f.Expression||(b=new f.Expression([b])),b=new f.Value([b])),new f.Rule("@"+a,b,(!1),null,0)}),h.frames=[new f.Ruleset(null,g)]);var i,j=[],k=[new e.JoinSelectorVisitor,new e.MarkVisibleSelectorsVisitor((!0)),new e.ExtendVisitor,new e.ToCSSVisitor({compress:Boolean(b.compress)})];if(b.pluginManager){var l=b.pluginManager.getVisitors();for(i=0;i<l.length;i++){var m=l[i];m.isPreEvalVisitor?j.push(m):m.isPreVisitor?k.splice(0,0,m):k.push(m)}}for(i=0;i<j.length;i++)j[i].run(a);for(c=a.eval(h),i=0;i<k.length;i++)k[i].run(c);return c}},{"./contexts":11,"./tree":62,"./visitors":87}],45:[function(a,b,c){var d=a("./node"),e=function(a){this.value=a};e.prototype=new d,e.prototype.type="Alpha",e.prototype.accept=function(a){this.value=a.visit(this.value)},e.prototype.eval=function(a){return this.value.eval?new e(this.value.eval(a)):this},e.prototype.genCSS=function(a,b){b.add("alpha(opacity="),this.value.genCSS?this.value.genCSS(a,b):b.add(this.value),b.add(")")},b.exports=e},{"./node":70}],46:[function(a,b,c){var d=a("./node"),e=function(a,b,c,d,e,f){this.value=a,this.index=b,this.mapLines=d,this.currentFileInfo=c,this.rulesetLike="undefined"!=typeof e&&e,this.allowRoot=!0,this.copyVisibilityInfo(f)};e.prototype=new d,e.prototype.type="Anonymous",e.prototype.eval=function(){return new e(this.value,this.index,this.currentFileInfo,this.mapLines,this.rulesetLike,this.visibilityInfo())},e.prototype.compare=function(a){return a.toCSS&&this.toCSS()===a.toCSS()?0:void 0},e.prototype.isRulesetLike=function(){return this.rulesetLike},e.prototype.genCSS=function(a,b){b.add(this.value,this.currentFileInfo,this.index,this.mapLines)},b.exports=e},{"./node":70}],47:[function(a,b,c){var d=a("./node"),e=function(a,b){this.key=a,this.value=b};e.prototype=new d,e.prototype.type="Assignment",e.prototype.accept=function(a){this.value=a.visit(this.value)},e.prototype.eval=function(a){return this.value.eval?new e(this.key,this.value.eval(a)):this},e.prototype.genCSS=function(a,b){b.add(this.key+"="),this.value.genCSS?this.value.genCSS(a,b):b.add(this.value)},b.exports=e},{"./node":70}],48:[function(a,b,c){var d=a("./node"),e=function(a,b,c){this.key=a,this.op=b,this.value=c};e.prototype=new d,e.prototype.type="Attribute",e.prototype.eval=function(a){return new e(this.key.eval?this.key.eval(a):this.key,this.op,this.value&&this.value.eval?this.value.eval(a):this.value)},e.prototype.genCSS=function(a,b){b.add(this.toCSS(a))},e.prototype.toCSS=function(a){var b=this.key.toCSS?this.key.toCSS(a):this.key;return this.op&&(b+=this.op,b+=this.value.toCSS?this.value.toCSS(a):this.value),"["+b+"]"},b.exports=e},{"./node":70}],49:[function(a,b,c){var d=a("./node"),e=a("../functions/function-caller"),f=function(a,b,c,d){this.name=a,this.args=b,this.index=c,this.currentFileInfo=d};f.prototype=new d,f.prototype.type="Call",f.prototype.accept=function(a){this.args&&(this.args=a.visitArray(this.args))},f.prototype.eval=function(a){var b,c=this.args.map(function(b){return b.eval(a)}),d=new e(this.name,a,this.index,this.currentFileInfo);if(d.isValid()){try{b=d.call(c)}catch(g){throw{type:g.type||"Runtime",message:"error evaluating function `"+this.name+"`"+(g.message?": "+g.message:""),index:this.index,filename:this.currentFileInfo.filename}}if(null!=b)return b.index=this.index,b.currentFileInfo=this.currentFileInfo,b}return new f(this.name,c,this.index,this.currentFileInfo)},f.prototype.genCSS=function(a,b){b.add(this.name+"(",this.currentFileInfo,this.index);for(var c=0;c<this.args.length;c++)this.args[c].genCSS(a,b),c+1<this.args.length&&b.add(", ");b.add(")")},b.exports=f},{"../functions/function-caller":21,"./node":70}],50:[function(a,b,c){function d(a,b){return Math.min(Math.max(a,0),b)}function e(a){return"#"+a.map(function(a){return a=d(Math.round(a),255),(a<16?"0":"")+a.toString(16)}).join("")}var f=a("./node"),g=a("../data/colors"),h=function(a,b,c){this.rgb=Array.isArray(a)?a:6==a.length?a.match(/.{2}/g).map(function(a){return parseInt(a,16)}):a.split("").map(function(a){return parseInt(a+a,16)}),this.alpha="number"==typeof b?b:1,"undefined"!=typeof c&&(this.value=c)};h.prototype=new f,h.prototype.type="Color",h.prototype.luma=function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255;return a=a<=.03928?a/12.92:Math.pow((a+.055)/1.055,2.4),b=b<=.03928?b/12.92:Math.pow((b+.055)/1.055,2.4),c=c<=.03928?c/12.92:Math.pow((c+.055)/1.055,2.4),.2126*a+.7152*b+.0722*c},h.prototype.genCSS=function(a,b){b.add(this.toCSS(a))},h.prototype.toCSS=function(a,b){var c,e,f=a&&a.compress&&!b;if(this.value)return this.value;if(e=this.fround(a,this.alpha),e<1)return"rgba("+this.rgb.map(function(a){return d(Math.round(a),255)}).concat(d(e,1)).join(","+(f?"":" "))+")";if(c=this.toRGB(),f){var g=c.split("");g[1]===g[2]&&g[3]===g[4]&&g[5]===g[6]&&(c="#"+g[1]+g[3]+g[5])}return c},h.prototype.operate=function(a,b,c){for(var d=[],e=this.alpha*(1-c.alpha)+c.alpha,f=0;f<3;f++)d[f]=this._operate(a,b,this.rgb[f],c.rgb[f]);return new h(d,e)},h.prototype.toRGB=function(){return e(this.rgb)},h.prototype.toHSL=function(){var a,b,c=this.rgb[0]/255,d=this.rgb[1]/255,e=this.rgb[2]/255,f=this.alpha,g=Math.max(c,d,e),h=Math.min(c,d,e),i=(g+h)/2,j=g-h;if(g===h)a=b=0;else{switch(b=i>.5?j/(2-g-h):j/(g+h),g){case c:a=(d-e)/j+(d<e?6:0);break;case d:a=(e-c)/j+2;break;case e:a=(c-d)/j+4}a/=6}return{h:360*a,s:b,l:i,a:f}},h.prototype.toHSV=function(){var a,b,c=this.rgb[0]/255,d=this.rgb[1]/255,e=this.rgb[2]/255,f=this.alpha,g=Math.max(c,d,e),h=Math.min(c,d,e),i=g,j=g-h;if(b=0===g?0:j/g,g===h)a=0;else{switch(g){case c:a=(d-e)/j+(d<e?6:0);break;case d:a=(e-c)/j+2;break;case e:a=(c-d)/j+4}a/=6}return{h:360*a,s:b,v:i,a:f}},h.prototype.toARGB=function(){return e([255*this.alpha].concat(this.rgb))},h.prototype.compare=function(a){return a.rgb&&a.rgb[0]===this.rgb[0]&&a.rgb[1]===this.rgb[1]&&a.rgb[2]===this.rgb[2]&&a.alpha===this.alpha?0:void 0},h.fromKeyword=function(a){var b,c=a.toLowerCase();if(g.hasOwnProperty(c)?b=new h(g[c].slice(1)):"transparent"===c&&(b=new h([0,0,0],0)),b)return b.value=a,b},b.exports=h},{"../data/colors":12,"./node":70}],51:[function(a,b,c){var d=a("./node"),e=function(a){" "===a?(this.value=" ",this.emptyOrWhitespace=!0):(this.value=a?a.trim():"",this.emptyOrWhitespace=""===this.value)};e.prototype=new d,e.prototype.type="Combinator";var f={"":!0," ":!0,"|":!0};e.prototype.genCSS=function(a,b){var c=a.compress||f[this.value]?"":" ";b.add(c+this.value+c)},b.exports=e},{"./node":70}],52:[function(a,b,c){var d=a("./node"),e=a("./debug-info"),f=function(a,b,c,d){this.value=a,this.isLineComment=b,this.index=c,this.currentFileInfo=d,this.allowRoot=!0};f.prototype=new d,f.prototype.type="Comment",f.prototype.genCSS=function(a,b){this.debugInfo&&b.add(e(a,this),this.currentFileInfo,this.index),b.add(this.value)},f.prototype.isSilent=function(a){var b=a.compress&&"!"!==this.value[2];return this.isLineComment||b},b.exports=f},{"./debug-info":54,"./node":70}],53:[function(a,b,c){var d=a("./node"),e=function(a,b,c,d,e){this.op=a.trim(),this.lvalue=b,this.rvalue=c,this.index=d,this.negate=e};e.prototype=new d,e.prototype.type="Condition",e.prototype.accept=function(a){this.lvalue=a.visit(this.lvalue),this.rvalue=a.visit(this.rvalue)},e.prototype.eval=function(a){var b=function(a,b,c){switch(a){case"and":return b&&c;case"or":return b||c;default:switch(d.compare(b,c)){case-1:return"<"===a||"=<"===a||"<="===a;case 0:return"="===a||">="===a||"=<"===a||"<="===a;case 1:return">"===a||">="===a;default:return!1}}}(this.op,this.lvalue.eval(a),this.rvalue.eval(a));return this.negate?!b:b},b.exports=e},{"./node":70}],54:[function(a,b,c){var d=function(a,b,c){var e="";if(a.dumpLineNumbers&&!a.compress)switch(a.dumpLineNumbers){case"comments":e=d.asComment(b);break;case"mediaquery":e=d.asMediaQuery(b);break;case"all":e=d.asComment(b)+(c||"")+d.asMediaQuery(b)}return e};d.asComment=function(a){return"/* line "+a.debugInfo.lineNumber+", "+a.debugInfo.fileName+" */\n"},d.asMediaQuery=function(a){var b=a.debugInfo.fileName;return/^[a-z]+:\/\//i.test(b)||(b="file://"+b),"@media -sass-debug-info{filename{font-family:"+b.replace(/([.:\/\\])/g,function(a){return"\\"==a&&(a="/"),"\\"+a})+"}line{font-family:\\00003"+a.debugInfo.lineNumber+"}}\n"},b.exports=d},{}],55:[function(a,b,c){var d=a("./node"),e=a("../contexts"),f=function(a,b){this.ruleset=a,this.frames=b};f.prototype=new d,f.prototype.type="DetachedRuleset",f.prototype.evalFirst=!0,f.prototype.accept=function(a){this.ruleset=a.visit(this.ruleset)},f.prototype.eval=function(a){var b=this.frames||a.frames.slice(0);return new f(this.ruleset,b)},f.prototype.callEval=function(a){return this.ruleset.eval(this.frames?new e.Eval(a,this.frames.concat(a.frames)):a)},b.exports=f},{"../contexts":11,"./node":70}],56:[function(a,b,c){var d=a("./node"),e=a("../data/unit-conversions"),f=a("./unit"),g=a("./color"),h=function(a,b){this.value=parseFloat(a),this.unit=b&&b instanceof f?b:new f(b?[b]:void 0)};h.prototype=new d,h.prototype.type="Dimension",h.prototype.accept=function(a){this.unit=a.visit(this.unit)},h.prototype.eval=function(a){return this},h.prototype.toColor=function(){return new g([this.value,this.value,this.value])},h.prototype.genCSS=function(a,b){if(a&&a.strictUnits&&!this.unit.isSingular())throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());var c=this.fround(a,this.value),d=String(c);if(0!==c&&c<1e-6&&c>-1e-6&&(d=c.toFixed(20).replace(/0+$/,"")),a&&a.compress){if(0===c&&this.unit.isLength())return void b.add(d);c>0&&c<1&&(d=d.substr(1))}b.add(d),this.unit.genCSS(a,b)},h.prototype.operate=function(a,b,c){var d=this._operate(a,b,this.value,c.value),e=this.unit.clone();if("+"===b||"-"===b)if(0===e.numerator.length&&0===e.denominator.length)e=c.unit.clone(),this.unit.backupUnit&&(e.backupUnit=this.unit.backupUnit);else if(0===c.unit.numerator.length&&0===e.denominator.length);else{if(c=c.convertTo(this.unit.usedUnits()),a.strictUnits&&c.unit.toString()!==e.toString())throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '"+e.toString()+"' and '"+c.unit.toString()+"'.");d=this._operate(a,b,this.value,c.value)}else"*"===b?(e.numerator=e.numerator.concat(c.unit.numerator).sort(),e.denominator=e.denominator.concat(c.unit.denominator).sort(),e.cancel()):"/"===b&&(e.numerator=e.numerator.concat(c.unit.denominator).sort(),e.denominator=e.denominator.concat(c.unit.numerator).sort(),e.cancel());return new h(d,e)},h.prototype.compare=function(a){var b,c;if(a instanceof h){if(this.unit.isEmpty()||a.unit.isEmpty())b=this,c=a;else if(b=this.unify(),c=a.unify(),0!==b.unit.compare(c.unit))return;return d.numericCompare(b.value,c.value)}},h.prototype.unify=function(){return this.convertTo({length:"px",duration:"s",angle:"rad"})},h.prototype.convertTo=function(a){var b,c,d,f,g,i=this.value,j=this.unit.clone(),k={};if("string"==typeof a){for(b in e)e[b].hasOwnProperty(a)&&(k={},k[b]=a);a=k}g=function(a,b){return d.hasOwnProperty(a)?(b?i/=d[a]/d[f]:i*=d[a]/d[f],f):a};for(c in a)a.hasOwnProperty(c)&&(f=a[c],d=e[c],j.map(g));return j.cancel(),new h(i,j)},b.exports=h},{"../data/unit-conversions":14,"./color":50,"./node":70,"./unit":79}],57:[function(a,b,c){var d=a("./node"),e=a("./selector"),f=a("./ruleset"),g=function(a,b,c,d,f,g,h,i){var j;if(this.name=a,this.value=b,c)for(Array.isArray(c)?this.rules=c:(this.rules=[c],this.rules[0].selectors=new e([],null,null,this.index,f).createEmptySelectors()),j=0;j<this.rules.length;j++)this.rules[j].allowImports=!0;this.index=d,this.currentFileInfo=f,this.debugInfo=g,this.isRooted=h||!1,this.copyVisibilityInfo(i),this.allowRoot=!0};g.prototype=new d,g.prototype.type="Directive",g.prototype.accept=function(a){var b=this.value,c=this.rules;c&&(this.rules=a.visitArray(c)),b&&(this.value=a.visit(b))},g.prototype.isRulesetLike=function(){return this.rules||!this.isCharset()},g.prototype.isCharset=function(){return"@charset"===this.name},g.prototype.genCSS=function(a,b){var c=this.value,d=this.rules;b.add(this.name,this.currentFileInfo,this.index),c&&(b.add(" "),c.genCSS(a,b)),d?this.outputRuleset(a,b,d):b.add(";")},g.prototype.eval=function(a){var b,c,d=this.value,e=this.rules;return b=a.mediaPath,c=a.mediaBlocks,a.mediaPath=[],a.mediaBlocks=[],d&&(d=d.eval(a)),e&&(e=[e[0].eval(a)],e[0].root=!0),a.mediaPath=b,a.mediaBlocks=c,new g(this.name,d,e,this.index,this.currentFileInfo,this.debugInfo,this.isRooted,this.visibilityInfo())},g.prototype.variable=function(a){if(this.rules)return f.prototype.variable.call(this.rules[0],a)},g.prototype.find=function(){if(this.rules)return f.prototype.find.apply(this.rules[0],arguments)},g.prototype.rulesets=function(){if(this.rules)return f.prototype.rulesets.apply(this.rules[0])},g.prototype.outputRuleset=function(a,b,c){var d,e=c.length;if(a.tabLevel=(0|a.tabLevel)+1,a.compress){for(b.add("{"),d=0;d<e;d++)c[d].genCSS(a,b);return b.add("}"),void a.tabLevel--}var f="\n"+Array(a.tabLevel).join("  "),g=f+"  ";if(e){for(b.add(" {"+g),c[0].genCSS(a,b),d=1;d<e;d++)b.add(g),c[d].genCSS(a,b);b.add(f+"}")}else b.add(" {"+f+"}");a.tabLevel--},b.exports=g},{"./node":70,"./ruleset":76,"./selector":77}],58:[function(a,b,c){var d=a("./node"),e=a("./paren"),f=a("./combinator"),g=function(a,b,c,d,e){this.combinator=a instanceof f?a:new f(a),this.value="string"==typeof b?b.trim():b?b:"",this.index=c,this.currentFileInfo=d,this.copyVisibilityInfo(e)};g.prototype=new d,g.prototype.type="Element",g.prototype.accept=function(a){var b=this.value;this.combinator=a.visit(this.combinator),"object"==typeof b&&(this.value=a.visit(b))},g.prototype.eval=function(a){return new g(this.combinator,this.value.eval?this.value.eval(a):this.value,this.index,this.currentFileInfo,this.visibilityInfo())},g.prototype.clone=function(){return new g(this.combinator,this.value,this.index,this.currentFileInfo,this.visibilityInfo())},g.prototype.genCSS=function(a,b){b.add(this.toCSS(a),this.currentFileInfo,this.index)},g.prototype.toCSS=function(a){a=a||{};var b=this.value,c=a.firstSelector;return b instanceof e&&(a.firstSelector=!0),b=b.toCSS?b.toCSS(a):b,a.firstSelector=c,""===b&&"&"===this.combinator.value.charAt(0)?"":this.combinator.toCSS(a)+b},b.exports=g},{"./combinator":51,"./node":70,"./paren":72}],59:[function(a,b,c){var d=a("./node"),e=a("./paren"),f=a("./comment"),g=function(a){if(this.value=a,!a)throw new Error("Expression requires an array parameter")};g.prototype=new d,g.prototype.type="Expression",g.prototype.accept=function(a){this.value=a.visitArray(this.value)},g.prototype.eval=function(a){var b,c=this.parens&&!this.parensInOp,d=!1;return c&&a.inParenthesis(),this.value.length>1?b=new g(this.value.map(function(b){return b.eval(a)})):1===this.value.length?(this.value[0].parens&&!this.value[0].parensInOp&&(d=!0),b=this.value[0].eval(a)):b=this,c&&a.outOfParenthesis(),this.parens&&this.parensInOp&&!a.isMathOn()&&!d&&(b=new e(b)),b},g.prototype.genCSS=function(a,b){for(var c=0;c<this.value.length;c++)this.value[c].genCSS(a,b),c+1<this.value.length&&b.add(" ")},g.prototype.throwAwayComments=function(){this.value=this.value.filter(function(a){return!(a instanceof f)})},b.exports=g},{"./comment":52,"./node":70,"./paren":72}],60:[function(a,b,c){var d=a("./node"),e=a("./selector"),f=function g(a,b,c,d,e){switch(this.selector=a,this.option=b,this.index=c,this.object_id=g.next_id++,this.parent_ids=[this.object_id],this.currentFileInfo=d||{},this.copyVisibilityInfo(e),this.allowRoot=!0,b){case"all":this.allowBefore=!0,this.allowAfter=!0;break;default:this.allowBefore=!1,this.allowAfter=!1}};f.next_id=0,f.prototype=new d,f.prototype.type="Extend",f.prototype.accept=function(a){this.selector=a.visit(this.selector)},f.prototype.eval=function(a){return new f(this.selector.eval(a),this.option,this.index,this.currentFileInfo,this.visibilityInfo())},f.prototype.clone=function(a){return new f(this.selector,this.option,this.index,this.currentFileInfo,this.visibilityInfo())},f.prototype.findSelfSelectors=function(a){var b,c,d=[];for(b=0;b<a.length;b++)c=a[b].elements,b>0&&c.length&&""===c[0].combinator.value&&(c[0].combinator.value=" "),d=d.concat(a[b].elements);this.selfSelectors=[new e(d)],this.selfSelectors[0].copyVisibilityInfo(this.visibilityInfo())},b.exports=f},{"./node":70,"./selector":77}],61:[function(a,b,c){var d=a("./node"),e=a("./media"),f=a("./url"),g=a("./quoted"),h=a("./ruleset"),i=a("./anonymous"),j=function(a,b,c,d,e,f){if(this.options=c,this.index=d,this.path=a,this.features=b,this.currentFileInfo=e,this.allowRoot=!0,void 0!==this.options.less||this.options.inline)this.css=!this.options.less||this.options.inline;else{var g=this.getPath();g&&/[#\.\&\?\/]css([\?;].*)?$/.test(g)&&(this.css=!0)}this.copyVisibilityInfo(f)};j.prototype=new d,j.prototype.type="Import",j.prototype.accept=function(a){this.features&&(this.features=a.visit(this.features)),this.path=a.visit(this.path),this.options.plugin||this.options.inline||!this.root||(this.root=a.visit(this.root))},j.prototype.genCSS=function(a,b){this.css&&void 0===this.path.currentFileInfo.reference&&(b.add("@import ",this.currentFileInfo,this.index),this.path.genCSS(a,b),this.features&&(b.add(" "),this.features.genCSS(a,b)),b.add(";"))},j.prototype.getPath=function(){return this.path instanceof f?this.path.value.value:this.path.value},j.prototype.isVariableImport=function(){var a=this.path;return a instanceof f&&(a=a.value),!(a instanceof g)||a.containsVariables()},j.prototype.evalForImport=function(a){var b=this.path;return b instanceof f&&(b=b.value),new j(b.eval(a),this.features,this.options,this.index,this.currentFileInfo,this.visibilityInfo())},j.prototype.evalPath=function(a){var b=this.path.eval(a),c=this.currentFileInfo&&this.currentFileInfo.rootpath;if(!(b instanceof f)){if(c){var d=b.value;d&&a.isPathRelative(d)&&(b.value=c+d)}b.value=a.normalizePath(b.value)}return b},j.prototype.eval=function(a){var b=this.doEval(a);return(this.options.reference||this.blocksVisibility())&&(b.length||0===b.length?b.forEach(function(a){a.addVisibilityBlock()}):b.addVisibilityBlock()),b},j.prototype.doEval=function(a){var b,c,d=this.features&&this.features.eval(a);if(this.options.plugin)return c=a.frames[0]&&a.frames[0].functionRegistry,c&&this.root&&this.root.functions&&c.addMultiple(this.root.functions),[];if(this.skip&&("function"==typeof this.skip&&(this.skip=this.skip()),this.skip))return[];if(this.options.inline){var f=new i(this.root,0,{filename:this.importedFilename,reference:this.path.currentFileInfo&&this.path.currentFileInfo.reference},(!0),(!0));return this.features?new e([f],this.features.value):[f]}if(this.css){var g=new j(this.evalPath(a),d,this.options,this.index);if(!g.css&&this.error)throw this.error;return g}return b=new h(null,this.root.rules.slice(0)),b.evalImports(a),this.features?new e(b.rules,this.features.value):b.rules},b.exports=j},{"./anonymous":46,"./media":66,"./node":70,"./quoted":73,"./ruleset":76,"./url":80}],62:[function(a,b,c){var d={};d.Node=a("./node"),d.Alpha=a("./alpha"),d.Color=a("./color"),d.Directive=a("./directive"),d.DetachedRuleset=a("./detached-ruleset"),d.Operation=a("./operation"),d.Dimension=a("./dimension"),d.Unit=a("./unit"),d.Keyword=a("./keyword"),d.Variable=a("./variable"),d.Ruleset=a("./ruleset"),d.Element=a("./element"),d.Attribute=a("./attribute"),d.Combinator=a("./combinator"),d.Selector=a("./selector"),d.Quoted=a("./quoted"),d.Expression=a("./expression"),d.Rule=a("./rule"),d.Call=a("./call"),d.URL=a("./url"),d.Import=a("./import"),d.mixin={Call:a("./mixin-call"),Definition:a("./mixin-definition")},d.Comment=a("./comment"),d.Anonymous=a("./anonymous"),d.Value=a("./value"),d.JavaScript=a("./javascript"),d.Assignment=a("./assignment"),d.Condition=a("./condition"),d.Paren=a("./paren"),d.Media=a("./media"),d.UnicodeDescriptor=a("./unicode-descriptor"),d.Negative=a("./negative"),d.Extend=a("./extend"),d.RulesetCall=a("./ruleset-call"),b.exports=d},{"./alpha":45,"./anonymous":46,"./assignment":47,"./attribute":48,"./call":49,"./color":50,"./combinator":51,"./comment":52,"./condition":53,"./detached-ruleset":55,"./dimension":56,"./directive":57,"./element":58,"./expression":59,"./extend":60,"./import":61,"./javascript":63,"./keyword":65,"./media":66,"./mixin-call":67,"./mixin-definition":68,"./negative":69,"./node":70,"./operation":71,"./paren":72,"./quoted":73,"./rule":74,"./ruleset":76,"./ruleset-call":75,"./selector":77,"./unicode-descriptor":78,"./unit":79,"./url":80,"./value":81,"./variable":82}],63:[function(a,b,c){var d=a("./js-eval-node"),e=a("./dimension"),f=a("./quoted"),g=a("./anonymous"),h=function(a,b,c,d){this.escaped=b,this.expression=a,this.index=c,this.currentFileInfo=d};h.prototype=new d,h.prototype.type="JavaScript",h.prototype.eval=function(a){var b=this.evaluateJavaScript(this.expression,a);return"number"==typeof b?new e(b):"string"==typeof b?new f('"'+b+'"',b,this.escaped,this.index):new g(Array.isArray(b)?b.join(", "):b)},b.exports=h},{"./anonymous":46,"./dimension":56,"./js-eval-node":64,"./quoted":73}],64:[function(a,b,c){var d=a("./node"),e=a("./variable"),f=function(){};f.prototype=new d,f.prototype.evaluateJavaScript=function(a,b){var c,d=this,f={};if(void 0!==b.javascriptEnabled&&!b.javascriptEnabled)throw{message:"You are using JavaScript, which has been disabled.",filename:this.currentFileInfo.filename,index:this.index};a=a.replace(/@\{([\w-]+)\}/g,function(a,c){return d.jsify(new e("@"+c,d.index,d.currentFileInfo).eval(b))});try{a=new Function("return ("+a+")")}catch(g){throw{message:"JavaScript evaluation error: "+g.message+" from `"+a+"`",filename:this.currentFileInfo.filename,index:this.index}}var h=b.frames[0].variables();for(var i in h)h.hasOwnProperty(i)&&(f[i.slice(1)]={value:h[i].value,toJS:function(){return this.value.eval(b).toCSS()}});try{c=a.call(f)}catch(g){throw{message:"JavaScript evaluation error: '"+g.name+": "+g.message.replace(/["]/g,"'")+"'",filename:this.currentFileInfo.filename,index:this.index}}return c},f.prototype.jsify=function(a){return Array.isArray(a.value)&&a.value.length>1?"["+a.value.map(function(a){return a.toCSS()}).join(", ")+"]":a.toCSS()},b.exports=f},{"./node":70,"./variable":82}],65:[function(a,b,c){var d=a("./node"),e=function(a){this.value=a};e.prototype=new d,e.prototype.type="Keyword",e.prototype.genCSS=function(a,b){if("%"===this.value)throw{type:"Syntax",message:"Invalid % without number"};b.add(this.value)},e.True=new e("true"),e.False=new e("false"),b.exports=e},{"./node":70}],66:[function(a,b,c){var d=a("./ruleset"),e=a("./value"),f=a("./selector"),g=a("./anonymous"),h=a("./expression"),i=a("./directive"),j=function(a,b,c,g,h){this.index=c,this.currentFileInfo=g;var i=new f([],null,null,this.index,this.currentFileInfo).createEmptySelectors();this.features=new e(b),this.rules=[new d(i,a)],this.rules[0].allowImports=!0,this.copyVisibilityInfo(h),this.allowRoot=!0};j.prototype=new i,j.prototype.type="Media",j.prototype.isRulesetLike=!0,j.prototype.accept=function(a){this.features&&(this.features=a.visit(this.features)),this.rules&&(this.rules=a.visitArray(this.rules))},j.prototype.genCSS=function(a,b){b.add("@media ",this.currentFileInfo,this.index),this.features.genCSS(a,b),this.outputRuleset(a,b,this.rules)},j.prototype.eval=function(a){a.mediaBlocks||(a.mediaBlocks=[],a.mediaPath=[]);var b=new j(null,[],this.index,this.currentFileInfo,this.visibilityInfo());this.debugInfo&&(this.rules[0].debugInfo=this.debugInfo,b.debugInfo=this.debugInfo);var c=!1;a.strictMath||(c=!0,a.strictMath=!0);try{b.features=this.features.eval(a)}finally{c&&(a.strictMath=!1)}return a.mediaPath.push(b),a.mediaBlocks.push(b),this.rules[0].functionRegistry=a.frames[0].functionRegistry.inherit(),a.frames.unshift(this.rules[0]),b.rules=[this.rules[0].eval(a)],a.frames.shift(),a.mediaPath.pop(),0===a.mediaPath.length?b.evalTop(a):b.evalNested(a)},j.prototype.evalTop=function(a){var b=this;if(a.mediaBlocks.length>1){var c=new f([],null,null,this.index,this.currentFileInfo).createEmptySelectors();b=new d(c,a.mediaBlocks),b.multiMedia=!0,b.copyVisibilityInfo(this.visibilityInfo())}return delete a.mediaBlocks,delete a.mediaPath,b},j.prototype.evalNested=function(a){var b,c,f=a.mediaPath.concat([this]);for(b=0;b<f.length;b++)c=f[b].features instanceof e?f[b].features.value:f[b].features,f[b]=Array.isArray(c)?c:[c];return this.features=new e(this.permute(f).map(function(a){for(a=a.map(function(a){return a.toCSS?a:new g(a)}),b=a.length-1;b>0;b--)a.splice(b,0,new g("and"));return new h(a)})),new d([],[])},j.prototype.permute=function(a){if(0===a.length)return[];if(1===a.length)return a[0];for(var b=[],c=this.permute(a.slice(1)),d=0;d<c.length;d++)for(var e=0;e<a[0].length;e++)b.push([a[0][e]].concat(c[d]));return b},j.prototype.bubbleSelectors=function(a){a&&(this.rules=[new d(a.slice(0),[this.rules[0]])])},b.exports=j},{"./anonymous":46,"./directive":57,"./expression":59,"./ruleset":76,"./selector":77,"./value":81}],67:[function(a,b,c){var d=a("./node"),e=a("./selector"),f=a("./mixin-definition"),g=a("../functions/default"),h=function(a,b,c,d,f){this.selector=new e(a),this.arguments=b||[],this.index=c,this.currentFileInfo=d,this.important=f,this.allowRoot=!0};h.prototype=new d,h.prototype.type="MixinCall",h.prototype.accept=function(a){this.selector&&(this.selector=a.visit(this.selector)),this.arguments.length&&(this.arguments=a.visitArray(this.arguments))},h.prototype.eval=function(a){function b(b,c){var d,e,f;for(d=0;d<2;d++){for(x[d]=!0,g.value(d),e=0;e<c.length&&x[d];e++)f=c[e],f.matchCondition&&(x[d]=x[d]&&f.matchCondition(null,a));b.matchCondition&&(x[d]=x[d]&&b.matchCondition(t,a))}return x[0]||x[1]?x[0]!=x[1]?x[1]?A:B:z:y}var c,d,e,h,i,j,k,l,m,n,o,p,q,r,s,t=[],u=[],v=!1,w=[],x=[],y=-1,z=0,A=1,B=2;for(j=0;j<this.arguments.length;j++)if(h=this.arguments[j],i=h.value.eval(a),h.expand&&Array.isArray(i.value))for(i=i.value,k=0;k<i.length;k++)t.push({value:i[k]});else t.push({name:h.name,value:i});for(s=function(b){return b.matchArgs(null,a)},j=0;j<a.frames.length;j++)if((c=a.frames[j].find(this.selector,null,s)).length>0){for(n=!0,k=0;k<c.length;k++){for(d=c[k].rule,e=c[k].path,m=!1,l=0;l<a.frames.length;l++)if(!(d instanceof f)&&d===(a.frames[l].originalRuleset||a.frames[l])){m=!0;break}m||d.matchArgs(t,a)&&(o={mixin:d,group:b(d,e)},o.group!==y&&w.push(o),v=!0)}for(g.reset(),q=[0,0,0],k=0;k<w.length;k++)q[w[k].group]++;if(q[z]>0)p=B;else if(p=A,q[A]+q[B]>1)throw{type:"Runtime",message:"Ambiguous use of `default()` found when matching for `"+this.format(t)+"`",index:this.index,filename:this.currentFileInfo.filename};for(k=0;k<w.length;k++)if(o=w[k].group,o===z||o===p)try{d=w[k].mixin,d instanceof f||(r=d.originalRuleset||d,d=new f("",[],d.rules,null,(!1),null,r.visibilityInfo()),d.originalRuleset=r);var C=d.evalCall(a,t,this.important).rules;this._setVisibilityToReplacement(C),Array.prototype.push.apply(u,C)}catch(D){throw{message:D.message,index:this.index,filename:this.currentFileInfo.filename,
 stack:D.stack}}if(v)return u}throw n?{type:"Runtime",message:"No matching definition was found for `"+this.format(t)+"`",index:this.index,filename:this.currentFileInfo.filename}:{type:"Name",message:this.selector.toCSS().trim()+" is undefined",index:this.index,filename:this.currentFileInfo.filename}},h.prototype._setVisibilityToReplacement=function(a){var b,c;if(this.blocksVisibility())for(b=0;b<a.length;b++)c=a[b],c.addVisibilityBlock()},h.prototype.format=function(a){return this.selector.toCSS().trim()+"("+(a?a.map(function(a){var b="";return a.name&&(b+=a.name+":"),b+=a.value.toCSS?a.value.toCSS():"???"}).join(", "):"")+")"},b.exports=h},{"../functions/default":20,"./mixin-definition":68,"./node":70,"./selector":77}],68:[function(a,b,c){var d=a("./selector"),e=a("./element"),f=a("./ruleset"),g=a("./rule"),h=a("./expression"),i=a("../contexts"),j=function(a,b,c,f,g,h,i){this.name=a,this.selectors=[new d([new e(null,a,this.index,this.currentFileInfo)])],this.params=b,this.condition=f,this.variadic=g,this.arity=b.length,this.rules=c,this._lookups={};var j=[];this.required=b.reduce(function(a,b){return!b.name||b.name&&!b.value?a+1:(j.push(b.name),a)},0),this.optionalParameters=j,this.frames=h,this.copyVisibilityInfo(i),this.allowRoot=!0};j.prototype=new f,j.prototype.type="MixinDefinition",j.prototype.evalFirst=!0,j.prototype.accept=function(a){this.params&&this.params.length&&(this.params=a.visitArray(this.params)),this.rules=a.visitArray(this.rules),this.condition&&(this.condition=a.visit(this.condition))},j.prototype.evalParams=function(a,b,c,d){var e,j,k,l,m,n,o,p,q=new f(null,null),r=this.params.slice(0),s=0;if(b.frames&&b.frames[0]&&b.frames[0].functionRegistry&&(q.functionRegistry=b.frames[0].functionRegistry.inherit()),b=new i.Eval(b,[q].concat(b.frames)),c)for(c=c.slice(0),s=c.length,k=0;k<s;k++)if(j=c[k],n=j&&j.name){for(o=!1,l=0;l<r.length;l++)if(!d[l]&&n===r[l].name){d[l]=j.value.eval(a),q.prependRule(new g(n,j.value.eval(a))),o=!0;break}if(o){c.splice(k,1),k--;continue}throw{type:"Runtime",message:"Named argument for "+this.name+" "+c[k].name+" not found"}}for(p=0,k=0;k<r.length;k++)if(!d[k]){if(j=c&&c[p],n=r[k].name)if(r[k].variadic){for(e=[],l=p;l<s;l++)e.push(c[l].value.eval(a));q.prependRule(new g(n,new h(e).eval(a)))}else{if(m=j&&j.value)m=m.eval(a);else{if(!r[k].value)throw{type:"Runtime",message:"wrong number of arguments for "+this.name+" ("+s+" for "+this.arity+")"};m=r[k].value.eval(b),q.resetCache()}q.prependRule(new g(n,m)),d[k]=m}if(r[k].variadic&&c)for(l=p;l<s;l++)d[l]=c[l].value.eval(a);p++}return q},j.prototype.makeImportant=function(){var a=this.rules?this.rules.map(function(a){return a.makeImportant?a.makeImportant(!0):a}):this.rules,b=new j(this.name,this.params,a,this.condition,this.variadic,this.frames);return b},j.prototype.eval=function(a){return new j(this.name,this.params,this.rules,this.condition,this.variadic,this.frames||a.frames.slice(0))},j.prototype.evalCall=function(a,b,c){var d,e,j=[],k=this.frames?this.frames.concat(a.frames):a.frames,l=this.evalParams(a,new i.Eval(a,k),b,j);return l.prependRule(new g("@arguments",new h(j).eval(a))),d=this.rules.slice(0),e=new f(null,d),e.originalRuleset=this,e=e.eval(new i.Eval(a,[this,l].concat(k))),c&&(e=e.makeImportant()),e},j.prototype.matchCondition=function(a,b){return!(this.condition&&!this.condition.eval(new i.Eval(b,[this.evalParams(b,new i.Eval(b,this.frames?this.frames.concat(b.frames):b.frames),a,[])].concat(this.frames||[]).concat(b.frames))))},j.prototype.matchArgs=function(a,b){var c,d=a&&a.length||0,e=this.optionalParameters,f=a?a.reduce(function(a,b){return e.indexOf(b.name)<0?a+1:a},0):0;if(this.variadic){if(f<this.required-1)return!1}else{if(f<this.required)return!1;if(d>this.params.length)return!1}c=Math.min(f,this.arity);for(var g=0;g<c;g++)if(!this.params[g].name&&!this.params[g].variadic&&a[g].value.eval(b).toCSS()!=this.params[g].value.eval(b).toCSS())return!1;return!0},b.exports=j},{"../contexts":11,"./element":58,"./expression":59,"./rule":74,"./ruleset":76,"./selector":77}],69:[function(a,b,c){var d=a("./node"),e=a("./operation"),f=a("./dimension"),g=function(a){this.value=a};g.prototype=new d,g.prototype.type="Negative",g.prototype.genCSS=function(a,b){b.add("-"),this.value.genCSS(a,b)},g.prototype.eval=function(a){return a.isMathOn()?new e("*",[new f((-1)),this.value]).eval(a):new g(this.value.eval(a))},b.exports=g},{"./dimension":56,"./node":70,"./operation":71}],70:[function(a,b,c){var d=function(){};d.prototype.toCSS=function(a){var b=[];return this.genCSS(a,{add:function(a,c,d){b.push(a)},isEmpty:function(){return 0===b.length}}),b.join("")},d.prototype.genCSS=function(a,b){b.add(this.value)},d.prototype.accept=function(a){this.value=a.visit(this.value)},d.prototype.eval=function(){return this},d.prototype._operate=function(a,b,c,d){switch(b){case"+":return c+d;case"-":return c-d;case"*":return c*d;case"/":return c/d}},d.prototype.fround=function(a,b){var c=a&&a.numPrecision;return null==c?b:Number((b+2e-16).toFixed(c))},d.compare=function(a,b){if(a.compare&&"Quoted"!==b.type&&"Anonymous"!==b.type)return a.compare(b);if(b.compare)return-b.compare(a);if(a.type===b.type){if(a=a.value,b=b.value,!Array.isArray(a))return a===b?0:void 0;if(a.length===b.length){for(var c=0;c<a.length;c++)if(0!==d.compare(a[c],b[c]))return;return 0}}},d.numericCompare=function(a,b){return a<b?-1:a===b?0:a>b?1:void 0},d.prototype.blocksVisibility=function(){return null==this.visibilityBlocks&&(this.visibilityBlocks=0),0!==this.visibilityBlocks},d.prototype.addVisibilityBlock=function(){null==this.visibilityBlocks&&(this.visibilityBlocks=0),this.visibilityBlocks=this.visibilityBlocks+1},d.prototype.removeVisibilityBlock=function(){null==this.visibilityBlocks&&(this.visibilityBlocks=0),this.visibilityBlocks=this.visibilityBlocks-1},d.prototype.ensureVisibility=function(){this.nodeVisible=!0},d.prototype.ensureInvisibility=function(){this.nodeVisible=!1},d.prototype.isVisible=function(){return this.nodeVisible},d.prototype.visibilityInfo=function(){return{visibilityBlocks:this.visibilityBlocks,nodeVisible:this.nodeVisible}},d.prototype.copyVisibilityInfo=function(a){a&&(this.visibilityBlocks=a.visibilityBlocks,this.nodeVisible=a.nodeVisible)},b.exports=d},{}],71:[function(a,b,c){var d=a("./node"),e=a("./color"),f=a("./dimension"),g=function(a,b,c){this.op=a.trim(),this.operands=b,this.isSpaced=c};g.prototype=new d,g.prototype.type="Operation",g.prototype.accept=function(a){this.operands=a.visit(this.operands)},g.prototype.eval=function(a){var b=this.operands[0].eval(a),c=this.operands[1].eval(a);if(a.isMathOn()){if(b instanceof f&&c instanceof e&&(b=b.toColor()),c instanceof f&&b instanceof e&&(c=c.toColor()),!b.operate)throw{type:"Operation",message:"Operation on an invalid type"};return b.operate(a,this.op,c)}return new g(this.op,[b,c],this.isSpaced)},g.prototype.genCSS=function(a,b){this.operands[0].genCSS(a,b),this.isSpaced&&b.add(" "),b.add(this.op),this.isSpaced&&b.add(" "),this.operands[1].genCSS(a,b)},b.exports=g},{"./color":50,"./dimension":56,"./node":70}],72:[function(a,b,c){var d=a("./node"),e=function(a){this.value=a};e.prototype=new d,e.prototype.type="Paren",e.prototype.genCSS=function(a,b){b.add("("),this.value.genCSS(a,b),b.add(")")},e.prototype.eval=function(a){return new e(this.value.eval(a))},b.exports=e},{"./node":70}],73:[function(a,b,c){var d=a("./node"),e=a("./js-eval-node"),f=a("./variable"),g=function(a,b,c,d,e){this.escaped=null==c||c,this.value=b||"",this.quote=a.charAt(0),this.index=d,this.currentFileInfo=e};g.prototype=new e,g.prototype.type="Quoted",g.prototype.genCSS=function(a,b){this.escaped||b.add(this.quote,this.currentFileInfo,this.index),b.add(this.value),this.escaped||b.add(this.quote)},g.prototype.containsVariables=function(){return this.value.match(/(`([^`]+)`)|@\{([\w-]+)\}/)},g.prototype.eval=function(a){function b(a,b,c){var d=a;do a=d,d=a.replace(b,c);while(a!==d);return d}var c=this,d=this.value,e=function(b,d){return String(c.evaluateJavaScript(d,a))},h=function(b,d){var e=new f("@"+d,c.index,c.currentFileInfo).eval(a,!0);return e instanceof g?e.value:e.toCSS()};return d=b(d,/`([^`]+)`/g,e),d=b(d,/@\{([\w-]+)\}/g,h),new g(this.quote+d+this.quote,d,this.escaped,this.index,this.currentFileInfo)},g.prototype.compare=function(a){return"Quoted"!==a.type||this.escaped||a.escaped?a.toCSS&&this.toCSS()===a.toCSS()?0:void 0:d.numericCompare(this.value,a.value)},b.exports=g},{"./js-eval-node":64,"./node":70,"./variable":82}],74:[function(a,b,c){function d(a,b){var c,d="",e=b.length,f={add:function(a){d+=a}};for(c=0;c<e;c++)b[c].eval(a).genCSS(a,f);return d}var e=a("./node"),f=a("./value"),g=a("./keyword"),h=function(a,b,c,d,g,h,i,j){this.name=a,this.value=b instanceof e?b:new f([b]),this.important=c?" "+c.trim():"",this.merge=d,this.index=g,this.currentFileInfo=h,this.inline=i||!1,this.variable=void 0!==j?j:a.charAt&&"@"===a.charAt(0),this.allowRoot=!0};h.prototype=new e,h.prototype.type="Rule",h.prototype.genCSS=function(a,b){b.add(this.name+(a.compress?":":": "),this.currentFileInfo,this.index);try{this.value.genCSS(a,b)}catch(c){throw c.index=this.index,c.filename=this.currentFileInfo.filename,c}b.add(this.important+(this.inline||a.lastRule&&a.compress?"":";"),this.currentFileInfo,this.index)},h.prototype.eval=function(a){var b,c=!1,e=this.name,f=this.variable;"string"!=typeof e&&(e=1===e.length&&e[0]instanceof g?e[0].value:d(a,e),f=!1),"font"!==e||a.strictMath||(c=!0,a.strictMath=!0);try{if(a.importantScope.push({}),b=this.value.eval(a),!this.variable&&"DetachedRuleset"===b.type)throw{message:"Rulesets cannot be evaluated on a property.",index:this.index,filename:this.currentFileInfo.filename};var i=this.important,j=a.importantScope.pop();return!i&&j.important&&(i=j.important),new h(e,b,i,this.merge,this.index,this.currentFileInfo,this.inline,f)}catch(k){throw"number"!=typeof k.index&&(k.index=this.index,k.filename=this.currentFileInfo.filename),k}finally{c&&(a.strictMath=!1)}},h.prototype.makeImportant=function(){return new h(this.name,this.value,"!important",this.merge,this.index,this.currentFileInfo,this.inline)},b.exports=h},{"./keyword":65,"./node":70,"./value":81}],75:[function(a,b,c){var d=a("./node"),e=a("./variable"),f=function(a){this.variable=a,this.allowRoot=!0};f.prototype=new d,f.prototype.type="RulesetCall",f.prototype.eval=function(a){var b=new e(this.variable).eval(a);return b.callEval(a)},b.exports=f},{"./node":70,"./variable":82}],76:[function(a,b,c){var d=a("./node"),e=a("./rule"),f=a("./selector"),g=a("./element"),h=a("./paren"),i=a("../contexts"),j=a("../functions/function-registry"),k=a("../functions/default"),l=a("./debug-info"),m=function(a,b,c,d){this.selectors=a,this.rules=b,this._lookups={},this.strictImports=c,this.copyVisibilityInfo(d),this.allowRoot=!0};m.prototype=new d,m.prototype.type="Ruleset",m.prototype.isRuleset=!0,m.prototype.isRulesetLike=!0,m.prototype.accept=function(a){this.paths?this.paths=a.visitArray(this.paths,!0):this.selectors&&(this.selectors=a.visitArray(this.selectors)),this.rules&&this.rules.length&&(this.rules=a.visitArray(this.rules))},m.prototype.eval=function(a){var b,c,d,f,g=this.selectors,h=!1;if(g&&(c=g.length)){for(b=[],k.error({type:"Syntax",message:"it is currently only allowed in parametric mixin guards,"}),f=0;f<c;f++)d=g[f].eval(a),b.push(d),d.evaldCondition&&(h=!0);k.reset()}else h=!0;var i,l,n=this.rules?this.rules.slice(0):null,o=new m(b,n,this.strictImports,this.visibilityInfo());o.originalRuleset=this,o.root=this.root,o.firstRoot=this.firstRoot,o.allowImports=this.allowImports,this.debugInfo&&(o.debugInfo=this.debugInfo),h||(n.length=0),o.functionRegistry=function(a){for(var b,c=0,d=a.length;c!==d;++c)if(b=a[c].functionRegistry)return b;return j}(a.frames).inherit();var p=a.frames;p.unshift(o);var q=a.selectors;q||(a.selectors=q=[]),q.unshift(this.selectors),(o.root||o.allowImports||!o.strictImports)&&o.evalImports(a);var r=o.rules,s=r?r.length:0;for(f=0;f<s;f++)r[f].evalFirst&&(r[f]=r[f].eval(a));var t=a.mediaBlocks&&a.mediaBlocks.length||0;for(f=0;f<s;f++)"MixinCall"===r[f].type?(n=r[f].eval(a).filter(function(a){return!(a instanceof e&&a.variable)||!o.variable(a.name)}),r.splice.apply(r,[f,1].concat(n)),s+=n.length-1,f+=n.length-1,o.resetCache()):"RulesetCall"===r[f].type&&(n=r[f].eval(a).rules.filter(function(a){return!(a instanceof e&&a.variable)}),r.splice.apply(r,[f,1].concat(n)),s+=n.length-1,f+=n.length-1,o.resetCache());for(f=0;f<r.length;f++)i=r[f],i.evalFirst||(r[f]=i=i.eval?i.eval(a):i);for(f=0;f<r.length;f++)if(i=r[f],i instanceof m&&i.selectors&&1===i.selectors.length&&i.selectors[0].isJustParentSelector()){r.splice(f--,1);for(var u=0;u<i.rules.length;u++)l=i.rules[u],l.copyVisibilityInfo(i.visibilityInfo()),l instanceof e&&l.variable||r.splice(++f,0,l)}if(p.shift(),q.shift(),a.mediaBlocks)for(f=t;f<a.mediaBlocks.length;f++)a.mediaBlocks[f].bubbleSelectors(b);return o},m.prototype.evalImports=function(a){var b,c,d=this.rules;if(d)for(b=0;b<d.length;b++)"Import"===d[b].type&&(c=d[b].eval(a),c&&(c.length||0===c.length)?(d.splice.apply(d,[b,1].concat(c)),b+=c.length-1):d.splice(b,1,c),this.resetCache())},m.prototype.makeImportant=function(){var a=new m(this.selectors,this.rules.map(function(a){return a.makeImportant?a.makeImportant():a}),this.strictImports,this.visibilityInfo());return a},m.prototype.matchArgs=function(a){return!a||0===a.length},m.prototype.matchCondition=function(a,b){var c=this.selectors[this.selectors.length-1];return!!c.evaldCondition&&!(c.condition&&!c.condition.eval(new i.Eval(b,b.frames)))},m.prototype.resetCache=function(){this._rulesets=null,this._variables=null,this._lookups={}},m.prototype.variables=function(){return this._variables||(this._variables=this.rules?this.rules.reduce(function(a,b){if(b instanceof e&&b.variable===!0&&(a[b.name]=b),"Import"===b.type&&b.root&&b.root.variables){var c=b.root.variables();for(var d in c)c.hasOwnProperty(d)&&(a[d]=c[d])}return a},{}):{}),this._variables},m.prototype.variable=function(a){return this.variables()[a]},m.prototype.rulesets=function(){if(!this.rules)return[];var a,b,c=[],d=this.rules,e=d.length;for(a=0;a<e;a++)b=d[a],b.isRuleset&&c.push(b);return c},m.prototype.prependRule=function(a){var b=this.rules;b?b.unshift(a):this.rules=[a]},m.prototype.find=function(a,b,c){b=b||this;var d,e,g=[],h=a.toCSS();return h in this._lookups?this._lookups[h]:(this.rulesets().forEach(function(h){if(h!==b)for(var i=0;i<h.selectors.length;i++)if(d=a.match(h.selectors[i])){if(a.elements.length>d){if(!c||c(h)){e=h.find(new f(a.elements.slice(d)),b,c);for(var j=0;j<e.length;++j)e[j].path.push(h);Array.prototype.push.apply(g,e)}}else g.push({rule:h,path:[]});break}}),this._lookups[h]=g,g)},m.prototype.genCSS=function(a,b){function c(a){return"boolean"==typeof a.isRulesetLike?a.isRulesetLike:"function"==typeof a.isRulesetLike&&a.isRulesetLike()}var d,e,f,g,h,i=[],j=[];a.tabLevel=a.tabLevel||0,this.root||a.tabLevel++;var k,m=a.compress?"":Array(a.tabLevel+1).join("  "),n=a.compress?"":Array(a.tabLevel).join("  "),o=0,p=0;for(d=0;d<this.rules.length;d++)g=this.rules[d],"Comment"===g.type?(p===d&&p++,j.push(g)):g.isCharset&&g.isCharset()?(j.splice(o,0,g),o++,p++):"Import"===g.type?(j.splice(p,0,g),p++):j.push(g);if(j=i.concat(j),!this.root){f=l(a,this,n),f&&(b.add(f),b.add(n));var q,r=this.paths,s=r.length;for(k=a.compress?",":",\n"+n,d=0;d<s;d++)if(h=r[d],q=h.length)for(d>0&&b.add(k),a.firstSelector=!0,h[0].genCSS(a,b),a.firstSelector=!1,e=1;e<q;e++)h[e].genCSS(a,b);b.add((a.compress?"{":" {\n")+m)}for(d=0;d<j.length;d++){g=j[d],d+1===j.length&&(a.lastRule=!0);var t=a.lastRule;c(g)&&(a.lastRule=!1),g.genCSS?g.genCSS(a,b):g.value&&b.add(g.value.toString()),a.lastRule=t,a.lastRule?a.lastRule=!1:b.add(a.compress?"":"\n"+m)}this.root||(b.add(a.compress?"}":"\n"+n+"}"),a.tabLevel--),b.isEmpty()||a.compress||!this.firstRoot||b.add("\n")},m.prototype.joinSelectors=function(a,b,c){for(var d=0;d<c.length;d++)this.joinSelector(a,b,c[d])},m.prototype.joinSelector=function(a,b,c){function d(a,b){var c,d;if(0===a.length)c=new h(a[0]);else{var e=[];for(d=0;d<a.length;d++)e.push(new g(null,a[d],b.index,b.currentFileInfo));c=new h(new f(e))}return c}function e(a,b){var c,d;return c=new g(null,a,b.index,b.currentFileInfo),d=new f([c])}function i(a,b,c,d){var e,f,h;if(e=[],a.length>0?(e=a.slice(0),f=e.pop(),h=d.createDerived(f.elements.slice(0))):h=d.createDerived([]),b.length>0){var i=c.combinator,j=b[0].elements[0];i.emptyOrWhitespace&&!j.combinator.emptyOrWhitespace&&(i=j.combinator),h.elements.push(new g(i,j.value,c.index,c.currentFileInfo)),h.elements=h.elements.concat(b[0].elements.slice(1))}if(0!==h.elements.length&&e.push(h),b.length>1){var k=b.slice(1);k=k.map(function(a){return a.createDerived(a.elements,[])}),e=e.concat(k)}return e}function j(a,b,c,d,e){var f;for(f=0;f<a.length;f++){var g=i(a[f],b,c,d);e.push(g)}return e}function k(a,b){var c,d;if(0!==a.length){if(0===b.length)return void b.push([new f(a)]);for(c=0;c<b.length;c++)d=b[c],d.length>0?d[d.length-1]=d[d.length-1].createDerived(d[d.length-1].elements.concat(a)):d.push(new f(a))}}function l(a,b,c){function f(a){var b;return"Paren"!==a.value.type?null:(b=a.value.value,"Selector"!==b.type?null:b)}var h,m,n,o,p,q,r,s,t,u,v=!1;for(o=[],p=[[]],h=0;h<c.elements.length;h++)if(s=c.elements[h],"&"!==s.value){var w=f(s);if(null!=w){k(o,p);var x,y=[],z=[];for(x=l(y,b,w),v=v||x,n=0;n<y.length;n++){var A=e(d(y[n],s),s);j(p,[A],s,c,z)}p=z,o=[]}else o.push(s)}else{for(v=!0,q=[],k(o,p),m=0;m<p.length;m++)if(r=p[m],0===b.length)r.length>0&&r[0].elements.push(new g(s.combinator,"",s.index,s.currentFileInfo)),q.push(r);else for(n=0;n<b.length;n++){var B=i(r,b[n],s,c);q.push(B)}p=q,o=[]}for(k(o,p),h=0;h<p.length;h++)t=p[h].length,t>0&&(a.push(p[h]),u=p[h][t-1],p[h][t-1]=u.createDerived(u.elements,c.extendList));return v}function m(a,b){var c=b.createDerived(b.elements,b.extendList,b.evaldCondition);return c.copyVisibilityInfo(a),c}var n,o,p;if(o=[],p=l(o,b,c),!p)if(b.length>0)for(o=[],n=0;n<b.length;n++){var q=b[n].map(m.bind(this,c.visibilityInfo()));q.push(c),o.push(q)}else o=[[c]];for(n=0;n<o.length;n++)a.push(o[n])},b.exports=m},{"../contexts":11,"../functions/default":20,"../functions/function-registry":22,"./debug-info":54,"./element":58,"./node":70,"./paren":72,"./rule":74,"./selector":77}],77:[function(a,b,c){var d=a("./node"),e=a("./element"),f=function(a,b,c,d,e,f){this.elements=a,this.extendList=b,this.condition=c,this.currentFileInfo=e||{},c||(this.evaldCondition=!0),this.copyVisibilityInfo(f)};f.prototype=new d,f.prototype.type="Selector",f.prototype.accept=function(a){this.elements&&(this.elements=a.visitArray(this.elements)),this.extendList&&(this.extendList=a.visitArray(this.extendList)),this.condition&&(this.condition=a.visit(this.condition))},f.prototype.createDerived=function(a,b,c){var d=this.visibilityInfo();c=null!=c?c:this.evaldCondition;var e=new f(a,b||this.extendList,null,this.index,this.currentFileInfo,d);return e.evaldCondition=c,e.mediaEmpty=this.mediaEmpty,e},f.prototype.createEmptySelectors=function(){var a=new e("","&",this.index,this.currentFileInfo),b=[new f([a],null,null,this.index,this.currentFileInfo)];return b[0].mediaEmpty=!0,b},f.prototype.match=function(a){var b,c,d=this.elements,e=d.length;if(a.CacheElements(),b=a._elements.length,0===b||e<b)return 0;for(c=0;c<b;c++)if(d[c].value!==a._elements[c])return 0;return b},f.prototype.CacheElements=function(){if(!this._elements){var a=this.elements.map(function(a){return a.combinator.value+(a.value.value||a.value)}).join("").match(/[,&#\*\.\w-]([\w-]|(\\.))*/g);a?"&"===a[0]&&a.shift():a=[],this._elements=a}},f.prototype.isJustParentSelector=function(){return!this.mediaEmpty&&1===this.elements.length&&"&"===this.elements[0].value&&(" "===this.elements[0].combinator.value||""===this.elements[0].combinator.value)},f.prototype.eval=function(a){var b=this.condition&&this.condition.eval(a),c=this.elements,d=this.extendList;return c=c&&c.map(function(b){return b.eval(a)}),d=d&&d.map(function(b){return b.eval(a)}),this.createDerived(c,d,b)},f.prototype.genCSS=function(a,b){var c,d;if(a&&a.firstSelector||""!==this.elements[0].combinator.value||b.add(" ",this.currentFileInfo,this.index),!this._css)for(c=0;c<this.elements.length;c++)d=this.elements[c],d.genCSS(a,b)},f.prototype.getIsOutput=function(){return this.evaldCondition},b.exports=f},{"./element":58,"./node":70}],78:[function(a,b,c){var d=a("./node"),e=function(a){this.value=a};e.prototype=new d,e.prototype.type="UnicodeDescriptor",b.exports=e},{"./node":70}],79:[function(a,b,c){var d=a("./node"),e=a("../data/unit-conversions"),f=function(a,b,c){this.numerator=a?a.slice(0).sort():[],this.denominator=b?b.slice(0).sort():[],c?this.backupUnit=c:a&&a.length&&(this.backupUnit=a[0])};f.prototype=new d,f.prototype.type="Unit",f.prototype.clone=function(){return new f(this.numerator.slice(0),this.denominator.slice(0),this.backupUnit)},f.prototype.genCSS=function(a,b){var c=a&&a.strictUnits;1===this.numerator.length?b.add(this.numerator[0]):!c&&this.backupUnit?b.add(this.backupUnit):!c&&this.denominator.length&&b.add(this.denominator[0])},f.prototype.toString=function(){var a,b=this.numerator.join("*");for(a=0;a<this.denominator.length;a++)b+="/"+this.denominator[a];return b},f.prototype.compare=function(a){return this.is(a.toString())?0:void 0},f.prototype.is=function(a){return this.toString().toUpperCase()===a.toUpperCase()},f.prototype.isLength=function(){return Boolean(this.toCSS().match(/px|em|%|in|cm|mm|pc|pt|ex/))},f.prototype.isEmpty=function(){return 0===this.numerator.length&&0===this.denominator.length},f.prototype.isSingular=function(){return this.numerator.length<=1&&0===this.denominator.length},f.prototype.map=function(a){var b;for(b=0;b<this.numerator.length;b++)this.numerator[b]=a(this.numerator[b],!1);for(b=0;b<this.denominator.length;b++)this.denominator[b]=a(this.denominator[b],!0)},f.prototype.usedUnits=function(){var a,b,c,d={};b=function(b){return a.hasOwnProperty(b)&&!d[c]&&(d[c]=b),b};for(c in e)e.hasOwnProperty(c)&&(a=e[c],this.map(b));return d},f.prototype.cancel=function(){var a,b,c={};for(b=0;b<this.numerator.length;b++)a=this.numerator[b],c[a]=(c[a]||0)+1;for(b=0;b<this.denominator.length;b++)a=this.denominator[b],c[a]=(c[a]||0)-1;this.numerator=[],this.denominator=[];for(a in c)if(c.hasOwnProperty(a)){var d=c[a];if(d>0)for(b=0;b<d;b++)this.numerator.push(a);else if(d<0)for(b=0;b<-d;b++)this.denominator.push(a)}this.numerator.sort(),this.denominator.sort()},b.exports=f},{"../data/unit-conversions":14,"./node":70}],80:[function(a,b,c){var d=a("./node"),e=function(a,b,c,d){this.value=a,this.currentFileInfo=c,this.index=b,this.isEvald=d};e.prototype=new d,e.prototype.type="Url",e.prototype.accept=function(a){this.value=a.visit(this.value)},e.prototype.genCSS=function(a,b){b.add("url("),this.value.genCSS(a,b),b.add(")")},e.prototype.eval=function(a){var b,c=this.value.eval(a);if(!this.isEvald&&(b=this.currentFileInfo&&this.currentFileInfo.rootpath,b&&"string"==typeof c.value&&a.isPathRelative(c.value)&&(c.quote||(b=b.replace(/[\(\)'"\s]/g,function(a){return"\\"+a})),c.value=b+c.value),c.value=a.normalizePath(c.value),a.urlArgs&&!c.value.match(/^\s*data:/))){var d=c.value.indexOf("?")===-1?"?":"&",f=d+a.urlArgs;c.value.indexOf("#")!==-1?c.value=c.value.replace("#",f+"#"):c.value+=f}return new e(c,this.index,this.currentFileInfo,(!0))},b.exports=e},{"./node":70}],81:[function(a,b,c){var d=a("./node"),e=function(a){if(this.value=a,!a)throw new Error("Value requires an array argument")};e.prototype=new d,e.prototype.type="Value",e.prototype.accept=function(a){this.value&&(this.value=a.visitArray(this.value))},e.prototype.eval=function(a){return 1===this.value.length?this.value[0].eval(a):new e(this.value.map(function(b){return b.eval(a)}))},e.prototype.genCSS=function(a,b){var c;for(c=0;c<this.value.length;c++)this.value[c].genCSS(a,b),c+1<this.value.length&&b.add(a&&a.compress?",":", ")},b.exports=e},{"./node":70}],82:[function(a,b,c){var d=a("./node"),e=function(a,b,c){this.name=a,this.index=b,this.currentFileInfo=c||{}};e.prototype=new d,e.prototype.type="Variable",e.prototype.eval=function(a){var b,c=this.name;if(0===c.indexOf("@@")&&(c="@"+new e(c.slice(1),this.index,this.currentFileInfo).eval(a).value),this.evaluating)throw{type:"Name",message:"Recursive variable definition for "+c,filename:this.currentFileInfo.filename,index:this.index};if(this.evaluating=!0,b=this.find(a.frames,function(b){var d=b.variable(c);if(d){if(d.important){var e=a.importantScope[a.importantScope.length-1];e.important=d.important}return d.value.eval(a)}}))return this.evaluating=!1,b;throw{type:"Name",message:"variable "+c+" is undefined",filename:this.currentFileInfo.filename,index:this.index}},e.prototype.find=function(a,b){for(var c,d=0;d<a.length;d++)if(c=b.call(a,a[d]))return c;return null},b.exports=e},{"./node":70}],83:[function(a,b,c){b.exports={getLocation:function(a,b){for(var c=a+1,d=null,e=-1;--c>=0&&"\n"!==b.charAt(c);)e++;return"number"==typeof a&&(d=(b.slice(0,a).match(/\n/g)||"").length),{line:d,column:e}}}},{}],84:[function(a,b,c){var d=a("../tree"),e=a("./visitor"),f=a("../logger"),g=function(){this._visitor=new e(this),this.contexts=[],this.allExtendsStack=[[]]};g.prototype={run:function(a){return a=this._visitor.visit(a),a.allExtends=this.allExtendsStack[0],a},visitRule:function(a,b){b.visitDeeper=!1},visitMixinDefinition:function(a,b){b.visitDeeper=!1},visitRuleset:function(a,b){if(!a.root){var c,e,f,g,h=[],i=a.rules,j=i?i.length:0;for(c=0;c<j;c++)a.rules[c]instanceof d.Extend&&(h.push(i[c]),a.extendOnEveryPath=!0);var k=a.paths;for(c=0;c<k.length;c++){var l=k[c],m=l[l.length-1],n=m.extendList;for(g=n?n.slice(0).concat(h):h,g&&(g=g.map(function(a){return a.clone()})),e=0;e<g.length;e++)this.foundExtends=!0,f=g[e],f.findSelfSelectors(l),f.ruleset=a,0===e&&(f.firstExtendOnThisSelectorPath=!0),this.allExtendsStack[this.allExtendsStack.length-1].push(f)}this.contexts.push(a.selectors)}},visitRulesetOut:function(a){a.root||(this.contexts.length=this.contexts.length-1)},visitMedia:function(a,b){a.allExtends=[],this.allExtendsStack.push(a.allExtends)},visitMediaOut:function(a){this.allExtendsStack.length=this.allExtendsStack.length-1},visitDirective:function(a,b){a.allExtends=[],this.allExtendsStack.push(a.allExtends)},visitDirectiveOut:function(a){this.allExtendsStack.length=this.allExtendsStack.length-1}};var h=function(){this._visitor=new e(this)};h.prototype={run:function(a){var b=new g;if(this.extendIndices={},b.run(a),!b.foundExtends)return a;a.allExtends=a.allExtends.concat(this.doExtendChaining(a.allExtends,a.allExtends)),this.allExtendsStack=[a.allExtends];var c=this._visitor.visit(a);return this.checkExtendsForNonMatched(a.allExtends),c},checkExtendsForNonMatched:function(a){var b=this.extendIndices;a.filter(function(a){return!a.hasFoundMatches&&1==a.parent_ids.length}).forEach(function(a){var c="_unknown_";try{c=a.selector.toCSS({})}catch(d){}b[a.index+" "+c]||(b[a.index+" "+c]=!0,f.warn("extend '"+c+"' has no matches"))})},doExtendChaining:function(a,b,c){var e,f,g,h,i,j,k,l,m=[],n=this;for(c=c||0,e=0;e<a.length;e++)for(f=0;f<b.length;f++)j=a[e],k=b[f],j.parent_ids.indexOf(k.object_id)>=0||(i=[k.selfSelectors[0]],g=n.findMatch(j,i),g.length&&(j.hasFoundMatches=!0,j.selfSelectors.forEach(function(a){var b=k.visibilityInfo();h=n.extendSelector(g,i,a,j.isVisible()),l=new d.Extend(k.selector,k.option,0,k.currentFileInfo,b),l.selfSelectors=h,h[h.length-1].extendList=[l],m.push(l),l.ruleset=k.ruleset,l.parent_ids=l.parent_ids.concat(k.parent_ids,j.parent_ids),k.firstExtendOnThisSelectorPath&&(l.firstExtendOnThisSelectorPath=!0,k.ruleset.paths.push(h))})));if(m.length){if(this.extendChainCount++,c>100){var o="{unable to calculate}",p="{unable to calculate}";try{o=m[0].selfSelectors[0].toCSS(),p=m[0].selector.toCSS()}catch(q){}throw{message:"extend circular reference detected. One of the circular extends is currently:"+o+":extend("+p+")"}}return m.concat(n.doExtendChaining(m,b,c+1))}return m},visitRule:function(a,b){b.visitDeeper=!1},visitMixinDefinition:function(a,b){b.visitDeeper=!1},visitSelector:function(a,b){b.visitDeeper=!1},visitRuleset:function(a,b){if(!a.root){var c,d,e,f,g=this.allExtendsStack[this.allExtendsStack.length-1],h=[],i=this;for(e=0;e<g.length;e++)for(d=0;d<a.paths.length;d++)if(f=a.paths[d],!a.extendOnEveryPath){var j=f[f.length-1].extendList;j&&j.length||(c=this.findMatch(g[e],f),c.length&&(g[e].hasFoundMatches=!0,g[e].selfSelectors.forEach(function(a){var b;b=i.extendSelector(c,f,a,g[e].isVisible()),h.push(b)})))}a.paths=a.paths.concat(h)}},findMatch:function(a,b){var c,d,e,f,g,h,i,j=this,k=a.selector.elements,l=[],m=[];for(c=0;c<b.length;c++)for(d=b[c],e=0;e<d.elements.length;e++)for(f=d.elements[e],(a.allowBefore||0===c&&0===e)&&l.push({pathIndex:c,index:e,matched:0,initialCombinator:f.combinator}),h=0;h<l.length;h++)i=l[h],g=f.combinator.value,""===g&&0===e&&(g=" "),!j.isElementValuesEqual(k[i.matched].value,f.value)||i.matched>0&&k[i.matched].combinator.value!==g?i=null:i.matched++,i&&(i.finished=i.matched===k.length,i.finished&&!a.allowAfter&&(e+1<d.elements.length||c+1<b.length)&&(i=null)),i?i.finished&&(i.length=k.length,i.endPathIndex=c,i.endPathElementIndex=e+1,l.length=0,m.push(i)):(l.splice(h,1),h--);return m},isElementValuesEqual:function(a,b){if("string"==typeof a||"string"==typeof b)return a===b;if(a instanceof d.Attribute)return a.op===b.op&&a.key===b.key&&(a.value&&b.value?(a=a.value.value||a.value,b=b.value.value||b.value,a===b):!a.value&&!b.value);if(a=a.value,b=b.value,a instanceof d.Selector){if(!(b instanceof d.Selector)||a.elements.length!==b.elements.length)return!1;for(var c=0;c<a.elements.length;c++){if(a.elements[c].combinator.value!==b.elements[c].combinator.value&&(0!==c||(a.elements[c].combinator.value||" ")!==(b.elements[c].combinator.value||" ")))return!1;if(!this.isElementValuesEqual(a.elements[c].value,b.elements[c].value))return!1}return!0}return!1},extendSelector:function(a,b,c,e){var f,g,h,i,j,k=0,l=0,m=[];for(f=0;f<a.length;f++)i=a[f],g=b[i.pathIndex],h=new d.Element(i.initialCombinator,c.elements[0].value,c.elements[0].index,c.elements[0].currentFileInfo),i.pathIndex>k&&l>0&&(m[m.length-1].elements=m[m.length-1].elements.concat(b[k].elements.slice(l)),l=0,k++),j=g.elements.slice(l,i.index).concat([h]).concat(c.elements.slice(1)),k===i.pathIndex&&f>0?m[m.length-1].elements=m[m.length-1].elements.concat(j):(m=m.concat(b.slice(k,i.pathIndex)),m.push(new d.Selector(j))),k=i.endPathIndex,l=i.endPathElementIndex,l>=b[k].elements.length&&(l=0,k++);return k<b.length&&l>0&&(m[m.length-1].elements=m[m.length-1].elements.concat(b[k].elements.slice(l)),k++),m=m.concat(b.slice(k,b.length)),m=m.map(function(a){var b=a.createDerived(a.elements);return e?b.ensureVisibility():b.ensureInvisibility(),b})},visitMedia:function(a,b){var c=a.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);c=c.concat(this.doExtendChaining(c,a.allExtends)),this.allExtendsStack.push(c)},visitMediaOut:function(a){var b=this.allExtendsStack.length-1;this.allExtendsStack.length=b},visitDirective:function(a,b){var c=a.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);c=c.concat(this.doExtendChaining(c,a.allExtends)),this.allExtendsStack.push(c)},visitDirectiveOut:function(a){var b=this.allExtendsStack.length-1;this.allExtendsStack.length=b}},b.exports=h},{"../logger":33,"../tree":62,"./visitor":91}],85:[function(a,b,c){function d(a){this.imports=[],this.variableImports=[],this._onSequencerEmpty=a,this._currentDepth=0}d.prototype.addImport=function(a){var b=this,c={callback:a,args:null,isReady:!1};return this.imports.push(c),function(){c.args=Array.prototype.slice.call(arguments,0),c.isReady=!0,b.tryRun()}},d.prototype.addVariableImport=function(a){this.variableImports.push(a)},d.prototype.tryRun=function(){this._currentDepth++;try{for(;;){for(;this.imports.length>0;){var a=this.imports[0];if(!a.isReady)return;
-this.imports=this.imports.slice(1),a.callback.apply(null,a.args)}if(0===this.variableImports.length)break;var b=this.variableImports[0];this.variableImports=this.variableImports.slice(1),b()}}finally{this._currentDepth--}0===this._currentDepth&&this._onSequencerEmpty&&this._onSequencerEmpty()},b.exports=d},{}],86:[function(a,b,c){var d=a("../contexts"),e=a("./visitor"),f=a("./import-sequencer"),g=function(a,b){this._visitor=new e(this),this._importer=a,this._finish=b,this.context=new d.Eval,this.importCount=0,this.onceFileDetectionMap={},this.recursionDetector={},this._sequencer=new f(this._onSequencerEmpty.bind(this))};g.prototype={isReplacing:!1,run:function(a){try{this._visitor.visit(a)}catch(b){this.error=b}this.isFinished=!0,this._sequencer.tryRun()},_onSequencerEmpty:function(){this.isFinished&&this._finish(this.error)},visitImport:function(a,b){var c=a.options.inline;if(!a.css||c){var e=new d.Eval(this.context,this.context.frames.slice(0)),f=e.frames[0];this.importCount++,a.isVariableImport()?this._sequencer.addVariableImport(this.processImportNode.bind(this,a,e,f)):this.processImportNode(a,e,f)}b.visitDeeper=!1},processImportNode:function(a,b,c){var d,e=a.options.inline;try{d=a.evalForImport(b)}catch(f){f.filename||(f.index=a.index,f.filename=a.currentFileInfo.filename),a.css=!0,a.error=f}if(!d||d.css&&!e)this.importCount--,this.isFinished&&this._sequencer.tryRun();else{d.options.multiple&&(b.importMultiple=!0);for(var g=void 0===d.css,h=0;h<c.rules.length;h++)if(c.rules[h]===a){c.rules[h]=d;break}var i=this.onImported.bind(this,d,b),j=this._sequencer.addImport(i);this._importer.push(d.getPath(),g,d.currentFileInfo,d.options,j)}},onImported:function(a,b,c,d,e,f){c&&(c.filename||(c.index=a.index,c.filename=a.currentFileInfo.filename),this.error=c);var g=this,h=a.options.inline,i=a.options.plugin,j=a.options.optional,k=e||f in g.recursionDetector;if(b.importMultiple||(a.skip=!!k||function(){return f in g.onceFileDetectionMap||(g.onceFileDetectionMap[f]=!0,!1)}),!f&&j&&(a.skip=!0),d&&(a.root=d,a.importedFilename=f,!h&&!i&&(b.importMultiple||!k))){g.recursionDetector[f]=!0;var l=this.context;this.context=b;try{this._visitor.visit(d)}catch(c){this.error=c}this.context=l}g.importCount--,g.isFinished&&g._sequencer.tryRun()},visitRule:function(a,b){"DetachedRuleset"===a.value.type?this.context.frames.unshift(a):b.visitDeeper=!1},visitRuleOut:function(a){"DetachedRuleset"===a.value.type&&this.context.frames.shift()},visitDirective:function(a,b){this.context.frames.unshift(a)},visitDirectiveOut:function(a){this.context.frames.shift()},visitMixinDefinition:function(a,b){this.context.frames.unshift(a)},visitMixinDefinitionOut:function(a){this.context.frames.shift()},visitRuleset:function(a,b){this.context.frames.unshift(a)},visitRulesetOut:function(a){this.context.frames.shift()},visitMedia:function(a,b){this.context.frames.unshift(a.rules[0])},visitMediaOut:function(a){this.context.frames.shift()}},b.exports=g},{"../contexts":11,"./import-sequencer":85,"./visitor":91}],87:[function(a,b,c){var d={Visitor:a("./visitor"),ImportVisitor:a("./import-visitor"),MarkVisibleSelectorsVisitor:a("./set-tree-visibility-visitor"),ExtendVisitor:a("./extend-visitor"),JoinSelectorVisitor:a("./join-selector-visitor"),ToCSSVisitor:a("./to-css-visitor")};b.exports=d},{"./extend-visitor":84,"./import-visitor":86,"./join-selector-visitor":88,"./set-tree-visibility-visitor":89,"./to-css-visitor":90,"./visitor":91}],88:[function(a,b,c){var d=a("./visitor"),e=function(){this.contexts=[[]],this._visitor=new d(this)};e.prototype={run:function(a){return this._visitor.visit(a)},visitRule:function(a,b){b.visitDeeper=!1},visitMixinDefinition:function(a,b){b.visitDeeper=!1},visitRuleset:function(a,b){var c,d=this.contexts[this.contexts.length-1],e=[];this.contexts.push(e),a.root||(c=a.selectors,c&&(c=c.filter(function(a){return a.getIsOutput()}),a.selectors=c.length?c:c=null,c&&a.joinSelectors(e,d,c)),c||(a.rules=null),a.paths=e)},visitRulesetOut:function(a){this.contexts.length=this.contexts.length-1},visitMedia:function(a,b){var c=this.contexts[this.contexts.length-1];a.rules[0].root=0===c.length||c[0].multiMedia},visitDirective:function(a,b){var c=this.contexts[this.contexts.length-1];a.rules&&a.rules.length&&(a.rules[0].root=a.isRooted||0===c.length||null)}},b.exports=e},{"./visitor":91}],89:[function(a,b,c){var d=function(a){this.visible=a};d.prototype.run=function(a){this.visit(a)},d.prototype.visitArray=function(a){if(!a)return a;var b,c=a.length;for(b=0;b<c;b++)this.visit(a[b]);return a},d.prototype.visit=function(a){return a?a.constructor===Array?this.visitArray(a):!a.blocksVisibility||a.blocksVisibility()?a:(this.visible?a.ensureVisibility():a.ensureInvisibility(),a.accept(this),a):a},b.exports=d},{}],90:[function(a,b,c){var d=a("../tree"),e=a("./visitor"),f=function(a){this._visitor=new e(this),this._context=a};f.prototype={containsSilentNonBlockedChild:function(a){var b;if(null==a)return!1;for(var c=0;c<a.length;c++)if(b=a[c],b.isSilent&&b.isSilent(this._context)&&!b.blocksVisibility())return!0;return!1},keepOnlyVisibleChilds:function(a){null!=a&&null!=a.rules&&(a.rules=a.rules.filter(function(a){return a.isVisible()}))},isEmpty:function(a){return null==a||null==a.rules||0===a.rules.length},hasVisibleSelector:function(a){return null!=a&&null!=a.paths&&a.paths.length>0},resolveVisibility:function(a,b){if(!a.blocksVisibility()){if(this.isEmpty(a)&&!this.containsSilentNonBlockedChild(b))return;return a}var c=a.rules[0];if(this.keepOnlyVisibleChilds(c),!this.isEmpty(c))return a.ensureVisibility(),a.removeVisibilityBlock(),a},isVisibleRuleset:function(a){return!!a.firstRoot||!this.isEmpty(a)&&!(!a.root&&!this.hasVisibleSelector(a))}};var g=function(a){this._visitor=new e(this),this._context=a,this.utils=new f(a)};g.prototype={isReplacing:!0,run:function(a){return this._visitor.visit(a)},visitRule:function(a,b){if(!a.blocksVisibility()&&!a.variable)return a},visitMixinDefinition:function(a,b){a.frames=[]},visitExtend:function(a,b){},visitComment:function(a,b){if(!a.blocksVisibility()&&!a.isSilent(this._context))return a},visitMedia:function(a,b){var c=a.rules[0].rules;return a.accept(this._visitor),b.visitDeeper=!1,this.utils.resolveVisibility(a,c)},visitImport:function(a,b){if(!a.blocksVisibility())return a},visitDirective:function(a,b){return a.rules&&a.rules.length?this.visitDirectiveWithBody(a,b):this.visitDirectiveWithoutBody(a,b)},visitDirectiveWithBody:function(a,b){function c(a){var b=a.rules;return 1===b.length&&(!b[0].paths||0===b[0].paths.length)}function d(a){var b=a.rules;return c(a)?b[0].rules:b}var e=d(a);return a.accept(this._visitor),b.visitDeeper=!1,this.utils.isEmpty(a)||this._mergeRules(a.rules[0].rules),this.utils.resolveVisibility(a,e)},visitDirectiveWithoutBody:function(a,b){if(!a.blocksVisibility()){if("@charset"===a.name){if(this.charset){if(a.debugInfo){var c=new d.Comment("/* "+a.toCSS(this._context).replace(/\n/g,"")+" */\n");return c.debugInfo=a.debugInfo,this._visitor.visit(c)}return}this.charset=!0}return a}},checkValidNodes:function(a,b){if(a)for(var c=0;c<a.length;c++){var e=a[c];if(b&&e instanceof d.Rule&&!e.variable)throw{message:"Properties must be inside selector blocks. They cannot be in the root",index:e.index,filename:e.currentFileInfo&&e.currentFileInfo.filename};if(e instanceof d.Call)throw{message:"Function '"+e.name+"' is undefined",index:e.index,filename:e.currentFileInfo&&e.currentFileInfo.filename};if(e.type&&!e.allowRoot)throw{message:e.type+" node returned by a function is not valid here",index:e.index,filename:e.currentFileInfo&&e.currentFileInfo.filename}}},visitRuleset:function(a,b){var c,d=[];if(this.checkValidNodes(a.rules,a.firstRoot),a.root)a.accept(this._visitor),b.visitDeeper=!1;else{this._compileRulesetPaths(a);for(var e=a.rules,f=e?e.length:0,g=0;g<f;)c=e[g],c&&c.rules?(d.push(this._visitor.visit(c)),e.splice(g,1),f--):g++;f>0?a.accept(this._visitor):a.rules=null,b.visitDeeper=!1}return a.rules&&(this._mergeRules(a.rules),this._removeDuplicateRules(a.rules)),this.utils.isVisibleRuleset(a)&&(a.ensureVisibility(),d.splice(0,0,a)),1===d.length?d[0]:d},_compileRulesetPaths:function(a){a.paths&&(a.paths=a.paths.filter(function(a){var b;for(" "===a[0].elements[0].combinator.value&&(a[0].elements[0].combinator=new d.Combinator("")),b=0;b<a.length;b++)if(a[b].isVisible()&&a[b].getIsOutput())return!0;return!1}))},_removeDuplicateRules:function(a){if(a){var b,c,e,f={};for(e=a.length-1;e>=0;e--)if(c=a[e],c instanceof d.Rule)if(f[c.name]){b=f[c.name],b instanceof d.Rule&&(b=f[c.name]=[f[c.name].toCSS(this._context)]);var g=c.toCSS(this._context);b.indexOf(g)!==-1?a.splice(e,1):b.push(g)}else f[c.name]=c}},_mergeRules:function(a){if(a){for(var b,c,e,f={},g=0;g<a.length;g++)c=a[g],c instanceof d.Rule&&c.merge&&(e=[c.name,c.important?"!":""].join(","),f[e]?a.splice(g--,1):f[e]=[],f[e].push(c));Object.keys(f).map(function(a){function e(a){return new d.Expression(a.map(function(a){return a.value}))}function g(a){return new d.Value(a.map(function(a){return a}))}if(b=f[a],b.length>1){c=b[0];var h=[],i=[];b.map(function(a){"+"===a.merge&&(i.length>0&&h.push(e(i)),i=[]),i.push(a)}),h.push(e(i)),c.value=g(h)}})}},visitAnonymous:function(a,b){if(!a.blocksVisibility())return a.accept(this._visitor),a}},b.exports=g},{"../tree":62,"./visitor":91}],91:[function(a,b,c){function d(a){return a}function e(a,b){var c,d;for(c in a)if(a.hasOwnProperty(c))switch(d=a[c],typeof d){case"function":d.prototype&&d.prototype.type&&(d.prototype.typeIndex=b++);break;case"object":b=e(d,b)}return b}var f=a("../tree"),g={visitDeeper:!0},h=!1,i=function(a){this._implementation=a,this._visitFnCache=[],h||(e(f,1),h=!0)};i.prototype={visit:function(a){if(!a)return a;var b=a.typeIndex;if(!b)return a;var c,e=this._visitFnCache,f=this._implementation,h=b<<1,i=1|h,j=e[h],k=e[i],l=g;if(l.visitDeeper=!0,j||(c="visit"+a.type,j=f[c]||d,k=f[c+"Out"]||d,e[h]=j,e[i]=k),j!==d){var m=j.call(f,a,l);f.isReplacing&&(a=m)}return l.visitDeeper&&a&&a.accept&&a.accept(this),k!=d&&k.call(f,a),a},visitArray:function(a,b){if(!a)return a;var c,d=a.length;if(b||!this._implementation.isReplacing){for(c=0;c<d;c++)this.visit(a[c]);return a}var e=[];for(c=0;c<d;c++){var f=this.visit(a[c]);void 0!==f&&(f.splice?f.length&&this.flatten(f,e):e.push(f))}return e},flatten:function(a,b){b||(b=[]);var c,d,e,f,g,h;for(d=0,c=a.length;d<c;d++)if(e=a[d],void 0!==e)if(e.splice)for(g=0,f=e.length;g<f;g++)h=e[g],void 0!==h&&(h.splice?h.length&&this.flatten(h,b):b.push(h));else b.push(e);return b}},b.exports=i},{"../tree":62}],92:[function(a,b,c){"use strict";function d(){if(i.length)throw i.shift()}function e(a){var b;b=h.length?h.pop():new f,b.task=a,g(b)}function f(){this.task=null}var g=a("./raw"),h=[],i=[],j=g.makeRequestCallFromTimer(d);b.exports=e,f.prototype.call=function(){try{this.task.call()}catch(a){e.onerror?e.onerror(a):(i.push(a),j())}finally{this.task=null,h[h.length]=this}}},{"./raw":93}],93:[function(a,b,c){(function(a){"use strict";function c(a){h.length||(g(),i=!0),h[h.length]=a}function d(){for(;j<h.length;){var a=j;if(j+=1,h[a].call(),j>k){for(var b=0,c=h.length-j;b<c;b++)h[b]=h[b+j];h.length-=j,j=0}}h.length=0,j=0,i=!1}function e(a){var b=1,c=new l(a),d=document.createTextNode("");return c.observe(d,{characterData:!0}),function(){b=-b,d.data=b}}function f(a){return function(){function b(){clearTimeout(c),clearInterval(d),a()}var c=setTimeout(b,0),d=setInterval(b,50)}}b.exports=c;var g,h=[],i=!1,j=0,k=1024,l=a.MutationObserver||a.WebKitMutationObserver;g="function"==typeof l?e(d):f(d),c.requestFlush=g,c.makeRequestCallFromTimer=f}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],94:[function(a,b,c){"use strict";function d(){}function e(a){try{return a.then}catch(b){return r=b,s}}function f(a,b){try{return a(b)}catch(c){return r=c,s}}function g(a,b,c){try{a(b,c)}catch(d){return r=d,s}}function h(a){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof a)throw new TypeError("not a function");this._45=0,this._81=0,this._65=null,this._54=null,a!==d&&p(a,this)}function i(a,b,c){return new a.constructor(function(e,f){var g=new h(d);g.then(e,f),j(a,new o(b,c,g))})}function j(a,b){for(;3===a._81;)a=a._65;return h._10&&h._10(a),0===a._81?0===a._45?(a._45=1,void(a._54=b)):1===a._45?(a._45=2,void(a._54=[a._54,b])):void a._54.push(b):void k(a,b)}function k(a,b){q(function(){var c=1===a._81?b.onFulfilled:b.onRejected;if(null===c)return void(1===a._81?l(b.promise,a._65):m(b.promise,a._65));var d=f(c,a._65);d===s?m(b.promise,r):l(b.promise,d)})}function l(a,b){if(b===a)return m(a,new TypeError("A promise cannot be resolved with itself."));if(b&&("object"==typeof b||"function"==typeof b)){var c=e(b);if(c===s)return m(a,r);if(c===a.then&&b instanceof h)return a._81=3,a._65=b,void n(a);if("function"==typeof c)return void p(c.bind(b),a)}a._81=1,a._65=b,n(a)}function m(a,b){a._81=2,a._65=b,h._97&&h._97(a,b),n(a)}function n(a){if(1===a._45&&(j(a,a._54),a._54=null),2===a._45){for(var b=0;b<a._54.length;b++)j(a,a._54[b]);a._54=null}}function o(a,b,c){this.onFulfilled="function"==typeof a?a:null,this.onRejected="function"==typeof b?b:null,this.promise=c}function p(a,b){var c=!1,d=g(a,function(a){c||(c=!0,l(b,a))},function(a){c||(c=!0,m(b,a))});c||d!==s||(c=!0,m(b,r))}var q=a("asap/raw"),r=null,s={};b.exports=h,h._10=null,h._97=null,h._61=d,h.prototype.then=function(a,b){if(this.constructor!==h)return i(this,a,b);var c=new h(d);return j(this,new o(a,b,c)),c}},{"asap/raw":93}],95:[function(a,b,c){"use strict";function d(a){var b=new e(e._61);return b._81=1,b._65=a,b}var e=a("./core.js");b.exports=e;var f=d(!0),g=d(!1),h=d(null),i=d(void 0),j=d(0),k=d("");e.resolve=function(a){if(a instanceof e)return a;if(null===a)return h;if(void 0===a)return i;if(a===!0)return f;if(a===!1)return g;if(0===a)return j;if(""===a)return k;if("object"==typeof a||"function"==typeof a)try{var b=a.then;if("function"==typeof b)return new e(b.bind(a))}catch(c){return new e(function(a,b){b(c)})}return d(a)},e.all=function(a){var b=Array.prototype.slice.call(a);return new e(function(a,c){function d(g,h){if(h&&("object"==typeof h||"function"==typeof h)){if(h instanceof e&&h.then===e.prototype.then){for(;3===h._81;)h=h._65;return 1===h._81?d(g,h._65):(2===h._81&&c(h._65),void h.then(function(a){d(g,a)},c))}var i=h.then;if("function"==typeof i){var j=new e(i.bind(h));return void j.then(function(a){d(g,a)},c)}}b[g]=h,0===--f&&a(b)}if(0===b.length)return a([]);for(var f=b.length,g=0;g<b.length;g++)d(g,b[g])})},e.reject=function(a){return new e(function(b,c){c(a)})},e.race=function(a){return new e(function(b,c){a.forEach(function(a){e.resolve(a).then(b,c)})})},e.prototype["catch"]=function(a){return this.then(null,a)}},{"./core.js":94}],96:[function(a,b,c){"function"!=typeof Promise.prototype.done&&(Promise.prototype.done=function(a,b){var c=arguments.length?this.then.apply(this,arguments):this;c.then(null,function(a){setTimeout(function(){throw a},0)})})},{}],97:[function(a,b,c){a("asap");"undefined"==typeof Promise&&(Promise=a("./lib/core.js"),a("./lib/es6-extensions.js")),a("./polyfill-done.js")},{"./lib/core.js":94,"./lib/es6-extensions.js":95,"./polyfill-done.js":96,asap:92}]},{},[2])(2)});
\ No newline at end of file
+this.imports=this.imports.slice(1),a.callback.apply(null,a.args)}if(0===this.variableImports.length)break;var b=this.variableImports[0];this.variableImports=this.variableImports.slice(1),b()}}finally{this._currentDepth--}0===this._currentDepth&&this._onSequencerEmpty&&this._onSequencerEmpty()},b.exports=d},{}],86:[function(a,b,c){var d=a("../contexts"),e=a("./visitor"),f=a("./import-sequencer"),g=function(a,b){this._visitor=new e(this),this._importer=a,this._finish=b,this.context=new d.Eval,this.importCount=0,this.onceFileDetectionMap={},this.recursionDetector={},this._sequencer=new f(this._onSequencerEmpty.bind(this))};g.prototype={isReplacing:!1,run:function(a){try{this._visitor.visit(a)}catch(b){this.error=b}this.isFinished=!0,this._sequencer.tryRun()},_onSequencerEmpty:function(){this.isFinished&&this._finish(this.error)},visitImport:function(a,b){var c=a.options.inline;if(!a.css||c){var e=new d.Eval(this.context,this.context.frames.slice(0)),f=e.frames[0];this.importCount++,a.isVariableImport()?this._sequencer.addVariableImport(this.processImportNode.bind(this,a,e,f)):this.processImportNode(a,e,f)}b.visitDeeper=!1},processImportNode:function(a,b,c){var d,e=a.options.inline;try{d=a.evalForImport(b)}catch(f){f.filename||(f.index=a.index,f.filename=a.currentFileInfo.filename),a.css=!0,a.error=f}if(!d||d.css&&!e)this.importCount--,this.isFinished&&this._sequencer.tryRun();else{d.options.multiple&&(b.importMultiple=!0);for(var g=void 0===d.css,h=0;h<c.rules.length;h++)if(c.rules[h]===a){c.rules[h]=d;break}var i=this.onImported.bind(this,d,b),j=this._sequencer.addImport(i);this._importer.push(d.getPath(),g,d.currentFileInfo,d.options,j)}},onImported:function(a,b,c,d,e,f){c&&(c.filename||(c.index=a.index,c.filename=a.currentFileInfo.filename),this.error=c);var g=this,h=a.options.inline,i=a.options.plugin,j=a.options.optional,k=e||f in g.recursionDetector;if(b.importMultiple||(a.skip=!!k||function(){return f in g.onceFileDetectionMap||(g.onceFileDetectionMap[f]=!0,!1)}),!f&&j&&(a.skip=!0),d&&(a.root=d,a.importedFilename=f,!h&&!i&&(b.importMultiple||!k))){g.recursionDetector[f]=!0;var l=this.context;this.context=b;try{this._visitor.visit(d)}catch(c){this.error=c}this.context=l}g.importCount--,g.isFinished&&g._sequencer.tryRun()},visitRule:function(a,b){"DetachedRuleset"===a.value.type?this.context.frames.unshift(a):b.visitDeeper=!1},visitRuleOut:function(a){"DetachedRuleset"===a.value.type&&this.context.frames.shift()},visitDirective:function(a,b){this.context.frames.unshift(a)},visitDirectiveOut:function(a){this.context.frames.shift()},visitMixinDefinition:function(a,b){this.context.frames.unshift(a)},visitMixinDefinitionOut:function(a){this.context.frames.shift()},visitRuleset:function(a,b){this.context.frames.unshift(a)},visitRulesetOut:function(a){this.context.frames.shift()},visitMedia:function(a,b){this.context.frames.unshift(a.rules[0])},visitMediaOut:function(a){this.context.frames.shift()}},b.exports=g},{"../contexts":11,"./import-sequencer":85,"./visitor":91}],87:[function(a,b,c){var d={Visitor:a("./visitor"),ImportVisitor:a("./import-visitor"),MarkVisibleSelectorsVisitor:a("./set-tree-visibility-visitor"),ExtendVisitor:a("./extend-visitor"),JoinSelectorVisitor:a("./join-selector-visitor"),ToCSSVisitor:a("./to-css-visitor")};b.exports=d},{"./extend-visitor":84,"./import-visitor":86,"./join-selector-visitor":88,"./set-tree-visibility-visitor":89,"./to-css-visitor":90,"./visitor":91}],88:[function(a,b,c){var d=a("./visitor"),e=function(){this.contexts=[[]],this._visitor=new d(this)};e.prototype={run:function(a){return this._visitor.visit(a)},visitRule:function(a,b){b.visitDeeper=!1},visitMixinDefinition:function(a,b){b.visitDeeper=!1},visitRuleset:function(a,b){var c,d=this.contexts[this.contexts.length-1],e=[];this.contexts.push(e),a.root||(c=a.selectors,c&&(c=c.filter(function(a){return a.getIsOutput()}),a.selectors=c.length?c:c=null,c&&a.joinSelectors(e,d,c)),c||(a.rules=null),a.paths=e)},visitRulesetOut:function(a){this.contexts.length=this.contexts.length-1},visitMedia:function(a,b){var c=this.contexts[this.contexts.length-1];a.rules[0].root=0===c.length||c[0].multiMedia},visitDirective:function(a,b){var c=this.contexts[this.contexts.length-1];a.rules&&a.rules.length&&(a.rules[0].root=a.isRooted||0===c.length||null)}},b.exports=e},{"./visitor":91}],89:[function(a,b,c){var d=function(a){this.visible=a};d.prototype.run=function(a){this.visit(a)},d.prototype.visitArray=function(a){if(!a)return a;var b,c=a.length;for(b=0;b<c;b++)this.visit(a[b]);return a},d.prototype.visit=function(a){return a?a.constructor===Array?this.visitArray(a):!a.blocksVisibility||a.blocksVisibility()?a:(this.visible?a.ensureVisibility():a.ensureInvisibility(),a.accept(this),a):a},b.exports=d},{}],90:[function(a,b,c){var d=a("../tree"),e=a("./visitor"),f=function(a){this._visitor=new e(this),this._context=a};f.prototype={containsSilentNonBlockedChild:function(a){var b;if(null==a)return!1;for(var c=0;c<a.length;c++)if(b=a[c],b.isSilent&&b.isSilent(this._context)&&!b.blocksVisibility())return!0;return!1},keepOnlyVisibleChilds:function(a){null!=a&&null!=a.rules&&(a.rules=a.rules.filter(function(a){return a.isVisible()}))},isEmpty:function(a){return null==a||null==a.rules||0===a.rules.length},hasVisibleSelector:function(a){return null!=a&&null!=a.paths&&a.paths.length>0},resolveVisibility:function(a,b){if(!a.blocksVisibility()){if(this.isEmpty(a)&&!this.containsSilentNonBlockedChild(b))return;return a}var c=a.rules[0];if(this.keepOnlyVisibleChilds(c),!this.isEmpty(c))return a.ensureVisibility(),a.removeVisibilityBlock(),a},isVisibleRuleset:function(a){return!!a.firstRoot||!this.isEmpty(a)&&!(!a.root&&!this.hasVisibleSelector(a))}};var g=function(a){this._visitor=new e(this),this._context=a,this.utils=new f(a)};g.prototype={isReplacing:!0,run:function(a){return this._visitor.visit(a)},visitRule:function(a,b){if(!a.blocksVisibility()&&!a.variable)return a},visitMixinDefinition:function(a,b){a.frames=[]},visitExtend:function(a,b){},visitComment:function(a,b){if(!a.blocksVisibility()&&!a.isSilent(this._context))return a},visitMedia:function(a,b){var c=a.rules[0].rules;return a.accept(this._visitor),b.visitDeeper=!1,this.utils.resolveVisibility(a,c)},visitImport:function(a,b){if(!a.blocksVisibility())return a},visitDirective:function(a,b){return a.rules&&a.rules.length?this.visitDirectiveWithBody(a,b):this.visitDirectiveWithoutBody(a,b)},visitDirectiveWithBody:function(a,b){function c(a){var b=a.rules;return 1===b.length&&(!b[0].paths||0===b[0].paths.length)}function d(a){var b=a.rules;return c(a)?b[0].rules:b}var e=d(a);return a.accept(this._visitor),b.visitDeeper=!1,this.utils.isEmpty(a)||this._mergeRules(a.rules[0].rules),this.utils.resolveVisibility(a,e)},visitDirectiveWithoutBody:function(a,b){if(!a.blocksVisibility()){if("@charset"===a.name){if(this.charset){if(a.debugInfo){var c=new d.Comment("/* "+a.toCSS(this._context).replace(/\n/g,"")+" */\n");return c.debugInfo=a.debugInfo,this._visitor.visit(c)}return}this.charset=!0}return a}},checkValidNodes:function(a,b){if(a)for(var c=0;c<a.length;c++){var e=a[c];if(b&&e instanceof d.Rule&&!e.variable)throw{message:"Properties must be inside selector blocks. They cannot be in the root",index:e.index,filename:e.currentFileInfo&&e.currentFileInfo.filename};if(e instanceof d.Call)throw{message:"Function '"+e.name+"' is undefined",index:e.index,filename:e.currentFileInfo&&e.currentFileInfo.filename};if(e.type&&!e.allowRoot)throw{message:e.type+" node returned by a function is not valid here",index:e.index,filename:e.currentFileInfo&&e.currentFileInfo.filename}}},visitRuleset:function(a,b){var c,d=[];if(this.checkValidNodes(a.rules,a.firstRoot),a.root)a.accept(this._visitor),b.visitDeeper=!1;else{this._compileRulesetPaths(a);for(var e=a.rules,f=e?e.length:0,g=0;g<f;)c=e[g],c&&c.rules?(d.push(this._visitor.visit(c)),e.splice(g,1),f--):g++;f>0?a.accept(this._visitor):a.rules=null,b.visitDeeper=!1}return a.rules&&(this._mergeRules(a.rules),this._removeDuplicateRules(a.rules)),this.utils.isVisibleRuleset(a)&&(a.ensureVisibility(),d.splice(0,0,a)),1===d.length?d[0]:d},_compileRulesetPaths:function(a){a.paths&&(a.paths=a.paths.filter(function(a){var b;for(" "===a[0].elements[0].combinator.value&&(a[0].elements[0].combinator=new d.Combinator("")),b=0;b<a.length;b++)if(a[b].isVisible()&&a[b].getIsOutput())return!0;return!1}))},_removeDuplicateRules:function(a){if(a){var b,c,e,f={};for(e=a.length-1;e>=0;e--)if(c=a[e],c instanceof d.Rule)if(f[c.name]){b=f[c.name],b instanceof d.Rule&&(b=f[c.name]=[f[c.name].toCSS(this._context)]);var g=c.toCSS(this._context);b.indexOf(g)!==-1?a.splice(e,1):b.push(g)}else f[c.name]=c}},_mergeRules:function(a){if(a){for(var b,c,e,f={},g=0;g<a.length;g++)c=a[g],c instanceof d.Rule&&c.merge&&(e=[c.name,c.important?"!":""].join(","),f[e]?a.splice(g--,1):f[e]=[],f[e].push(c));Object.keys(f).map(function(a){function e(a){return new d.Expression(a.map(function(a){return a.value}))}function g(a){return new d.Value(a.map(function(a){return a}))}if(b=f[a],b.length>1){c=b[0];var h=[],i=[];b.map(function(a){"+"===a.merge&&(i.length>0&&h.push(e(i)),i=[]),i.push(a)}),h.push(e(i)),c.value=g(h)}})}},visitAnonymous:function(a,b){if(!a.blocksVisibility())return a.accept(this._visitor),a}},b.exports=g},{"../tree":62,"./visitor":91}],91:[function(a,b,c){function d(a){return a}function e(a,b){var c,d;for(c in a)if(a.hasOwnProperty(c))switch(d=a[c],typeof d){case"function":d.prototype&&d.prototype.type&&(d.prototype.typeIndex=b++);break;case"object":b=e(d,b)}return b}var f=a("../tree"),g={visitDeeper:!0},h=!1,i=function(a){this._implementation=a,this._visitFnCache=[],h||(e(f,1),h=!0)};i.prototype={visit:function(a){if(!a)return a;var b=a.typeIndex;if(!b)return a;var c,e=this._visitFnCache,f=this._implementation,h=b<<1,i=1|h,j=e[h],k=e[i],l=g;if(l.visitDeeper=!0,j||(c="visit"+a.type,j=f[c]||d,k=f[c+"Out"]||d,e[h]=j,e[i]=k),j!==d){var m=j.call(f,a,l);f.isReplacing&&(a=m)}return l.visitDeeper&&a&&a.accept&&a.accept(this),k!=d&&k.call(f,a),a},visitArray:function(a,b){if(!a)return a;var c,d=a.length;if(b||!this._implementation.isReplacing){for(c=0;c<d;c++)this.visit(a[c]);return a}var e=[];for(c=0;c<d;c++){var f=this.visit(a[c]);void 0!==f&&(f.splice?f.length&&this.flatten(f,e):e.push(f))}return e},flatten:function(a,b){b||(b=[]);var c,d,e,f,g,h;for(d=0,c=a.length;d<c;d++)if(e=a[d],void 0!==e)if(e.splice)for(g=0,f=e.length;g<f;g++)h=e[g],void 0!==h&&(h.splice?h.length&&this.flatten(h,b):b.push(h));else b.push(e);return b}},b.exports=i},{"../tree":62}],92:[function(a,b,c){"use strict";function d(){if(i.length)throw i.shift()}function e(a){var b;b=h.length?h.pop():new f,b.task=a,g(b)}function f(){this.task=null}var g=a("./raw"),h=[],i=[],j=g.makeRequestCallFromTimer(d);b.exports=e,f.prototype.call=function(){try{this.task.call()}catch(a){e.onerror?e.onerror(a):(i.push(a),j())}finally{this.task=null,h[h.length]=this}}},{"./raw":93}],93:[function(a,b,c){(function(a){"use strict";function c(a){h.length||(g(),i=!0),h[h.length]=a}function d(){for(;j<h.length;){var a=j;if(j+=1,h[a].call(),j>k){for(var b=0,c=h.length-j;b<c;b++)h[b]=h[b+j];h.length-=j,j=0}}h.length=0,j=0,i=!1}function e(a){var b=1,c=new l(a),d=document.createTextNode("");return c.observe(d,{characterData:!0}),function(){b=-b,d.data=b}}function f(a){return function(){function b(){clearTimeout(c),clearInterval(d),a()}var c=setTimeout(b,0),d=setInterval(b,50)}}b.exports=c;var g,h=[],i=!1,j=0,k=1024,l=a.MutationObserver||a.WebKitMutationObserver;g="function"==typeof l?e(d):f(d),c.requestFlush=g,c.makeRequestCallFromTimer=f}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],94:[function(a,b,c){"use strict";function d(){}function e(a){try{return a.then}catch(b){return r=b,s}}function f(a,b){try{return a(b)}catch(c){return r=c,s}}function g(a,b,c){try{a(b,c)}catch(d){return r=d,s}}function h(a){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof a)throw new TypeError("not a function");this._45=0,this._81=0,this._65=null,this._54=null,a!==d&&p(a,this)}function i(a,b,c){return new a.constructor(function(e,f){var g=new h(d);g.then(e,f),j(a,new o(b,c,g))})}function j(a,b){for(;3===a._81;)a=a._65;return h._10&&h._10(a),0===a._81?0===a._45?(a._45=1,void(a._54=b)):1===a._45?(a._45=2,void(a._54=[a._54,b])):void a._54.push(b):void k(a,b)}function k(a,b){q(function(){var c=1===a._81?b.onFulfilled:b.onRejected;if(null===c)return void(1===a._81?l(b.promise,a._65):m(b.promise,a._65));var d=f(c,a._65);d===s?m(b.promise,r):l(b.promise,d)})}function l(a,b){if(b===a)return m(a,new TypeError("A promise cannot be resolved with itself."));if(b&&("object"==typeof b||"function"==typeof b)){var c=e(b);if(c===s)return m(a,r);if(c===a.then&&b instanceof h)return a._81=3,a._65=b,void n(a);if("function"==typeof c)return void p(c.bind(b),a)}a._81=1,a._65=b,n(a)}function m(a,b){a._81=2,a._65=b,h._97&&h._97(a,b),n(a)}function n(a){if(1===a._45&&(j(a,a._54),a._54=null),2===a._45){for(var b=0;b<a._54.length;b++)j(a,a._54[b]);a._54=null}}function o(a,b,c){this.onFulfilled="function"==typeof a?a:null,this.onRejected="function"==typeof b?b:null,this.promise=c}function p(a,b){var c=!1,d=g(a,function(a){c||(c=!0,l(b,a))},function(a){c||(c=!0,m(b,a))});c||d!==s||(c=!0,m(b,r))}var q=a("asap/raw"),r=null,s={};b.exports=h,h._10=null,h._97=null,h._61=d,h.prototype.then=function(a,b){if(this.constructor!==h)return i(this,a,b);var c=new h(d);return j(this,new o(a,b,c)),c}},{"asap/raw":93}],95:[function(a,b,c){"use strict";function d(a){var b=new e(e._61);return b._81=1,b._65=a,b}var e=a("./core.js");b.exports=e;var f=d(!0),g=d(!1),h=d(null),i=d(void 0),j=d(0),k=d("");e.resolve=function(a){if(a instanceof e)return a;if(null===a)return h;if(void 0===a)return i;if(a===!0)return f;if(a===!1)return g;if(0===a)return j;if(""===a)return k;if("object"==typeof a||"function"==typeof a)try{var b=a.then;if("function"==typeof b)return new e(b.bind(a))}catch(c){return new e(function(a,b){b(c)})}return d(a)},e.all=function(a){var b=Array.prototype.slice.call(a);return new e(function(a,c){function d(g,h){if(h&&("object"==typeof h||"function"==typeof h)){if(h instanceof e&&h.then===e.prototype.then){for(;3===h._81;)h=h._65;return 1===h._81?d(g,h._65):(2===h._81&&c(h._65),void h.then(function(a){d(g,a)},c))}var i=h.then;if("function"==typeof i){var j=new e(i.bind(h));return void j.then(function(a){d(g,a)},c)}}b[g]=h,0===--f&&a(b)}if(0===b.length)return a([]);for(var f=b.length,g=0;g<b.length;g++)d(g,b[g])})},e.reject=function(a){return new e(function(b,c){c(a)})},e.race=function(a){return new e(function(b,c){a.forEach(function(a){e.resolve(a).then(b,c)})})},e.prototype["catch"]=function(a){return this.then(null,a)}},{"./core.js":94}],96:[function(a,b,c){"function"!=typeof Promise.prototype.done&&(Promise.prototype.done=function(a,b){var c=arguments.length?this.then.apply(this,arguments):this;c.then(null,function(a){setTimeout(function(){throw a},0)})})},{}],97:[function(a,b,c){a("asap");"undefined"==typeof Promise&&(Promise=a("./lib/core.js"),a("./lib/es6-extensions.js")),a("./polyfill-done.js")},{"./lib/core.js":94,"./lib/es6-extensions.js":95,"./polyfill-done.js":96,asap:92}]},{},[2])(2)});
diff --git a/ui/public/locales/ar.json b/ui/public/locales/ar.json
index df4afa7..0cf6308 100644
--- a/ui/public/locales/ar.json
+++ b/ui/public/locales/ar.json
@@ -1480,4 +1480,4 @@
 "state.stopped": "\u062a\u0648\u0642\u0641",
 "state.stopping": "Stopping",
 "state.suspended": "\u062a\u0645 \u0627\u0644\u0625\u064a\u0642\u0627\u0641"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/ca.json b/ui/public/locales/ca.json
index 465ce78..7d9c2ff 100644
--- a/ui/public/locales/ca.json
+++ b/ui/public/locales/ca.json
@@ -1480,4 +1480,4 @@
 "state.stopped": "Stopped",
 "state.stopping": "Stopping",
 "state.suspended": "Susp\u00e9s"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/de_DE.json b/ui/public/locales/de_DE.json
index 55b3be4..d9adc43 100644
--- a/ui/public/locales/de_DE.json
+++ b/ui/public/locales/de_DE.json
@@ -2198,4 +2198,4 @@
 "state.suspended": "Suspendiert",
 "user.login": "Anmelden",
 "user.logout": "Abmelden"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/el_GR.json b/ui/public/locales/el_GR.json
index ffe6aaf..754cde8 100644
--- a/ui/public/locales/el_GR.json
+++ b/ui/public/locales/el_GR.json
@@ -1578,6 +1578,8 @@
 "label.shared": "Κοινόχρηστο",
 "label.sharedexecutable": "Κοινόχρηστο",
 "label.sharedmountpoint": "Κοινόχρηστο μέσο",
+"label.sharedrouterip": "Διεύθυνση IPv4 του δρομολογητή στο κοινόχρηστο δίκτυο ",
+"label.sharedrouteripv6": "Διεύθυνση IPv6 του δρομολογητή στο κοινόχρηστο δίκτυο",
 "label.sharewith": "Κοινή χρήση με",
 "label.showing": "Προβολή",
 "label.shrinkok": "Συρρίκνωση OK",
@@ -2720,4 +2722,4 @@
 "state.suspended": "Ανεσταλμένο",
 "user.login": "Σύνδεση χρήστη",
 "user.logout": "Αποσύνδεση χρήστη"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 0691c2d..338ef39 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -69,6 +69,8 @@
 "label.action.delete.egress.firewall": "Delete egress firewall rule",
 "label.action.delete.firewall": "Delete firewall rule",
 "label.action.delete.interface.static.route": "Remove Tungsten Fabric interface static route",
+"label.action.delete.guest.os": "Delete guest os",
+"label.action.delete.guest.os.hypervisor.mapping": "Delete guest os hypervisor mapping",
 "label.action.delete.ip.range": "Delete IP range",
 "label.action.delete.iso": "Delete ISO",
 "label.action.delete.load.balancer": "Delete load balancer rule",
@@ -123,6 +125,7 @@
 "label.action.expunge.instance": "Expunge instance",
 "label.action.force.reconnect": "Force reconnect",
 "label.action.generate.keys": "Generate keys",
+"label.action.generate.api.secret.keys": "Generate New API/Secret Keys",
 "label.action.get.diagnostics": "Get diagnostics data",
 "label.action.health.monitor": "Health monitor",
 "label.action.image.store.read.only": "Make image store read-only",
@@ -164,6 +167,7 @@
 "label.action.router.health.checks": "Get health checks result",
 "label.action.run.diagnostics": "Run diagnostics",
 "label.action.secure.host": "Provision host security keys",
+"label.action.set.as.source.nat.ip": "make source NAT",
 "label.action.setup.2FA.user.auth": "Setup User Two Factor Authentication",
 "label.action.start.instance": "Start instance",
 "label.action.start.router": "Start router",
@@ -187,6 +191,7 @@
 "label.action.vmsnapshot.revert": "Revert to VM snapshot",
 "label.action.vmstoragesnapshot.create": "Take VM volume snapshot",
 "label.actions": "Actions",
+"label.active": "Active",
 "label.activate.project": "Activate project",
 "label.activeviewersessions": "Active sessions",
 "label.add": "Add",
@@ -210,6 +215,8 @@
 "label.add.firewall": "Add firewall rule",
 "label.add.firewallrule": "Add Firewall Rule",
 "label.add.guest.network": "Add guest network",
+"label.add.guest.os": "Add guest os",
+"label.add.guest.os.hypervisor.mapping": "Add guest os hypervisor mapping",
 "label.add.host": "Add host",
 "label.add.ingress.rule": "Add ingress rule",
 "label.add.intermediate.certificate": "Add intermediate certificate",
@@ -329,6 +336,7 @@
 "label.apply.tungsten.network.policy": "Apply Network Policy",
 "label.apply.tungsten.tag": "Apply tag",
 "label.archive": "Archive",
+"label.archived": "Archived",
 "label.archive.alerts": "Archive alerts",
 "label.archive.events": "Archive events",
 "label.as.default": "as default",
@@ -402,6 +410,7 @@
 "label.bypassvlanoverlapcheck": "Bypass VLAN id/range overlap",
 "label.cachemode": "Write-cache type",
 "label.cancel": "Cancel",
+"label.cancel.shutdown": "Cancel Shutdown",
 "label.cancelmaintenance": "Cancel maintenance",
 "label.capacity": "Capacity",
 "label.capacitybytes": "Capacity bytes",
@@ -438,6 +447,7 @@
 "label.clear.list": "Clear list",
 "label.clear.notification": "Clear notification",
 "label.close": "Close",
+"label.cloud.managed": "CloudManaged",
 "label.cloudian.storage": "Cloudian storage",
 "label.cluster": "Cluster",
 "label.cluster.name": "Cluster name",
@@ -452,6 +462,7 @@
 "label.collectiontime": "Collection time",
 "label.columns": "Columns",
 "label.comma.separated.list.description": "Enter comma-separated list of commands",
+"label.command": "Command",
 "label.comments": "Comments",
 "label.communities": "Communities",
 "label.community": "Community",
@@ -503,6 +514,7 @@
 "label.copied.clipboard": "Copied to clipboard",
 "label.copy": "Copy",
 "label.copy.clipboard": "Copy to clipboard",
+"label.copy.consoleurl": "Copy console URL to clipboard",
 "label.copyid": "Copy ID",
 "label.core": "Core",
 "label.core.zone.type": "Core zone type",
@@ -549,6 +561,7 @@
 "label.creating": "Creating",
 "label.creating.iprange": "Creating IP ranges",
 "label.credit": "Credit",
+"label.cron": "Cron expression",
 "label.crosszones": "Cross zones",
 "label.currency": "Currency",
 "label.current": "Current",
@@ -821,6 +834,7 @@
 "label.expunged": "Expunged",
 "label.expunging": "Expunging",
 "label.export.rules": "Export Rules",
+"label.external.managed": "ExternalManaged",
 "label.external.link": "External link",
 "label.externalid": "External Id",
 "label.externalloadbalanceripaddress": "External load balancer IP address.",
@@ -849,6 +863,8 @@
 "label.for": "for",
 "label.forbidden": "Forbidden",
 "label.forced": "Force",
+"label.force.stop": "Force stop",
+"label.force.reboot": "Force reboot",
 "label.forceencap": "Force UDP encapsulation of ESP packets",
 "label.forgedtransmits": "Forged transmits",
 "label.format": "Format",
@@ -886,6 +902,8 @@
 "label.guest.ip.range": "Guest IP range",
 "label.guest.netmask": "Guest netmask",
 "label.guest.networks": "Guest networks",
+"label.guest.os": "Guest OS",
+"label.guest.os.hypervisor.mappings": "Guest OS mappings",
 "label.guest.start.ip": "Guest start IP",
 "label.guest.traffic": "Guest traffic",
 "label.guestcidraddress": "Guest CIDR",
@@ -908,6 +926,7 @@
 "label.haenable": "HA enabled",
 "label.haprovider": "HA provider",
 "label.hardware": "Hardware",
+"label.hasrules":"FW rules defined",
 "label.hastate": "HA state",
 "label.header.backup.schedule": "You can set up recurring backup schedules by selecting from the available options below and applying your policy preference.",
 "label.header.volume.snapshot": "You can set up recurring snapshot schedules by selecting from the available options below and applying your policy preference.",
@@ -1068,6 +1087,7 @@
 "label.issourcenat": "Source NAT",
 "label.isstaticnat": "Static NAT",
 "label.issystem": "Is system",
+"label.isuserdefined": "User defined",
 "label.isvolatile": "Volatile",
 "label.items": "items",
 "label.items.selected": "item(s) selected",
@@ -1101,6 +1121,7 @@
 "label.kubernetes.version.update": "Manage Kubernetes version",
 "label.kubernetesversionid": "Kubernetes version",
 "label.kubernetesversionname": "Kubernetes version",
+"label.kvm": "KVM",
 "label.kvmnetworklabel": "KVM traffic label",
 "label.l2": "L2",
 "label.l2gatewayserviceuuid": "L2 Gateway Service UUID",
@@ -1164,6 +1185,7 @@
 "label.logout": "Logout",
 "label.lun": "LUN",
 "label.lun.number": "LUN #",
+"label.lxc": "LXC",
 "label.lxcnetworklabel": "LXC traffic label",
 "label.macaddress": "MAC address",
 "label.macaddress.example": "The MAC address. Example: 01:23:45:67:89:ab",
@@ -1333,6 +1355,10 @@
 "label.nfsserver": "NFS server",
 "label.nic": "NIC",
 "label.nicadaptertype": "NIC adapter type",
+"label.nicmultiqueuenumber" : "NIC multiqueue number",
+"label.nicmultiqueuenumber.tooltip" : "NIC multiqueue number. This supports only KVM. The value \"-1\" indicates the NIC multiqueue number will be set to the vCPU number of the instance.",
+"label.nicpackedvirtqueuesenabled" : "NIC packed virtqueues enabled",
+"label.nicpackedvirtqueuesenabled.tooltip" : "Enable NIC packed virtqueues or not. This supports only KVM with QEMU >= 4.2.0 and Libvirt >=6.3.0.",
 "label.nics": "NICs",
 "label.no": "No",
 "label.no.data": "No data to show",
@@ -1373,7 +1399,12 @@
 "label.operator.equal": "Equals to",
 "label.optional": "Optional",
 "label.order": "Order",
-"label.oscategoryid": "OS preference",
+"label.oscategoryid": "OS category",
+"label.oscategoryname": "OS category name",
+"label.osname": "OS name",
+"label.osdisplayname": "OS name",
+"label.osmappingcheckenabled": "Check OS name with hypervisor",
+"label.osnameforhypervisor": "Hypervisor mapping name",
 "label.ostypeid": "OS type",
 "label.osdistribution": "OS distribution",
 "label.ostypename": "OS type",
@@ -1392,6 +1423,7 @@
 "label.overridepublictraffic": "Override public-traffic",
 "label.override.root.diskoffering": "Override root disk offering",
 "label.ovf.properties": "vApp properties",
+"label.ovm3": "OVM3",
 "label.ovm3cluster": "Native Clustering",
 "label.ovm3networklabel": "OVM3 traffic label",
 "label.ovm3pool": "Native pooling",
@@ -1418,6 +1450,7 @@
 "label.pavr": "Virtual router",
 "label.payload": "Payload",
 "label.pcidevice": "GPU",
+"label.pending.jobs": "Pending Jobs",
 "label.per.account": "Per account",
 "label.per.zone": "Per zone",
 "label.percentage": "Percentage",
@@ -1456,6 +1489,7 @@
 "label.preferred": "Preferred",
 "label.prefix": "Prefix",
 "label.prefix.type": "Prefix type",
+"label.prepare.for.shutdown": "Prepare for Shutdown",
 "label.prepareformaintenance": "Prepare for Maintenance",
 "label.presetup": "PreSetup",
 "label.prev": "Prev",
@@ -1657,8 +1691,8 @@
 "label.router.health.check.success": "Success",
 "label.router.health.checks": "Health checks",
 "label.routercount": "Total of virtual routers",
-"label.routerip": "IPv4 address for the VR in this shared network.",
-"label.routeripv6": "IPv6 address for the VR in this shared network.",
+"label.routerip": "IPv4 address for the VR in this network.",
+"label.routeripv6": "IPv6 address for the VR in this network.",
 "label.resourcegroup": "Resource group",
 "label.routing.policy": "Routing policy",
 "label.routing.policy.terms": "Routing policy terms",
@@ -1697,8 +1731,10 @@
 "label.scaleup.policies": "ScaleUp policies",
 "label.scaleup.policy": "ScaleUp policy",
 "label.schedule": "Schedule",
+"label.schedule.add": "Add schedule",
 "label.scheduled.backups": "Scheduled backups",
 "label.scheduled.snapshots": "Scheduled snapshots",
+"label.schedules": "Schedules",
 "label.scope": "Scope",
 "label.search": "Search",
 "label.secondary.isolated.vlan.type.isolated": "Isolated",
@@ -1723,6 +1759,7 @@
 "label.select-view": "Select view",
 "label.select.a.zone": "Select a zone",
 "label.select.deployment.infrastructure": "Select deployment infrastructure",
+"label.select.guest.os.type": "Please select the guest OS type",
 "label.select.network": "Select Network",
 "label.select.period": "Select period",
 "label.select.project": "Select project",
@@ -1764,6 +1801,8 @@
 "label.shared": "Shared",
 "label.sharedexecutable": "Shared",
 "label.sharedmountpoint": "SharedMountPoint",
+"label.sharedrouterip": "IPv4 address for the VR in this shared network.",
+"label.sharedrouteripv6": "IPv6 address for the VR in this shared network.",
 "label.sharewith": "Share with",
 "label.showing": "Showing",
 "label.shrinkok": "Shrink OK",
@@ -1792,6 +1831,7 @@
 "label.sourceipaddress": "Source IP address",
 "label.sourceipaddressnetworkid": "Network ID of source IP address",
 "label.sourcenat": "Source NAT",
+"label.sourcenatipaddress": "Source NAT IP address",
 "label.sourcenatsupported": "Source NAT supported",
 "label.sourcenattype": "Supported source NAT type",
 "label.sourceport": "Source port",
@@ -1843,6 +1883,7 @@
 "label.startport": "Start port",
 "label.startquota": "Quota value",
 "label.state": "State",
+"label.staticnat": "Static NAT",
 "label.static.routes": "Static routes",
 "label.status": "Status",
 "label.step.1": "Step 1",
@@ -1975,6 +2016,7 @@
 "label.traffic.types": "Traffic types",
 "label.traffictype": "Traffic type",
 "label.transportzoneuuid": "Transport zone UUID",
+"label.trigger.shutdown": "Trigger Safe Shutdown",
 "label.try.again": "Try again",
 "label.tuesday": "Tuesday",
 "label.two.factor.authentication.secret.key": "Your Two factor authentication secret key",
@@ -2019,6 +2061,7 @@
 "label.unit": "Usage unit",
 "label.unknown": "Unknown",
 "label.unlimited": "Unlimited",
+"label.unmanaged": "Unmanaged",
 "label.unmanage.instance": "Unmanage instance",
 "label.unmanaged.instance": "Unmanaged instance",
 "label.unmanaged.instances": "Unmanaged instances",
@@ -2117,8 +2160,10 @@
 "label.vmlimit": "Instance limits",
 "label.vmname": "VM name",
 "label.vms": "VMs",
+"label.vmscheduleactions": "Actions",
 "label.vmstate": "VM state",
 "label.vmtotal": "Total of VMs",
+"label.vmware": "VMware",
 "label.vmware.storage.policy": "VMWare storage policy",
 "label.vmwaredcid": "VMware datacenter ID",
 "label.vmwaredcname": "VMware datacenter name",
@@ -2181,6 +2226,7 @@
 "label.writeio": "Write (IO)",
 "label.writethrough": "Write-through",
 "label.xennetworklabel": "XenServer Traffic Label",
+"label.xenserver": "XenServer",
 "label.xenservertoolsversion61plus": "Original XS Version is 6.1+",
 "label.yes": "Yes",
 "label.yourinstance": "Your instance",
@@ -2209,6 +2255,8 @@
 "message.action.delete.external.firewall": "Please confirm that you would like to remove this external firewall. Warning: If you are planning to add back the same external firewall, you must reset usage data on the device.",
 "message.action.delete.external.load.balancer": "Please confirm that you would like to remove this external load balancer. Warning: If you are planning to add back the same external load balancer, you must reset usage data on the device.",
 "message.action.delete.ingress.rule": "Please confirm that you want to delete this ingress rule.",
+"message.action.delete.guest.os": "Please confirm that you want to delete this guest os. System defined entry cannot be deleted.",
+"message.action.delete.guest.os.hypervisor.mapping": "Please confirm that you want to delete this guest os hypervisor mapping. System defined entry cannot be deleted.",
 "message.action.delete.instance.group": "Please confirm that you want to delete the instance group.",
 "message.action.delete.interface.static.route": "Please confirm that you want to remove this interface Static Route?",
 "message.action.delete.iso": "Please confirm that you want to delete this ISO.",
@@ -2356,6 +2404,7 @@
 "message.backup.create": "Are you sure you want create a VM backup?",
 "message.backup.offering.remove": "Are you sure you want to remove VM from backup offering and delete the backup chain?",
 "message.backup.restore": "Please confirm that you want to restore the vm backup?",
+"message.cancel.shutdown": "Please confirm that you would like to cancel the  shutdown on this Management server. It will resume accepting any new Async Jobs.",
 "message.certificate.upload.processing": "Certificate upload in progress",
 "message.change.offering.confirm": "Please confirm that you wish to change the service offering of this virtual instance.",
 "message.change.offering.for.volume": "Successfully changed offering for the volume",
@@ -2419,6 +2468,7 @@
 "message.confirm.scale.up.system.vm": "Do you really want to scale up the system VM?",
 "message.confirm.start.lb.vm": "Please confirm you want to start LB VM.",
 "message.confirm.sync.storage": "Please confirm you want to sync the storage pool",
+"message.confirm.type": "To confirm, please type",
 "message.confirm.upgrade.router.newer.template": "Please confirm that you want to upgrade router to use newer template.",
 "message.cpu.usage.info": "The CPU usage percentage can exceed 100% if the VM has more than 1 vCPU or when CPU Cap is not enabled. This behavior happens according to the hypervisor being used (e.g: in KVM), due to how they account the stats",
 "message.create.compute.offering": "Compute offering created",
@@ -2553,6 +2603,7 @@
 "message.error.cluster.description": "Please enter Kubernetes cluster description.",
 "message.error.cluster.name": "Please enter cluster name.",
 "message.error.confirm.password": "Please confirm new password.",
+"message.error.confirm.text": "Please enter the confirmation text",
 "message.error.current.password": "Please enter current password.",
 "message.error.custom.disk.size": "Please enter custom disk size.",
 "message.error.date": "Please select a date.",
@@ -2618,6 +2669,7 @@
 "message.error.remove.nic": "There was an error",
 "message.error.remove.secondary.ipaddress": "There was an error removing the secondary IP Address",
 "message.error.remove.tungsten.routing.policy": "Removing Tungsten-Fabric Routing Policy from network failed",
+"message.error.remove.vm.schedule": "Removing Instance Schedule failed",
 "message.error.required.input": "Please enter input",
 "message.error.reset.config": "Unable to reset config to default value",
 "message.error.retrieve.kubeconfig": "Unable to retrieve Kubernetes cluster config",
@@ -2683,7 +2735,7 @@
 "message.failed.to.add": "Failed to add",
 "message.failed.to.assign.vms": "Failed to assign VMs",
 "message.failed.to.remove": "Failed to remove",
-"message.generate.keys": "Please confirm that you would like to generate new keys for this user.",
+"message.generate.keys": "Please confirm that you would like to generate new API/Secret keys for this user.",
 "message.chart.statistic.info": "The shown charts are self-adjustable, that means, if the value gets close to the limit or overpass it, it will grow to adjust the shown value",
 "message.guest.traffic.in.advanced.zone": "Guest network traffic is communication between end-user virtual machines. Specify a range of VLAN IDs or VXLAN network identifiers (VNIs) to carry guest traffic for each physical network.",
 "message.guest.traffic.in.basic.zone": "Guest network traffic is communication between end-user virtual machines. Specify a range of IP addresses that CloudStack can assign to guest VMs. Make sure this range does not overlap the reserved system IP range.",
@@ -2735,6 +2787,7 @@
 "message.linstor.resourcegroup.description": "Linstor resource group to use for primary storage.",
 "message.listnsp.not.return.providerid": "error: listNetworkServiceProviders API doesn't return VirtualRouter provider ID.",
 "message.load.host.failed": "Failed to load hosts.",
+"message.loadbalancer.stickypolicy.configuration": "Customize the load balancer stickiness policy:",
 "message.loading.add.interface.static.route": "Adding interface Static Route...",
 "message.loading.add.network.static.route": "Adding network Static Route...",
 "message.loading.add.policy.rule": "Adding Policy rule...",
@@ -2778,6 +2831,7 @@
 "message.network.offering.promiscuous.mode": "Applicable for guest networks on VMware hypervisor only.\nReject - The switch drops any outbound frame from a virtual machine adapter with a source MAC address that is different from the one in the .vmx configuration file.\nAccept - The switch does not perform filtering, and permits all outbound frames.\nNone - Default to value from global setting.",
 "message.network.removenic": "Please confirm that want to remove this NIC, which will also remove the associated network from the VM.",
 "message.network.secondaryip": "Please confirm that you would like to acquire a new secondary IP for this NIC. \n NOTE: You need to manually configure the newly-acquired secondary IP inside the virtual machine.",
+"message.network.selection": "Choose one or more networks to attach the instance to. A new network can also be created here.",
 "message.network.updateip": "Please confirm that you would like to change the IP address for this NIC on VM.",
 "message.network.usage.info.data.points": "Each data point represents the difference in data traffic since the last data point.",
 "message.network.usage.info.sum.of.vnics": "The network usage shown is made up of the sum of data traffic from all the vNICs in the VM.",
@@ -2795,6 +2849,7 @@
 "message.please.wait.while.zone.is.being.created": "Please wait while your zone is being created; this may take a while...",
 "message.pod.dedicated": "Pod dedicated.",
 "message.pod.dedication.released": "Pod dedication released.",
+"message.prepare.for.shutdown": "Please confirm that you would like to prep this Management server for shutdown. It will not accept any new Async Jobs but will NOT terminate after there are no pending jobs.",
 "message.primary.storage.invalid.state": "Primary storage is not in Up state",
 "message.processing.complete": "Processing complete!",
 "message.protocol.description": "For XenServer, choose NFS, iSCSI, or PreSetup. For KVM, choose NFS, SharedMountPoint, RDB, CLVM or Gluster. For vSphere, choose NFS, PreSetup (VMFS or iSCSI or FiberChannel or vSAN or vVols) or DatastoreCluster. For Hyper-V, choose SMB/CIFS. For LXC, choose NFS or SharedMountPoint. For OVM, choose NFS or OCFS2.",
@@ -2870,6 +2925,9 @@
 "message.setup.physical.network.during.zone.creation": "When adding a zone, you need to set up one or more physical networks. Each network corresponds to a NIC on the hypervisor. Each physical network can carry one or more types of traffic, with certain restrictions on how they may be combined. Add or remove one or more traffic types onto each physical network.",
 "message.setup.physical.network.during.zone.creation.basic": "When adding a basic zone, you can set up one physical network, which corresponds to a NIC on the hypervisor. The network carries several types of traffic.<br/><br/>You may also <strong>add</strong> other traffic types onto the physical network.",
 "message.shared.network.offering.warning": "Domain admins and regular users can only create shared networks from network offering with the setting specifyvlan=false. Please contact an administrator to create a network offering if this list is empty.",
+"message.shutdown.triggered": "A shutdown has been triggered. CloudStack will not accept new jobs",
+"message.sourcenatip.change.warning": "WARNING: Changing the sourcenat IP address of the network will cause connectivity downtime for the VMs with NICs in the network.",
+"message.sourcenatip.change.inhibited": "Changing the sourcenat to this IP of the network to this address is inhibited as firewall rules are defined for it. This can include port forwarding or load balancing rules.\n - If this is an isolated network, please use updateNetwork/click the edit button.\n - If this is a VPC, first clear all other rules for this address.",
 "message.specify.tag.key": "Please specify a tag key.",
 "message.specify.tag.value": "Please specify a tag value.",
 "message.step.2.continue": "Please select a service offering to continue.",
@@ -2914,6 +2972,7 @@
 "message.success.config.backup.schedule": "Successfully configured VM backup schedule",
 "message.success.config.health.monitor": "Successfully Configure Health Monitor",
 "message.success.config.sticky.policy": "Successfully configured sticky policy",
+"message.success.config.vm.schedule": "Successfully configured instance schedule",
 "message.success.copy.clipboard": "Successfully copied to clipboard",
 "message.success.create.account": "Successfully created account",
 "message.success.create.internallb": "Successfully created Internal Load Balancer",
@@ -2995,6 +3054,7 @@
 "message.template.type.change.warning": "WARNING: Changing the template type to SYSTEM will disable further changes to the template.",
 "message.tooltip.reserved.system.netmask": "The network prefix that defines the pod subnet. Uses CIDR notation.",
 "message.traffic.type.to.basic.zone": "traffic type to basic zone",
+"message.trigger.shutdown": "Please confirm that you would like to trigger a shutdown on this Management server. It will not accept any new Async Jobs and will terminate after there are no pending jobs.",
 "message.type.values.to.add": "Please add additonal values by typing them in",
 "message.update.autoscale.policy.failed": "Failed to update autoscale policy",
 "message.update.autoscale.vmgroup.failed": "Failed to update autoscale vm group",
diff --git a/ui/public/locales/es.json b/ui/public/locales/es.json
index 939aa5c..7648893 100644
--- a/ui/public/locales/es.json
+++ b/ui/public/locales/es.json
@@ -1512,4 +1512,4 @@
 "state.stopped": "Detenidas",
 "state.stopping": "Parando",
 "state.suspended": "Suspendido"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/fr_FR.json b/ui/public/locales/fr_FR.json
index 6aaafb5..f11f4ac 100644
--- a/ui/public/locales/fr_FR.json
+++ b/ui/public/locales/fr_FR.json
@@ -1482,4 +1482,4 @@
 "state.stopped": "Arr\u00eat\u00e9e",
 "state.stopping": "Arr\u00eat en cours",
 "state.suspended": "Suspendu"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/hi.json b/ui/public/locales/hi.json
index 45c6ee6..0559093 100644
--- a/ui/public/locales/hi.json
+++ b/ui/public/locales/hi.json
@@ -461,4 +461,4 @@
 "label.zone": "ज़ोन",
 "label.zoneid": "ज़ोन",
 "label.zonename": "ज़ोन नाम"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/hu.json b/ui/public/locales/hu.json
index 8e58fa6..3810b39 100644
--- a/ui/public/locales/hu.json
+++ b/ui/public/locales/hu.json
@@ -1480,4 +1480,4 @@
 "state.stopped": "Le\u00e1ll\u00edtva",
 "state.stopping": "Le\u00e1ll\u00e1s folyamatban",
 "state.suspended": "Felf\u00fcggesztett"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/it_IT.json b/ui/public/locales/it_IT.json
index 15faa8f..ab3ff76 100644
--- a/ui/public/locales/it_IT.json
+++ b/ui/public/locales/it_IT.json
@@ -1480,4 +1480,4 @@
 "state.stopped": "Arrestato",
 "state.stopping": "Arresto in corso",
 "state.suspended": "Sospeso"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/ja_JP.json b/ui/public/locales/ja_JP.json
index 19938b9..f151828 100644
--- a/ui/public/locales/ja_JP.json
+++ b/ui/public/locales/ja_JP.json
@@ -2046,6 +2046,8 @@
   "label.shared": "共有",
   "label.sharedexecutable": "共有",
   "label.sharedmountpoint": "SharedMountPoint",
+  "label.sharedrouterip": "共有ネットワークのルーターのIPv4アドレス",
+  "label.sharedrouteripv6": "共有ネットワークのルーターのIPv6アドレス",
   "label.sharewith": "共有",
   "label.show.ingress.rule": "受信ルールの表示",
   "label.showing": "表示中",
diff --git a/ui/public/locales/ko_KR.json b/ui/public/locales/ko_KR.json
index 68c6fe9..a34cdea 100644
--- a/ui/public/locales/ko_KR.json
+++ b/ui/public/locales/ko_KR.json
@@ -1373,6 +1373,8 @@
 "label.shared": "shared",
 "label.sharedexecutable": "\uacf5\uc720",
 "label.sharedmountpoint": "\uacf5\uc720 \ub9c8\uc6b4\ud2b8 \ud3ec\uc778\ud2b8",
+"label.sharedrouterip": "\uc11c\ube44\uc2a4\uc6a9 \ub124\ud2b8\uc6cc\ud06c\uc758 \ub77c\uc6b0\ud130\uc5d0 \ub300\ud55c IPv4 \uc8fc\uc18c",
+"label.sharedrouteripv6": "\uc11c\ube44\uc2a4\uc6a9 \ub124\ud2b8\uc6cc\ud06c\uc758 \ub77c\uc6b0\ud130\uc5d0 \ub300\ud55c IPv6 \uc8fc\uc18c",
 "label.sharewith": "\uacf5\uc720",
 "label.showing": "\ubcf4\uae30",
 "label.shrinkok": "\ubcc0\uacbd \uc644\ub8cc",
@@ -2324,4 +2326,4 @@
 "state.suspended": "\uc77c\uc2dc\uc815\uc9c0",
 "user.login": "\ub85c\uadf8\uc778",
 "user.logout": "\ub85c\uadf8\uc544\uc6c3"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/nb_NO.json b/ui/public/locales/nb_NO.json
index b9e7664..a0fbd89 100644
--- a/ui/public/locales/nb_NO.json
+++ b/ui/public/locales/nb_NO.json
@@ -1480,4 +1480,4 @@
 "state.stopped": "Stoppet",
 "state.stopping": "Stopper",
 "state.suspended": "Pauset"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/nl_NL.json b/ui/public/locales/nl_NL.json
index 07951cc..87c107b 100644
--- a/ui/public/locales/nl_NL.json
+++ b/ui/public/locales/nl_NL.json
@@ -1481,4 +1481,4 @@
 "state.stopped": "Gestopt",
 "state.stopping": "Stoppen",
 "state.suspended": "Gepauzeerd"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/pl.json b/ui/public/locales/pl.json
index e91eae4..135a684 100644
--- a/ui/public/locales/pl.json
+++ b/ui/public/locales/pl.json
@@ -1481,4 +1481,4 @@
 "state.stopped": "Zatrzymano",
 "state.stopping": "Stopping",
 "state.suspended": "Zawieszono"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/pt_BR.json b/ui/public/locales/pt_BR.json
index 712d9f1..1e73684 100644
--- a/ui/public/locales/pt_BR.json
+++ b/ui/public/locales/pt_BR.json
@@ -1468,6 +1468,8 @@
 "label.shared": "Compatilhado",
 "label.sharedexecutable": "Compatilhado",
 "label.sharedmountpoint": "SharedMountPoint",
+"label.sharedrouterip": "Endere\u00e7os IPv4 para o roteador dentro da rede compartilhada",
+"label.sharedrouteripv6": "Endere\u00e7os IPv6 para o roteador dentro da rede compartilhada",
 "label.sharewith": "Compartilhar com",
 "label.showing": "Exibindo",
 "label.shrinkok": "Encolhimento OK",
@@ -2504,4 +2506,4 @@
 "state.suspended": "Suspendido",
 "user.login": "Entrar",
 "user.logout": "Sair"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/ru_RU.json b/ui/public/locales/ru_RU.json
index f855035..f68d767 100644
--- a/ui/public/locales/ru_RU.json
+++ b/ui/public/locales/ru_RU.json
@@ -1479,4 +1479,4 @@
 "state.stopped": "\u041e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e",
 "state.stopping": "\u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c",
 "state.suspended": "\u041f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e"
-}
\ No newline at end of file
+}
diff --git a/ui/public/locales/zh_CN.json b/ui/public/locales/zh_CN.json
index 7ba77fd..91353d2 100644
--- a/ui/public/locales/zh_CN.json
+++ b/ui/public/locales/zh_CN.json
@@ -2333,6 +2333,8 @@
   "label.shared": "\u5DF2\u5171\u4EAB",
   "label.sharedexecutable": "\u5DF2\u5171\u4EAB",
   "label.sharedmountpoint": "\u5171\u4EAB\u6302\u8F7D\u70B9",
+  "label.sharedrouterip": "\u5171\u4EAB\u7F51\u7EDC\u4E2D\u8DEF\u7531\u5668\u7684 IPv4 \u5730\u5740",
+  "label.sharedrouteripv6": "\u5171\u4EAB\u7F51\u7EDC\u4E2D\u8DEF\u7531\u5668\u7684 IPv6 \u5730\u5740",
   "label.sharewith": "\u5206\u4EAB",
 
   "label.show.ingress.rule": "\u663E\u793A\u5165\u53E3\u89C4\u5219",
@@ -4016,4 +4018,4 @@
   "title.upload.volume": "\u4E0A\u4F20\u5377",
   "user.login": "\u767B\u5F55",
   "user.logout": "\u6CE8\u9500"
-}
\ No newline at end of file
+}
diff --git a/ui/src/assets/icons/dark.svg b/ui/src/assets/icons/dark.svg
index 9190c1d..b1dd4b3 100644
--- a/ui/src/assets/icons/dark.svg
+++ b/ui/src/assets/icons/dark.svg
@@ -36,4 +36,4 @@
             </g>
         </g>
     </g>
-</svg>
\ No newline at end of file
+</svg>
diff --git a/ui/src/assets/icons/debian.svg b/ui/src/assets/icons/debian.svg
index b28d3a2..06df6bc 100644
--- a/ui/src/assets/icons/debian.svg
+++ b/ui/src/assets/icons/debian.svg
@@ -150,4 +150,4 @@
    inkscape:connector-curvature="0" />
 		</g>
 	</g>
-</svg>
\ No newline at end of file
+</svg>
diff --git a/ui/src/assets/icons/kubernetes.svg b/ui/src/assets/icons/kubernetes.svg
index f4115cb..39d3780 100644
--- a/ui/src/assets/icons/kubernetes.svg
+++ b/ui/src/assets/icons/kubernetes.svg
@@ -55,4 +55,4 @@
      sodipodi:nodetypes="ccccccccsccccscssccsccccccccscccsccccccccccccccscccscsccsccccscscsccccccccscccscsccccsccccscscscccccccccccccccscccsccccccccccccscccccscccccccccccccccccccccccscccscccccccccscccscccc"
      inkscape:export-filename="./path3059.png"
      inkscape:export-xdpi="250.55"
-     inkscape:export-ydpi="250.55" /></g></svg>
\ No newline at end of file
+     inkscape:export-ydpi="250.55" /></g></svg>
diff --git a/ui/src/assets/icons/light.svg b/ui/src/assets/icons/light.svg
index fbb1000..eb68ad7 100644
--- a/ui/src/assets/icons/light.svg
+++ b/ui/src/assets/icons/light.svg
@@ -37,4 +37,4 @@
             </g>
         </g>
     </g>
-</svg>
\ No newline at end of file
+</svg>
diff --git a/ui/src/components/CheckBoxSelectPair.vue b/ui/src/components/CheckBoxSelectPair.vue
index 19dd8bd..de6aed4 100644
--- a/ui/src/components/CheckBoxSelectPair.vue
+++ b/ui/src/components/CheckBoxSelectPair.vue
@@ -34,13 +34,14 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             @change="val => { handleSelectChange(val) }">
             <a-select-option
               v-for="(opt) in selectSource"
               :key="opt.id"
-              :disabled="opt.enabled === false">
+              :disabled="opt.enabled === false"
+              :label="opt.displaytext || opt.name || opt.description">
               {{ opt.displaytext || opt.name || opt.description }}
             </a-select-option>
           </a-select>
diff --git a/ui/src/components/header/ProjectMenu.vue b/ui/src/components/header/ProjectMenu.vue
index 722bc28..11b1a79 100644
--- a/ui/src/components/header/ProjectMenu.vue
+++ b/ui/src/components/header/ProjectMenu.vue
@@ -27,18 +27,6 @@
       @focus="fetchData"
       showSearch>
 
-      <template #suffixIcon>
-        <a-tooltip placement="bottom">
-          <template #title>
-            <span>{{ $t('label.projects') }}</span>
-          </template>
-          <span class="custom-suffix-icon">
-            <ProjectOutlined v-if="!loading" class="ant-select-suffix" />
-            <LoadingOutlined v-else />
-          </span>
-        </a-tooltip>
-      </template>
-
       <a-select-option
         v-for="(project, index) in projects"
         :key="index"
diff --git a/ui/src/components/header/SamlDomainSwitcher.vue b/ui/src/components/header/SamlDomainSwitcher.vue
index fbb7557..1d820dc 100644
--- a/ui/src/components/header/SamlDomainSwitcher.vue
+++ b/ui/src/components/header/SamlDomainSwitcher.vue
@@ -25,7 +25,7 @@
       showSearch
       optionFilterProp="label"
       :filterOption="(input, option) => {
-        return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+        return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
       }"
       @change="changeAccount"
       @focus="fetchData" >
@@ -42,7 +42,7 @@
         </a-tooltip>
       </template>
 
-      <a-select-option v-for="(account, index) in samlAccounts" :key="index">
+      <a-select-option v-for="(account, index) in samlAccounts" :key="index" :label="`${account.accountName} (${account.domainName})`">
         {{ `${account.accountName} (${account.domainName})` }}
       </a-select-option>
     </a-select>
diff --git a/ui/src/components/header/UserMenu.vue b/ui/src/components/header/UserMenu.vue
index d2b7787..42df044 100644
--- a/ui/src/components/header/UserMenu.vue
+++ b/ui/src/components/header/UserMenu.vue
@@ -29,42 +29,34 @@
         <span v-if="image">
           <resource-icon :image="image" size="2x" style="margin-right: 5px"/>
         </span>
-        <a-avatar v-else-if="userInitials" class="user-menu-avatar avatar" size="small" :style="{ backgroundColor: '#1890ff', color: 'white' }">
+        <a-avatar v-else-if="userInitials" class="user-menu-avatar avatar" size="small" :style="{ backgroundColor: $config.theme['@primary-color'], color: 'white' }">
           {{ userInitials }}
         </a-avatar>
-        <a-avatar v-else class="user-menu-avatar avatar" size="small" :style="{ backgroundColor: '#1890ff', color: 'white' }">
+        <a-avatar v-else class="user-menu-avatar avatar" size="small" :style="{ backgroundColor: $config.theme['@primary-color'], color: 'white' }">
           <template #icon><user-outlined /></template>
         </a-avatar>
         <span>{{ nickname() }}</span>
       </span>
       <template #overlay>
-        <a-menu class="user-menu-wrapper">
-          <router-link :to="{ path: '/accountuser/' + $store.getters.userInfo.id }">
-            <a-menu-item class="user-menu-item" key="0">
-                <UserOutlined class="user-menu-item-icon" />
-                <span class="user-menu-item-name">{{ $t('label.profilename') }}</span>
-            </a-menu-item>
-          </router-link>
-          <a @click="toggleUseBrowserTimezone">
-            <a-menu-item class="user-menu-item" key="1">
-                <ClockCircleOutlined class="user-menu-item-icon" />
-                <span class="user-menu-item-name" style="margin-right: 5px">{{ $t('label.use.local.timezone') }}</span>
-                <a-switch :checked="$store.getters.usebrowsertimezone" />
-            </a-menu-item>
-          </a>
-          <a :href="$config.docBase" target="_blank">
-            <a-menu-item class="user-menu-item" key="2">
-              <QuestionCircleOutlined class="user-menu-item-icon" />
-              <span class="user-menu-item-name">{{ $t('label.help') }}</span>
-            </a-menu-item>
-          </a>
+        <a-menu class="user-menu-wrapper" @click="handleClickMenu">
+          <a-menu-item class="user-menu-item" key="profile">
+            <UserOutlined class="user-menu-item-icon" />
+            <span class="user-menu-item-name">{{ $t('label.profilename') }}</span>
+          </a-menu-item>
+          <a-menu-item class="user-menu-item" key="timezone">
+            <ClockCircleOutlined class="user-menu-item-icon" />
+            <span class="user-menu-item-name" style="margin-right: 5px">{{ $t('label.use.local.timezone') }}</span>
+            <a-switch :checked="$store.getters.usebrowsertimezone" />
+          </a-menu-item>
+          <a-menu-item class="user-menu-item" key="document">
+            <QuestionCircleOutlined class="user-menu-item-icon" />
+            <span class="user-menu-item-name">{{ $t('label.help') }}</span>
+          </a-menu-item>
           <a-menu-divider/>
-          <a href="javascript:;" @click="handleLogout">
-            <a-menu-item class="user-menu-item" key="3">
-              <LogoutOutlined class="user-menu-item-icon" />
-              <span class="user-menu-item-name">{{ $t('label.logout') }}</span>
-            </a-menu-item>
-          </a>
+          <a-menu-item class="user-menu-item" key="logout">
+            <LogoutOutlined class="user-menu-item-icon" />
+            <span class="user-menu-item-name">{{ $t('label.logout') }}</span>
+          </a-menu-item>
         </a-menu>
       </template>
     </a-dropdown>
@@ -145,6 +137,22 @@
         })
       })
     },
+    handleClickMenu (item) {
+      switch (item.key) {
+        case 'profile':
+          this.$router.push(`/accountuser/${this.$store.getters.userInfo.id}`)
+          break
+        case 'timezone':
+          this.toggleUseBrowserTimezone()
+          break
+        case 'document':
+          window.open(this.$config.docBase, '_blank')
+          break
+        case 'logout':
+          this.handleLogout()
+          break
+      }
+    },
     handleLogout () {
       return this.Logout({}).then(() => {
         this.$router.push('/user/login')
diff --git a/ui/src/components/multitab/index.less b/ui/src/components/multitab/index.less
index 917d40d..3ac1760 100644
--- a/ui/src/components/multitab/index.less
+++ b/ui/src/components/multitab/index.less
@@ -28,4 +28,4 @@
 .topmenu .@{multi-tab-wrapper-prefix-cls} {
   max-width: 1200px;
   margin: 0 auto;
-}
\ No newline at end of file
+}
diff --git a/ui/src/components/page/GlobalLayout.vue b/ui/src/components/page/GlobalLayout.vue
index 3f8779d..d807525 100644
--- a/ui/src/components/page/GlobalLayout.vue
+++ b/ui/src/components/page/GlobalLayout.vue
@@ -16,98 +16,105 @@
 // under the License.
 
 <template>
-  <a-layout class="layout" :class="[device]">
-    <a-affix style="z-index: 200">
-      <template v-if="isSideMenu()">
-        <a-drawer
-          v-if="isMobile()"
-          :wrapClassName="'drawer-sider ' + navTheme"
-          :closable="false"
-          :visible="collapsed"
-          placement="left"
-          @close="() => this.collapsed = false"
-        >
-          <side-menu
-            :menus="menus"
-            :theme="navTheme"
-            :collapsed="false"
-            :collapsible="true"
-            mode="inline"
-            @menuSelect="menuSelect"></side-menu>
-        </a-drawer>
-
-        <side-menu
-          v-else
-          mode="inline"
-          :menus="menus"
-          :theme="navTheme"
-          :collapsed="collapsed"
-          :collapsible="true"></side-menu>
-      </template>
-      <template v-else>
-        <a-drawer
-          v-if="isMobile()"
-          :wrapClassName="'drawer-sider ' + navTheme"
-          placement="left"
-          @close="() => this.collapsed = false"
-          :closable="false"
-          :visible="collapsed"
-        >
-          <side-menu
-            :menus="menus"
-            :theme="navTheme"
-            :collapsed="false"
-            :collapsible="true"
-            mode="inline"
-            @menuSelect="menuSelect"></side-menu>
-        </a-drawer>
-      </template>
-
-      <drawer :visible="showSetting" placement="right" v-if="isAdmin && (isDevelopmentMode || allowSettingTheme)">
-        <template #handler>
-          <a-button type="primary" size="large">
-            <close-outlined v-if="showSetting" />
-            <setting-outlined v-else />
-          </a-button>
-        </template>
-        <template #drawer>
-          <setting :visible="showSetting" />
-        </template>
-      </drawer>
-
+  <div>
+    <a-affix v-if="this.$store.getters.shutdownTriggered" >
+      <a-alert :message="$t('message.shutdown.triggered')" type="error" banner :showIcon="false" class="shutdownHeader" />
     </a-affix>
+    <a-layout class="layout" :class="[device]">
+      <a-affix style="z-index: 200" :offsetTop="this.$store.getters.shutdownTriggered ? 25 : 0">
+        <template v-if="isSideMenu()">
+          <a-drawer
+            v-if="isMobile()"
+            :wrapClassName="'drawer-sider ' + navTheme"
+            :closable="false"
+            :visible="collapsed"
+            placement="left"
+            @close="() => this.collapsed = false"
+          >
+            <side-menu
+              :menus="menus"
+              :theme="navTheme"
+              :collapsed="false"
+              :collapsible="true"
+              mode="inline"
+              @menuSelect="menuSelect"></side-menu>
+          </a-drawer>
+          <side-menu
+            v-else
+            mode="inline"
+            :menus="menus"
+            :theme="navTheme"
+            :collapsed="collapsed"
+            :collapsible="true"></side-menu>
+        </template>
+        <template v-else>
+          <a-drawer
+            v-if="isMobile()"
+            :wrapClassName="'drawer-sider ' + navTheme"
+            placement="left"
+            @close="() => this.collapsed = false"
+            :closable="false"
+            :visible="collapsed"
+          >
+            <side-menu
+              :menus="menus"
+              :theme="navTheme"
+              :collapsed="false"
+              :collapsible="true"
+              mode="inline"
+              @menuSelect="menuSelect"></side-menu>
+          </a-drawer>
+        </template>
 
-    <a-layout :class="[layoutMode, `content-width-${contentWidth}`]" :style="{ paddingLeft: contentPaddingLeft, minHeight: '100vh' }">
-      <!-- layout header -->
-      <a-affix style="z-index: 100">
-        <global-header
-          :mode="layoutMode"
-          :menus="menus"
-          :theme="navTheme"
-          :collapsed="collapsed"
-          :device="device"
-          @toggle="toggle"
-        />
+        <drawer :visible="showSetting" placement="right" v-if="isAdmin && (isDevelopmentMode || allowSettingTheme)">
+          <template #handler>
+            <a-button type="primary" size="large">
+              <close-outlined v-if="showSetting" />
+              <setting-outlined v-else />
+            </a-button>
+          </template>
+          <template #drawer>
+            <setting :visible="showSetting" />
+          </template>
+        </drawer>
+
       </a-affix>
 
-      <a-button
-        v-if="showClear"
-        type="default"
-        size="small"
-        class="button-clear-notification"
-        @click="onClearNotification">{{ $t('label.clear.notification') }}</a-button>
+      <a-layout :class="[layoutMode, `content-width-${contentWidth}`]" :style="{ paddingLeft: contentPaddingLeft, minHeight: '100vh' }">
+        <!-- layout header -->
+        <a-affix style="z-index: 100">
+          <global-header
+            :style="this.$store.getters.shutdownTriggered ? 'margin-top: 25px;' : null"
+            :mode="layoutMode"
+            :menus="menus"
+            :theme="navTheme"
+            :collapsed="collapsed"
+            :device="device"
+            @toggle="toggle"
+          />
+        </a-affix>
 
-      <!-- layout content -->
-      <a-layout-content class="layout-content" :class="{'is-header-fixed': fixedHeader}">
-        <slot></slot>
-      </a-layout-content>
+        <a-button
+          v-if="showClear"
+          type="default"
+          size="small"
+          class="button-clear-notification"
+          @click="onClearNotification">{{ $t('label.clear.notification') }}</a-button>
 
-      <!-- layout footer -->
-      <a-layout-footer style="padding: 0">
-        <global-footer />
-      </a-layout-footer>
+        <!-- layout content -->
+        <a-layout-content
+        class="layout-content"
+        :class="{'is-header-fixed': fixedHeader}">
+          <slot></slot>
+        </a-layout-content>
+
+        <!-- layout footer -->
+        <a-layout-footer style="padding: 0">
+          <global-footer />
+        </a-layout-footer>
+      </a-layout>
     </a-layout>
-  </a-layout>
+  </div>
 </template>
 
 <script>
@@ -118,6 +125,7 @@
 import { mapState, mapActions } from 'vuex'
 import { mixin, mixinDevice } from '@/utils/mixin.js'
 import { isAdmin } from '@/role'
+import { api } from '@/api'
 import Drawer from '@/components/widgets/Drawer'
 import Setting from '@/components/view/Setting.vue'
 
@@ -191,6 +199,7 @@
   created () {
     this.menus = this.mainMenu.find((item) => item.path === '/').children
     this.collapsed = !this.sidebarOpened
+    setInterval(this.checkShutdown, 5000)
   },
   mounted () {
     const layoutMode = this.$config.theme['@layout-mode'] || 'light'
@@ -243,6 +252,11 @@
     onClearNotification () {
       this.$notification.destroy()
       this.$store.commit('SET_COUNT_NOTIFY', 0)
+    },
+    checkShutdown () {
+      api('readyForShutdown', {}).then(json => {
+        this.$store.dispatch('SetShutdownTriggered', json.readyforshutdownresponse.readyforshutdown.shutdowntriggered || false)
+      })
     }
   }
 }
@@ -279,4 +293,15 @@
     padding: 0
   }
 }
+
+.shutdownHeader {
+  font-weight: bold;
+  height: 25px;
+  text-align: center;
+  padding: 0px;
+  margin: 0px;
+  width: 100vw;
+  position: absolute;
+}
+
 </style>
diff --git a/ui/src/components/view/ActionButton.vue b/ui/src/components/view/ActionButton.vue
index 95554f2..f15ec2f 100644
--- a/ui/src/components/view/ActionButton.vue
+++ b/ui/src/components/view/ActionButton.vue
@@ -21,14 +21,36 @@
       <template #title>
         {{ $t('label.view.console') }}
       </template>
-      <console :resource="resource" :size="size" />
+      <console
+        style="margin-top: -5px;"
+        :resource="resource"
+        size="default"
+        v-if="resource.id"
+        icon="code"
+      />
+    </a-tooltip>
+    <a-tooltip arrowPointAtCenter placement="bottomRight" v-if="resource && resource.id && dataView">
+      <template #title>
+        {{ $t('label.copy.consoleurl') }}
+      </template>
+      <console
+        copyUrlToClipboard
+        style="margin-top: -5px;"
+        :resource="resource"
+        size="default"
+        v-if="resource.id"
+        icon="copy"
+      />
     </a-tooltip>
     <a-tooltip
       v-for="(action, actionIndex) in actions"
       :key="actionIndex"
       arrowPointAtCenter
       placement="bottomRight">
-      <template #title>
+      <template v-if="action.hoverLabel" #title>
+        {{ $t(action.hoverLabel) }}
+      </template>
+      <template v-else #title>
         {{ $t(action.label) }}
       </template>
       <a-badge
diff --git a/ui/src/components/view/AnnotationsTab.vue b/ui/src/components/view/AnnotationsTab.vue
index 36539a2..97cf926 100644
--- a/ui/src/components/view/AnnotationsTab.vue
+++ b/ui/src/components/view/AnnotationsTab.vue
@@ -96,7 +96,7 @@
         <template #content>
           <div v-ctrl-enter="saveNote">
             <a-textarea
-              rows="4"
+              :rows="4"
               @change="handleNoteChange"
               v-model:value="annotation"
               :placeholder="$t('label.add.note')" />
@@ -192,6 +192,7 @@
         case 'SystemVm': return 'SYSTEM_VM'
         case 'VirtualRouter': return 'VR'
         case 'AutoScaleVmGroup': return 'AUTOSCALE_VM_GROUP'
+        case 'ManagementServer': return 'MANAGEMENT_SERVER'
         default: return ''
       }
     },
diff --git a/ui/src/components/view/BulkActionProgress.vue b/ui/src/components/view/BulkActionProgress.vue
index be21a05..c4068d0 100644
--- a/ui/src/components/view/BulkActionProgress.vue
+++ b/ui/src/components/view/BulkActionProgress.vue
@@ -52,36 +52,38 @@
         size="middle"
         :columns="selectedColumns"
         :dataSource="tableChanged ? filteredItems : selectedItems"
-        :rowKey="(record, idx) => ($route.path.includes('/template') || $route.path.includes('/iso')) ? record.zoneid: record.id"
+        :rowKey="record => ($route.path.includes('/template') || $route.path.includes('/iso')) ? record.zoneid: record.id"
         :pagination="true"
         @change="handleTableChange"
         style="overflow-y: auto">
-        <template #status="{text}">
-          <status :text=" text ? text : $t('state.inprogress') " displayText></status>
-        </template>
-        <template #algorithm="{record}">
-          {{ returnAlgorithmName(record.algorithm) }}
-        </template>
-        <template #privateport="{record}">
-          {{ record.privateport }} - {{ record.privateendport }}
-        </template>
-        <template #publicport="{record}">
-          {{ record.publicport }} - {{ record.publicendport }}
-        </template>
-        <template #protocol="{record}">
-          {{ capitalise(record.protocol) }}
-        </template>
-        <template #startport="{record}">
-          {{ record.icmptype || record.startport >= 0 ? record.icmptype || record.startport : $t('label.all') }}
-        </template>
-        <template #endport="{record}">
-          {{ record.icmpcode || record.endport >= 0 ? record.icmpcode || record.endport : $t('label.all') }}
-        </template>
-        <template #vm="{record}">
-          <div><desktop-outlined /> {{ record.virtualmachinename }} ({{ record.vmguestip }})</div>
-        </template>
-        <template #cidrlist="{ record }">
-          <span style="white-space: pre-line"> {{ record.cidrlist?.replaceAll(" ", "\n") }}</span>
+        <template #bodyCell="{ column, text, record }">
+          <template v-if="column.key === 'status'">
+            <status :text=" text ? text : $t('state.inprogress') " displayText></status>
+          </template>
+          <template v-if="column.key === 'algorithm'">
+            {{ returnAlgorithmName(record.algorithm) }}
+          </template>
+          <template v-if="column.key === 'privateport'">
+            {{ record.privateport }} - {{ record.privateendport }}
+          </template>
+          <template v-if="column.key === 'publicport'">
+            {{ record.publicport }} - {{ record.publicendport }}
+          </template>
+          <template v-if="column.key === 'protocol'">
+            {{ capitalise(record.protocol) }}
+          </template>
+          <template v-if="column.key === 'startport'">
+            {{ record.icmptype || record.startport >= 0 ? record.icmptype || record.startport : $t('label.all') }}
+          </template>
+          <template v-if="column.key === 'endport'">
+            {{ record.icmpcode || record.endport >= 0 ? record.icmpcode || record.endport : $t('label.all') }}
+          </template>
+          <template v-if="column.key === 'vm'">
+            <div><desktop-outlined /> {{ record.virtualmachinename }} ({{ record.vmguestip }})</div>
+          </template>
+          <template v-if="column.key === 'cidrlist'">
+            <span style="white-space: pre-line"> {{ record.cidrlist?.replaceAll(" ", "\n") }}</span>
+          </template>
         </template>
       </a-table>
       <br/>
diff --git a/ui/src/components/view/BulkActionView.vue b/ui/src/components/view/BulkActionView.vue
index a22ab5a..215abb6 100644
--- a/ui/src/components/view/BulkActionView.vue
+++ b/ui/src/components/view/BulkActionView.vue
@@ -55,35 +55,37 @@
           size="middle"
           :columns="selectedColumns"
           :dataSource="selectedItems"
-          :rowKey="(record, idx) => $route.path.includes('/iso/') ? record.zoneid : record.id"
+          :rowKey="record => $route.path.includes('/iso/') ? record.zoneid : record.id"
           :pagination="true"
           style="overflow-y: auto">
-          <template #algorithm="{record}">
-            {{ returnAlgorithmName(record.algorithm) }}
-          </template>
-          <template #column="{ text }">
-            <span v-for="(column, index) in selectedColumns" :key="index"> {{ text }} ==== {{ column }}</span>
-          </template>
-          <template #privateport="{record}">
-            {{ record.privateport }} - {{ record.privateendport }}
-          </template>
-          <template #publicport="{record}">
-            {{ record.publicport }} - {{ record.publicendport }}
-          </template>
-          <template #protocol="{record}">
-            {{ capitalise(record.protocol) }}
-          </template>
-          <template #vm="{record}">
-            <div><desktop-outlined /> {{ record.virtualmachinename }} ({{ record.vmguestip }})</div>
-          </template>
-          <template #startport="{record}">
-            {{ record.icmptype || record.startport >= 0 ? record.icmptype || record.startport : $t('label.all') }}
-          </template>
-          <template #endport="{record}">
-            {{ record.icmpcode || record.endport >= 0 ? record.icmpcode || record.endport : $t('label.all') }}
-          </template>
-          <template #cidrlist="{record}">
-            <span style="white-space: pre-line"> {{ record.cidrlist?.replaceAll(" ", "\n") }}</span>
+          <template #bodyCell="{ column, text, record }">
+            <template v-if="column.key === 'algorithm'">
+              {{ returnAlgorithmName(record.algorithm) }}
+            </template>
+            <template v-if="column.key === 'column'">
+              <span v-for="(column, index) in selectedColumns" :key="index"> {{ text }} ==== {{ column }}</span>
+            </template>
+            <template v-if="column.key === 'privateport'">
+              {{ record.privateport }} - {{ record.privateendport }}
+            </template>
+            <template v-if="column.key === 'publicport'">
+              {{ record.publicport }} - {{ record.publicendport }}
+            </template>
+            <template v-if="column.key === 'protocol'">
+              {{ capitalise(record.protocol) }}
+            </template>
+            <template v-if="column.key === 'vm'">
+              <div><desktop-outlined /> {{ record.virtualmachinename }} ({{ record.vmguestip }})</div>
+            </template>
+            <template v-if="column.key === 'startport'">
+              {{ record.icmptype || record.startport >= 0 ? record.icmptype || record.startport : $t('label.all') }}
+            </template>
+            <template v-if="column.key === 'endport'">
+              {{ record.icmpcode || record.endport >= 0 ? record.icmpcode || record.endport : $t('label.all') }}
+            </template>
+            <template v-if="column.key === 'cidrlist'">
+              <span style="white-space: pre-line"> {{ record.cidrlist?.replaceAll(" ", "\n") }}</span>
+            </template>
           </template>
         </a-table>
         <a-divider />
diff --git a/ui/src/components/view/DedicateDomain.vue b/ui/src/components/view/DedicateDomain.vue
index 5f04083..0b3645c 100644
--- a/ui/src/components/view/DedicateDomain.vue
+++ b/ui/src/components/view/DedicateDomain.vue
@@ -26,12 +26,16 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }"
           @change="handleChangeDomain"
           v-focus="true"
           v-model:value="domainId">
-          <a-select-option v-for="(domain, index) in domainsList" :value="domain.id" :key="index">
+          <a-select-option
+            v-for="(domain, index) in domainsList"
+            :value="domain.id"
+            :key="index"
+            :label="domain.path || domain.name || domain.description">
             {{ domain.path || domain.name || domain.description }}
           </a-select-option>
         </a-select>
@@ -43,9 +47,9 @@
         style="width: 100%"
         @change="handleChangeAccount"
         showSearch
-        optionFilterProp="label"
+        optionFilterProp="value"
         :filterOption="(input, option) => {
-          return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+          return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
         }" >
         <a-select-option v-for="(account, index) in accountsList" :value="account.name" :key="index">
           {{ account.name }}
diff --git a/ui/src/components/view/DetailsTab.vue b/ui/src/components/view/DetailsTab.vue
index 17a4e95..e276e05 100644
--- a/ui/src/components/view/DetailsTab.vue
+++ b/ui/src/components/view/DetailsTab.vue
@@ -112,14 +112,14 @@
       type: Object,
       required: true
     },
-    loading: {
-      type: Boolean,
-      default: false
-    },
     items: {
       type: Object,
       default: () => {}
     },
+    loading: {
+      type: Boolean,
+      default: false
+    },
     bordered: {
       type: Boolean,
       default: false
diff --git a/ui/src/components/view/EventsTab.vue b/ui/src/components/view/EventsTab.vue
index 66f8ae7..899a430 100644
--- a/ui/src/components/view/EventsTab.vue
+++ b/ui/src/components/view/EventsTab.vue
@@ -152,19 +152,15 @@
       for (var columnKey of this.columnKeys) {
         if (!this.selectedColumnKeys.includes(columnKey)) continue
         this.columns.push({
+          key: columnKey,
           title: this.$t('label.' + String(columnKey).toLowerCase()),
           dataIndex: columnKey,
-          slots: { customRender: columnKey },
           sorter: function (a, b) { return genericCompare(a[this.dataIndex] || '', b[this.dataIndex] || '') }
         })
       }
-      this.columns.push({
-        dataIndex: 'dropdownFilter',
-        slots: {
-          filterDropdown: 'filterDropdown',
-          filterIcon: 'filterIcon'
-        }
-      })
+      if (this.columns.length > 0) {
+        this.columns[this.columns.length - 1].customFilterDropdown = true
+      }
     }
   }
 }
diff --git a/ui/src/components/view/InfoCard.vue b/ui/src/components/view/InfoCard.vue
index 0b9ebf4..df1411a 100644
--- a/ui/src/components/view/InfoCard.vue
+++ b/ui/src/components/view/InfoCard.vue
@@ -84,11 +84,31 @@
               <a-tag v-if="resource.internetprotocol && ['IPv6', 'DualStack'].includes(resource.internetprotocol)">
                 {{ resource.internetprotocol ? $t('label.ip.v4.v6') : resource.internetprotocol }}
               </a-tag>
+              <a-tag v-if="resource.archived" :color="this.$config.theme['@warning-color']">
+                {{ $t('label.archived') }}
+              </a-tag>
               <a-tooltip placement="right" >
                 <template #title>
                   <span>{{ $t('label.view.console') }}</span>
                 </template>
-                <console style="margin-top: -5px;" :resource="resource" size="default" v-if="resource.id" />
+                <console
+                  style="margin-top: -5px;"
+                  :resource="resource"
+                  size="default"
+                  v-if="resource.id"
+                />
+              </a-tooltip>
+              <a-tooltip placement="right" >
+                <template #title>
+                  <span>{{ $t('label.copy.consoleurl') }}</span>
+                </template>
+                <console
+                  copyUrlToClipboard
+                  style="margin-top: -5px;"
+                  :resource="resource"
+                  size="default"
+                  v-if="resource.id"
+                />
               </a-tooltip>
             </div>
           </slot>
@@ -124,7 +144,7 @@
               icon="barcode-outlined"
               type="dashed"
               size="small"
-              :copyResource="resource.id"
+              :copyResource="String(resource.id)"
               @onClick="$message.success($t('label.copied.clipboard'))" />
             <span style="margin-left: 10px;">{{ resource.id }}</span>
           </div>
@@ -837,7 +857,7 @@
     },
     name () {
       return this.resource.displayname || this.resource.name || this.resource.displaytext || this.resource.username ||
-        this.resource.ipaddress || this.resource.virtualmachinename || this.resource.templatetype
+        this.resource.ipaddress || this.resource.virtualmachinename || this.resource.osname || this.resource.osdisplayname || this.resource.templatetype
     },
     keypairs () {
       if (!this.resource.keypairs) {
@@ -852,8 +872,13 @@
       return this.resource.templateid
     },
     resourceIcon () {
-      if (this.$showIcon() && this.resource?.icon?.base64image) {
-        return this.resource.icon.base64image
+      if (this.$showIcon()) {
+        if (this.resource?.icon?.base64image) {
+          return this.resource.icon.base64image
+        }
+        if (this.resource?.resourceIcon?.base64image) {
+          return this.resource.resourceIcon.base64image
+        }
       }
       return null
     },
diff --git a/ui/src/components/view/InstanceNicsNetworkSelectListView.vue b/ui/src/components/view/InstanceNicsNetworkSelectListView.vue
index 8ec485c..b9fe55a 100644
--- a/ui/src/components/view/InstanceNicsNetworkSelectListView.vue
+++ b/ui/src/components/view/InstanceNicsNetworkSelectListView.vue
@@ -25,23 +25,25 @@
       :dataSource="nics"
       :pagination="false"
       :rowKey="record => record.InstanceID">
-      <template #displaytext="{record}">
-        <span>{{ record.elementName + ' - ' + record.name }}
-          <a-tooltip :title="record.nicDescription" placement="top">
-            <info-circle-outlined class="table-tooltip-icon" />
-          </a-tooltip>
-        </span>
-      </template>
-      <template #size="{record}">
-        <span v-if="record.size">
-          {{ $bytesToHumanReadableSize(record.size) }}
-        </span>
-      </template>
-      <template #selectednetwork="{record}">
-        <span>{{ record.selectednetworkname || '' }}</span>
-      </template>
-      <template #select="{record}">
-        <div style="display: flex; justify-content: flex-end;"><a-button @click="openNicNetworkSelector(record)">{{ record.selectednetworkid ? $t('label.change') : $t('label.select') }}</a-button></div>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'displaytext'">
+          <span>{{ record.elementName + ' - ' + record.name }}
+            <a-tooltip :title="record.nicDescription" placement="top">
+              <info-circle-outlined class="table-tooltip-icon" />
+            </a-tooltip>
+          </span>
+        </template>
+        <template v-if="column.key === 'size'">
+          <span v-if="record.size">
+            {{ $bytesToHumanReadableSize(record.size) }}
+          </span>
+        </template>
+        <template v-if="column.key === 'selectednetwork'">
+          <span>{{ record.selectednetworkname || '' }}</span>
+        </template>
+        <template v-if="column.key === 'select'">
+          <div style="display: flex; justify-content: flex-end;"><a-button @click="openNicNetworkSelector(record)">{{ record.selectednetworkid ? $t('label.change') : $t('label.select') }}</a-button></div>
+        </template>
       </template>
     </a-table>
 
@@ -87,16 +89,16 @@
     return {
       nicColumns: [
         {
-          title: this.$t('label.nic'),
-          slots: { customRender: 'displaytext' }
+          key: 'displaytext',
+          title: this.$t('label.nic')
         },
         {
-          title: this.$t('label.network'),
-          slots: { customRender: 'selectednetwork' }
+          key: 'selectednetwork',
+          title: this.$t('label.network')
         },
         {
-          title: '',
-          slots: { customRender: 'select' }
+          key: 'select',
+          title: ''
         }
       ],
       selectedNicForNetworkSelection: {}
diff --git a/ui/src/components/view/InstanceVolumesStoragePoolSelectListView.vue b/ui/src/components/view/InstanceVolumesStoragePoolSelectListView.vue
index 4489af6..77f1b49 100644
--- a/ui/src/components/view/InstanceVolumesStoragePoolSelectListView.vue
+++ b/ui/src/components/view/InstanceVolumesStoragePoolSelectListView.vue
@@ -26,16 +26,18 @@
       :dataSource="volumes"
       :pagination="false"
       :rowKey="record => record.id">
-      <template #size="{ record }">
-        <span v-if="record.size">
-          {{ $bytesToHumanReadableSize(record.size) }}
-        </span>
-      </template>
-      <template #selectedstorage="{ record }">
-        <span>{{ record.selectedstoragename || '' }}</span>
-      </template>
-      <template #select="{ record }">
-        <div style="display: flex; justify-content: flex-end;"><a-button @click="openVolumeStoragePoolSelector(record)">{{ record.selectedstorageid ? $t('label.change') : $t('label.select') }}</a-button></div>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'size'">
+          <span v-if="record.size">
+            {{ $bytesToHumanReadableSize(record.size) }}
+          </span>
+        </template>
+        <template v-if="column.key === 'selectedstorage'">
+          <span>{{ record.selectedstoragename || '' }}</span>
+        </template>
+        <template v-if="column.key === 'select'">
+          <div style="display: flex; justify-content: flex-end;"><a-button @click="openVolumeStoragePoolSelector(record)">{{ record.selectedstorageid ? $t('label.change') : $t('label.select') }}</a-button></div>
+        </template>
       </template>
     </a-table>
 
@@ -86,24 +88,26 @@
       volumesLoading: false,
       volumeColumns: [
         {
+          key: 'name',
           title: this.$t('label.volumeid'),
           dataIndex: 'name'
         },
         {
+          key: 'type',
           title: this.$t('label.type'),
           dataIndex: 'type'
         },
         {
-          title: this.$t('label.size'),
-          slots: { customRender: 'size' }
+          key: 'size',
+          title: this.$t('label.size')
         },
         {
-          title: this.$t('label.storage'),
-          slots: { customRender: 'selectedstorage' }
+          key: 'selectedstorage',
+          title: this.$t('label.storage')
         },
         {
-          title: '',
-          slots: { customRender: 'select' }
+          key: 'select',
+          title: ''
         }
       ],
       selectedVolumeForStoragePoolSelection: {},
diff --git a/ui/src/components/view/ListResourceTable.vue b/ui/src/components/view/ListResourceTable.vue
index 398691a..c97aa0f 100644
--- a/ui/src/components/view/ListResourceTable.vue
+++ b/ui/src/components/view/ListResourceTable.vue
@@ -34,22 +34,23 @@
       :pagination="defaultPagination"
       @change="handleTableChange"
       @handle-search-filter="handleTableChange" >
+      <template #bodyCell="{ column, text, record }">
+        <div
+          v-for="(col, index) in Object.keys(routerlinks({}))"
+          :key="index">
+          <template v-if="column.key === col">
+            <router-link :set="routerlink = routerlinks(record)" :to="{ path: routerlink[col] }" >{{ text }}</router-link>
+          </template>
+        </div>
 
-      <template
-        v-for="(column, index) in Object.keys(routerlinks({}))"
-        :key="index"
-        #[column]="{ text, record }" >
-        <router-link :set="routerlink = routerlinks(record)" :to="{ path: routerlink[column] }" >{{ text }}</router-link>
+        <template v-if="column.key === 'state'">
+          <status :text="text ? text : ''" />{{ text }}
+        </template>
+
+        <template v-if="column.key === 'status'">
+          <status :text="text ? text : ''" />{{ text }}
+        </template>
       </template>
-
-      <template #state="{text}">
-        <status :text="text ? text : ''" />{{ text }}
-      </template>
-
-      <template #status="{text}">
-        <status :text="text ? text : ''" />{{ text }}
-      </template>
-
     </a-table>
 
     <div v-if="!defaultPagination" style="display: block; text-align: right; margin-top: 10px;">
@@ -197,9 +198,9 @@
       var columns = []
       for (const col of this.columns) {
         columns.push({
+          key: col,
           dataIndex: col,
-          title: this.$t('label.' + col),
-          slots: { customRender: col }
+          title: this.$t('label.' + col)
         })
       }
       return columns
diff --git a/ui/src/components/view/ListView.vue b/ui/src/components/view/ListView.vue
index 7ccb028..69dc3a1 100644
--- a/ui/src/components/view/ListView.vue
+++ b/ui/src/components/view/ListView.vue
@@ -23,11 +23,11 @@
     :dataSource="items"
     :rowKey="(record, idx) => record.id || record.name || record.usageType || idx + '-' + Math.random()"
     :pagination="false"
-    :rowSelection=" enableGroupAction() || $route.name === 'event' ? {selectedRowKeys: selectedRowKeys, onChange: onSelectChange} : null"
+    :rowSelection=" enableGroupAction() || $route.name === 'event' ? {selectedRowKeys: selectedRowKeys, onChange: onSelectChange, columnWidth: 30} : null"
     :rowClassName="getRowClassName"
     style="overflow-y: auto"
   >
-    <template #filterDropdown>
+    <template #customFilterDropdown>
       <div style="padding: 8px" class="filter-dropdown">
         <a-menu>
           <a-menu-item v-for="(column, idx) in columnKeys" :key="idx" @click="updateSelectedColumns(column)">
@@ -37,391 +37,406 @@
         </a-menu>
       </div>
     </template>
-    <template #footer>
-      <span v-if="hasSelected">
-        {{ `Selected ${selectedRowKeys.length} items` }}
-      </span>
-    </template>
-
-    <!--
-    <div #expandedRowRender="{ resource }">
-      <info-card :resource="resource style="margin-left: 0px; width: 50%">
-        <div #actions style="padding-top: 12px">
-          <a-tooltip
-            v-for="(action, actionIndex) in $route.meta.actions"
-            :key="actionIndex"
-            placement="bottom">
-            <template #title>
-              {{ $t(action.label) }}
-            </template>
-            <a-button
-              v-if="action.api in $store.getters.apis && action.dataView &&
-                ('show' in action ? action.show(resource, $store.getters.userInfo) : true)"
-              :icon="action.icon"
-              :type="action.icon === 'delete' ? 'danger' : (action.icon === 'plus' ? 'primary' : 'default')"
-              shape="circle"
-              style="margin-right: 5px; margin-top: 12px"
-              @click="$parent.execAction(action)"
-            >
-            </a-button>
-          </a-tooltip>
-        </div>
-      </info-card>
-    </div>
-    -->
-
-    <template #name="{text, record}">
-      <span v-if="['vm'].includes($route.path.split('/')[1])" style="margin-right: 5px">
-        <span v-if="record.icon && record.icon.base64image">
-          <resource-icon :image="record.icon.base64image" size="1x"/>
+    <template #bodyCell="{ column, text, record }">
+      <template v-if="column.key === 'name'">
+        <span v-if="['vm'].includes($route.path.split('/')[1])" style="margin-right: 5px">
+          <span v-if="record.icon && record.icon.base64image">
+            <resource-icon :image="record.icon.base64image" size="1x"/>
+          </span>
+          <os-logo v-else :osId="record.ostypeid" :osName="record.osdisplayname" size="lg" />
         </span>
-        <os-logo v-else :osId="record.ostypeid" :osName="record.osdisplayname" size="lg" />
-      </span>
-      <span style="min-width: 120px" >
+        <span style="min-width: 120px" >
+          <QuickView
+            style="margin-left: 5px"
+            :actions="actions"
+            :resource="record"
+            :enabled="quickViewEnabled() && actions.length > 0 && columns && columns[0].dataIndex === 'name' "
+            @exec-action="$parent.execAction"/>
+          <span v-if="$route.path.startsWith('/project')" style="margin-right: 5px">
+            <tooltip-button type="dashed" size="small" icon="LoginOutlined" @onClick="changeProject(record)" />
+          </span>
+          <span v-if="$showIcon() && !['vm'].includes($route.path.split('/')[1])" style="margin-right: 5px">
+            <resource-icon v-if="$showIcon() && record.icon && record.icon.base64image" :image="record.icon.base64image" size="1x"/>
+            <os-logo v-else-if="record.ostypename" :osName="record.ostypename" size="1x" />
+            <render-icon v-else-if="typeof $route.meta.icon ==='string'" style="font-size: 16px;" :icon="$route.meta.icon"/>
+            <render-icon v-else style="font-size: 16px;" :svgIcon="$route.meta.icon" />
+          </span>
+          <span v-else :style="{ 'margin-right': record.ostypename ? '5px' : '0' }">
+            <os-logo v-if="record.ostypename" :osName="record.ostypename" size="1x" />
+          </span>
+
+          <span v-if="record.hasannotations">
+            <span v-if="record.id">
+              <router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
+              <router-link :to="{ path: $route.path + '/' + record.id, query: { tab: 'comments' } }"><message-filled style="padding-left: 10px" size="small"/></router-link>
+            </span>
+            <router-link v-else :to="{ path: $route.path + '/' + record.name }" >{{ text }}</router-link>
+          </span>
+          <span v-else-if="$route.path.startsWith('/globalsetting')">{{ text }}</span>
+          <span v-else-if="$route.path.startsWith('/alert')">
+            <router-link :to="{ path: $route.path + '/' + record.id }" v-if="record.id">{{ $t(text.toLowerCase()) }}</router-link>
+            <router-link :to="{ path: $route.path + '/' + record.name }" v-else>{{ $t(text.toLowerCase()) }}</router-link>
+          </span>
+          <span v-else-if="$route.path.startsWith('/tungstenfabric')">
+            <router-link :to="{ path: $route.path + '/' + record.id }" v-if="record.id">{{ $t(text.toLowerCase()) }}</router-link>
+            <router-link :to="{ path: $route.path + '/' + record.name }" v-else>{{ $t(text.toLowerCase()) }}</router-link>
+          </span>
+          <span v-else-if="isTungstenPath()">
+            <router-link :to="{ path: $route.path + '/' + record.uuid, query: { zoneid: record.zoneid } }" v-if="record.uuid && record.zoneid">{{ $t(text.toLowerCase()) }}</router-link>
+            <router-link :to="{ path: $route.path + '/' + record.uuid, query: { zoneid: $route.query.zoneid } }" v-else-if="record.uuid && $route.query.zoneid">{{ $t(text.toLowerCase()) }}</router-link>
+            <router-link :to="{ path: $route.path }" v-else>{{ $t(text.toLowerCase()) }}</router-link>
+          </span>
+          <span v-else>
+            <router-link :to="{ path: $route.path + '/' + record.id }" v-if="record.id">{{ text }}</router-link>
+            <router-link :to="{ path: $route.path + '/' + record.name }" v-else>{{ text }}</router-link>
+          </span>
+        </span>
+      </template>
+      <template v-if="record.clustertype === 'ExternalManaged' && $route.path.split('/')[1] === 'kubernetes' && ['cpunumber', 'memory', 'size'].includes(column.key)">
+        <span>{{ text <= 0 ? 'N/A' : text }}</span>
+      </template>
+      <template v-if="column.key === 'templatetype'">
+        <router-link :to="{ path: $route.path + '/' + record.templatetype }">{{ text }}</router-link>
+      </template>
+      <template v-if="column.key === 'type'">
+        <span v-if="['USER.LOGIN', 'USER.LOGOUT', 'ROUTER.HEALTH.CHECKS', 'FIREWALL.CLOSE', 'ALERT.SERVICE.DOMAINROUTER'].includes(text)">{{ $t(text.toLowerCase()) }}</span>
+        <span v-else>{{ text }}</span>
+      </template>
+
+      <template v-if="column.key === 'schedule'">
+          {{ text }}
+          <br/>
+          ({{ generateHumanReadableSchedule(text) }})
+      </template>
+      <template v-if="column.key === 'displayname'">
         <QuickView
           style="margin-left: 5px"
           :actions="actions"
           :resource="record"
-          :enabled="quickViewEnabled() && actions.length > 0 && columns && columns[0].dataIndex === 'name' "
+          :enabled="quickViewEnabled() && actions.length > 0 && columns && columns[0].dataIndex === 'displayname' "
           @exec-action="$parent.execAction"/>
-        <span v-if="$route.path.startsWith('/project')" style="margin-right: 5px">
-          <tooltip-button type="dashed" size="small" icon="LoginOutlined" @onClick="changeProject(record)" />
-        </span>
+        <router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
+      </template>
+      <template v-if="column.key === 'username'">
         <span v-if="$showIcon() && !['vm'].includes($route.path.split('/')[1])" style="margin-right: 5px">
           <resource-icon v-if="$showIcon() && record.icon && record.icon.base64image" :image="record.icon.base64image" size="1x"/>
-          <os-logo v-else-if="record.ostypename" :osName="record.ostypename" size="1x" />
-          <render-icon v-else-if="typeof $route.meta.icon ==='string'" style="font-size: 16px;" :icon="$route.meta.icon"/>
-          <render-icon v-else style="font-size: 16px;" :svgIcon="$route.meta.icon" />
+          <user-outlined v-else style="font-size: 16px;" />
         </span>
-        <span v-else :style="{ 'margin-right': record.ostypename ? '5px' : '0' }">
-          <os-logo v-if="record.ostypename" :osName="record.ostypename" size="1x" />
+        <router-link :to="{ path: $route.path + '/' + record.id }" v-if="['/accountuser', '/vpnuser'].includes($route.path)">{{ text }}</router-link>
+        <router-link :to="{ path: '/accountuser', query: { username: record.username, domainid: record.domainid } }" v-else-if="$store.getters.userInfo.roletype !== 'User'">{{ text }}</router-link>
+        <span v-else>{{ text }}</span>
+      </template>
+      <template v-if="column.key === 'entityid'">
+        <router-link :to="{ path: generateCommentsPath(record), query: { tab: 'comments' } }">{{ record.entityname }}</router-link>
+      </template>
+      <template v-if="column.key === 'entitytype'">
+        {{ generateHumanReadableEntityType(record) }}
+      </template>
+      <template v-if="column.key === 'adminsonly' && ['Admin'].includes($store.getters.userInfo.roletype)">
+        <a-checkbox :checked="record.adminsonly" :value="record.id" v-if="record.userid === $store.getters.userInfo.id" @change="e => updateAdminsOnly(e)" />
+        <a-checkbox :checked="record.adminsonly" disabled v-else />
+      </template>
+      <template v-if="column.key === 'ipaddress'" href="javascript:;">
+        <router-link v-if="['/publicip', '/privategw'].includes($route.path)" :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
+        <span v-else>{{ text }}</span>
+        <span v-if="record.issourcenat">
+          &nbsp;
+          <a-tag>source-nat</a-tag>
         </span>
-
-        <span v-if="record.hasannotations">
-          <span v-if="record.id">
-            <router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
-            <router-link :to="{ path: $route.path + '/' + record.id, query: { tab: 'comments' } }"><message-filled style="padding-left: 10px" size="small"/></router-link>
-          </span>
-          <router-link v-else :to="{ path: $route.path + '/' + record.name }" >{{ text }}</router-link>
+        <span v-if="record.isstaticnat">
+          &nbsp;
+          <a-tag>static-nat</a-tag>
         </span>
-        <span v-else-if="$route.path.startsWith('/globalsetting')">{{ text }}</span>
-        <span v-else-if="$route.path.startsWith('/preferences')">{{ text }}</span>
-        <span v-else-if="$route.path.startsWith('/alert')">
-          <router-link :to="{ path: $route.path + '/' + record.id }" v-if="record.id">{{ $t(text.toLowerCase()) }}</router-link>
-          <router-link :to="{ path: $route.path + '/' + record.name }" v-else>{{ $t(text.toLowerCase()) }}</router-link>
-        </span>
-        <span v-else-if="$route.path.startsWith('/tungstenfabric')">
-          <router-link :to="{ path: $route.path + '/' + record.id }" v-if="record.id">{{ $t(text.toLowerCase()) }}</router-link>
-          <router-link :to="{ path: $route.path + '/' + record.name }" v-else>{{ $t(text.toLowerCase()) }}</router-link>
-        </span>
-        <span v-else-if="isTungstenPath()">
-          <router-link :to="{ path: $route.path + '/' + record.uuid, query: { zoneid: record.zoneid } }" v-if="record.uuid && record.zoneid">{{ $t(text.toLowerCase()) }}</router-link>
-          <router-link :to="{ path: $route.path + '/' + record.uuid, query: { zoneid: $route.query.zoneid } }" v-else-if="record.uuid && $route.query.zoneid">{{ $t(text.toLowerCase()) }}</router-link>
-          <router-link :to="{ path: $route.path }" v-else>{{ $t(text.toLowerCase()) }}</router-link>
-        </span>
-        <span v-else>
-          <router-link :to="{ path: $route.path + '/' + record.id }" v-if="record.id">{{ text }}</router-link>
-          <router-link :to="{ path: $route.path + '/' + record.name }" v-else>{{ text }}</router-link>
-        </span>
+      </template>
+      <template v-if="column.key === 'ip6address'" href="javascript:;">
+        <span>{{ ipV6Address(text, record) }}</span>
+      </template>
+      <template v-if="column.key === 'publicip'">
+        <router-link v-if="['/autoscalevmgroup'].includes($route.path)" :to="{ path: '/publicip' + '/' + record.publicipid }">{{ text }}</router-link>
+        <router-link v-else :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
+      </template>
+      <template v-if="column.key === 'traffictype'">
+        {{ text }}
+      </template>
+      <template v-if="column.key === 'vmname'">
+        <router-link :to="{ path: createPathBasedOnVmType(record.vmtype, record.virtualmachineid) }">{{ text }}</router-link>
+      </template>
+      <template v-if="column.key === 'virtualmachinename'">
+        <router-link :to="{ path: getVmRouteUsingType(record) + record.virtualmachineid }">{{ text }}</router-link>
+      </template>
+      <template v-if="column.key === 'hypervisor'">
+        <span v-if="$route.name === 'hypervisorcapability'">
+        <router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
       </span>
-    </template>
-    <template #templatetype="{ text, record }">
-      <router-link :to="{ path: $route.path + '/' + record.templatetype }">{{ text }}</router-link>
-    </template>
-    <template #type="{ text }">
-      <span v-if="['USER.LOGIN', 'USER.LOGOUT', 'ROUTER.HEALTH.CHECKS', 'FIREWALL.CLOSE', 'ALERT.SERVICE.DOMAINROUTER'].includes(text)">{{ $t(text.toLowerCase()) }}</span>
-      <span v-else>{{ text }}</span>
-    </template>
-    <template #displayname="{text, record}">
-      <QuickView
-        style="margin-left: 5px"
-        :actions="actions"
-        :resource="record"
-        :enabled="quickViewEnabled() && actions.length > 0 && columns && columns[0].dataIndex === 'displayname' "
-        @exec-action="$parent.execAction"/>
-      <router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
-    </template>
-    <template #username="{text, record}">
-      <span v-if="$showIcon() && !['vm'].includes($route.path.split('/')[1])" style="margin-right: 5px">
-        <resource-icon v-if="$showIcon() && record.icon && record.icon.base64image" :image="record.icon.base64image" size="1x"/>
-        <user-outlined v-else style="font-size: 16px;" />
-      </span>
-      <router-link :to="{ path: $route.path + '/' + record.id }" v-if="['/accountuser', '/vpnuser'].includes($route.path)">{{ text }}</router-link>
-      <router-link :to="{ path: '/accountuser', query: { username: record.username, domainid: record.domainid } }" v-else-if="$store.getters.userInfo.roletype !== 'User'">{{ text }}</router-link>
-      <span v-else>{{ text }}</span>
-    </template>
-    <template #entityid="{ record }" href="javascript:;">
-      <router-link :to="{ path: generateCommentsPath(record), query: { tab: 'comments' } }">{{ record.entityname }}</router-link>
-    </template>
-    <template #entitytype="{ record }" href="javascript:;">
-      {{ generateHumanReadableEntityType(record) }}
-    </template>
-    <template #adminsonly="{ record }" v-if="['Admin'].includes($store.getters.userInfo.roletype)" href="javascript:;">
-      <a-checkbox :checked="record.adminsonly" :value="record.id" v-if="record.userid === $store.getters.userInfo.id" @change="e => updateAdminsOnly(e)" />
-      <a-checkbox :checked="record.adminsonly" disabled v-else />
-    </template>
-    <template #ipaddress="{ text, record }" href="javascript:;">
-      <router-link v-if="['/publicip', '/privategw'].includes($route.path)" :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
-      <span v-else>{{ text }}</span>
-      <span v-if="record.issourcenat">
-        &nbsp;
-        <a-tag>source-nat</a-tag>
-      </span>
-      <span v-if="record.isstaticnat">
-        &nbsp;
-        <a-tag>static-nat</a-tag>
-      </span>
-    </template>
-    <template #ip6address="{ text, record }" href="javascript:;">
-      <span>{{ ipV6Address(text, record) }}</span>
-    </template>
-    <template #publicip="{ text, record }">
-      <router-link v-if="['/autoscalevmgroup'].includes($route.path)" :to="{ path: '/publicip' + '/' + record.publicipid }">{{ text }}</router-link>
-      <router-link v-else :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
-    </template>
-    <template #traffictype="{ text }" href="javascript:;">
-      {{ text }}
-    </template>
-    <template #vmname="{ text, record }">
-      <router-link :to="{ path: createPathBasedOnVmType(record.vmtype, record.virtualmachineid) }">{{ text }}</router-link>
-    </template>
-    <template #virtualmachinename="{ text, record }">
-      <router-link :to="{ path: '/vm/' + record.virtualmachineid }">{{ text }}</router-link>
-    </template>
-    <template #hypervisor="{ text, record }">
-      <span v-if="$route.name === 'hypervisorcapability'">
+      <span v-else-if="$route.name === 'guestoshypervisormapping'">
+        <QuickView
+          style="margin-left: 5px"
+          :actions="actions"
+          :resource="record"
+          :enabled="quickViewEnabled() && actions.length > 0 && columns && columns[0].dataIndex === 'hypervisor' "
+          @exec-action="$parent.execAction"/>
         <router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
       </span>
       <span v-else>{{ text }}</span>
     </template>
-    <template #state="{ text, record }">
+    <template v-if="column.key === 'osname'">
+      <span v-if="$route.name === 'guestos'">
+        <router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
+      </span>
+      <span v-else>{{ text }}</span>
+    </template>
+    <template v-if="column.key === 'state'">
       <status v-if="$route.path.startsWith('/host')" :text="getHostState(record)" displayText />
       <status v-else :text="text ? text : ''" displayText :styles="{ 'min-width': '80px' }" />
     </template>
-    <template #allocationstate="{ text }">
+    <template v-if="column.key === 'allocationstate'">
       <status :text="text ? text : ''" displayText />
     </template>
-    <template #resourcestate="{ text }">
+    <template v-if="column.key === 'resourcestate'">
       <status :text="text ? text : ''" displayText />
     </template>
-    <template #powerstate="{ text }">
+    <template v-if="column.key === 'powerstate'">
       <status :text="text ? text : ''" displayText />
     </template>
-    <template #agentstate="{ text }">
+    <template v-if="column.key === 'agentstate'">
       <status :text="text ? text : ''" displayText />
     </template>
-    <template #quotastate="{ text }">
+    <template v-if="column.key === 'quotastate'">
       <status :text="text ? text : ''" displayText />
     </template>
-    <template #vlan="{ text, record }">
+    <template v-if="column.key === 'vlan'">
       <a href="javascript:;">
         <router-link v-if="$route.path === '/guestvlans'" :to="{ path: '/guestvlans/' + record.id }">{{ text }}</router-link>
       </a>
     </template>
-    <template #guestnetworkname="{ text, record }">
+    <template v-if="column.key === 'guestnetworkname'">
       <router-link :to="{ path: '/guestnetwork/' + record.guestnetworkid }">{{ text }}</router-link>
     </template>
-    <template #associatednetworkname="{ text, record }">
+    <template v-if="column.key === 'associatednetworkname'">
       <router-link :to="{ path: '/guestnetwork/' + record.associatednetworkid }">{{ text }}</router-link>
     </template>
-    <template #vpcname="{ text, record }">
-      <router-link :to="{ path: '/vpc/' + record.vpcid }">{{ text }}</router-link>
+    <template v-if="column.key === 'vpcname'">
+      <a v-if="record.vpcid">
+        <router-link :to="{ path: '/vpc/' + record.vpcid }">{{ text }}</router-link>
+      </a>
+      <span v-else>{{ text }}</span>
     </template>
-    <template #hostname="{ text, record }">
+    <template v-if="column.key === 'hostname'">
       <router-link v-if="record.hostid" :to="{ path: '/host/' + record.hostid }">{{ text }}</router-link>
       <router-link v-else-if="record.hostname" :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
       <span v-else>{{ text }}</span>
     </template>
-    <template #storage="{ text, record }">
+    <template v-if="column.key === 'storage'">
       <router-link v-if="record.storageid" :to="{ path: '/storagepool/' + record.storageid }">{{ text }}</router-link>
       <span v-else>{{ text }}</span>
     </template>
-
-    <template
-      v-for="(value, name) in thresholdMapping"
-      :key="name"
-      #[name]="{ text, record }"
-      href="javascript:;">
-      <span>
-        <span v-if="record[value.disable]" class="alert-disable-threshold">
-          {{ text }}
-        </span>
-        <span v-else-if="record[value.notification]" class="alert-notification-threshold">
-          {{ text }}
-        </span>
-        <span style="padding: 10%;" v-else>
-          {{ text }}
-        </span>
-      </span>
-    </template>
-
-    <template #level="{ text, record }">
-      <router-link :to="{ path: '/event/' + record.id }">{{ text }}</router-link>
-    </template>
-
-    <template #clustername="{ text, record }">
-      <router-link :to="{ path: '/cluster/' + record.clusterid }">{{ text }}</router-link>
-    </template>
-    <template #podname="{ text, record }">
-      <router-link :to="{ path: '/pod/' + record.podid }">{{ text }}</router-link>
-    </template>
-    <template #account="{ text, record }">
-      <template v-if="record.owner">
-        <template v-for="(item, idx) in record.owner" :key="idx">
-          <span style="margin-right:5px">
-            <span v-if="$store.getters.userInfo.roletype !== 'User'">
-              <router-link v-if="'user' in item" :to="{ path: '/accountuser', query: { username: item.user, domainid: record.domainid }}">{{ item.account + '(' + item.user + ')' }}</router-link>
-              <router-link v-else :to="{ path: '/account', query: { name: item.account, domainid: record.domainid, dataView: true } }">{{ item.account }}</router-link>
-            </span>
-            <span v-else>{{ item.user ? item.account + '(' + item.user + ')' : item.account }}</span>
+    <template v-for="(value, name) in thresholdMapping" :key="name">
+      <template v-if="column.key === name">
+        <span>
+          <span v-if="record[value.disable]" class="alert-disable-threshold">
+            {{ text }}
           </span>
+          <span v-else-if="record[value.notification]" class="alert-notification-threshold">
+            {{ text }}
+          </span>
+          <span style="padding: 10%;" v-else>
+            {{ text }}
+          </span>
+        </span>
+      </template>
+    </template>
+
+      <template v-if="column.key === 'level'">
+        <router-link :to="{ path: '/event/' + record.id }">{{ text }}</router-link>
+      </template>
+
+      <template v-if="column.key === 'clustername'">
+        <router-link :to="{ path: '/cluster/' + record.clusterid }">{{ text }}</router-link>
+      </template>
+      <template v-if="column.key === 'podname'">
+        <router-link :to="{ path: '/pod/' + record.podid }">{{ text }}</router-link>
+      </template>
+      <template v-if="column.key === 'account'">
+        <template v-if="record.owner">
+          <template v-for="(item, idx) in record.owner" :key="idx">
+            <span style="margin-right:5px">
+              <span v-if="$store.getters.userInfo.roletype !== 'User'">
+                <router-link v-if="'user' in item" :to="{ path: '/accountuser', query: { username: item.user, domainid: record.domainid }}">{{ item.account + '(' + item.user + ')' }}</router-link>
+                <router-link v-else :to="{ path: '/account', query: { name: item.account, domainid: record.domainid, dataView: true } }">{{ item.account }}</router-link>
+              </span>
+              <span v-else>{{ item.user ? item.account + '(' + item.user + ')' : item.account }}</span>
+            </span>
+          </template>
+        </template>
+        <template v-if="text && !text.startsWith('PrjAcct-')">
+          <router-link
+            v-if="'quota' in record && $router.resolve(`${$route.path}/${record.account}`).matched[0].redirect !== '/exception/404'"
+            :to="{ path: `${$route.path}/${record.account}`, query: { account: record.account, domainid: record.domainid, quota: true } }">{{ text }}</router-link>
+          <router-link :to="{ path: '/account/' + record.accountid }" v-else-if="record.accountid">{{ text }}</router-link>
+          <router-link :to="{ path: '/account', query: { name: record.account, domainid: record.domainid, dataView: true } }" v-else-if="$store.getters.userInfo.roletype !== 'User'">{{ text }}</router-link>
+          <span v-else>{{ text }}</span>
         </template>
       </template>
-      <template v-if="text && !text.startsWith('PrjAcct-')">
-        <router-link
-          v-if="'quota' in record && $router.resolve(`${$route.path}/${record.account}`).matched[0].redirect !== '/exception/404'"
-          :to="{ path: `${$route.path}/${record.account}`, query: { account: record.account, domainid: record.domainid, quota: true } }">{{ text }}</router-link>
-        <router-link :to="{ path: '/account/' + record.accountid }" v-else-if="record.accountid">{{ text }}</router-link>
-        <router-link :to="{ path: '/account', query: { name: record.account, domainid: record.domainid, dataView: true } }" v-else-if="$store.getters.userInfo.roletype !== 'User'">{{ text }}</router-link>
+      <template v-if="column.key === 'resource'">
+        <resource-label :resourceType="record.resourcetype" :resourceId="record.resourceid" :resourceName="record.resourcename" />
+      </template>
+      <template v-if="column.key === 'domain'">
+        <router-link v-if="record.domainid && !record.domainid.toString().includes(',') && $store.getters.userInfo.roletype !== 'User'" :to="{ path: '/domain/' + record.domainid, query: { tab: 'details' } }">{{ text }}</router-link>
         <span v-else>{{ text }}</span>
       </template>
-    </template>
-    <template #resource="{ record }">
-      <resource-label :resourceType="record.resourcetype" :resourceId="record.resourceid" :resourceName="record.resourcename" />
-    </template>
-    <template #domain="{ text, record }">
-      <router-link v-if="record.domainid && !record.domainid.toString().includes(',') && $store.getters.userInfo.roletype !== 'User'" :to="{ path: '/domain/' + record.domainid, query: { tab: 'details' } }">{{ text }}</router-link>
-      <span v-else>{{ text }}</span>
-    </template>
-    <template #domainpath="{ text, record }">
-      <router-link v-if="record.domainid && !record.domainid.includes(',') && $router.resolve('/domain/' + record.domainid).matched[0].redirect !== '/exception/404'" :to="{ path: '/domain/' + record.domainid, query: { tab: 'details' } }">{{ text }}</router-link>
-      <span v-else>{{ text }}</span>
-    </template>
-    <template #zone="{ text, record }">
-      <router-link v-if="record.zoneid && !record.zoneid.includes(',') && $router.resolve('/zone/' + record.zoneid).matched[0].redirect !== '/exception/404'" :to="{ path: '/zone/' + record.zoneid }">{{ text }}</router-link>
-      <span v-else>{{ text }}</span>
-    </template>
-    <template #zonename="{ text, record }">
-      <router-link v-if="$router.resolve('/zone/' + record.zoneid).matched[0].redirect !== '/exception/404'" :to="{ path: '/zone/' + record.zoneid }">{{ text }}</router-link>
-      <span v-else>{{ text }}</span>
-    </template>
-    <template #rolename="{ text, record }">
-      <router-link v-if="record.roleid && $router.resolve('/role/' + record.roleid).matched[0].redirect !== '/exception/404'" :to="{ path: '/role/' + record.roleid }">{{ text }}</router-link>
-      <span v-else>{{ text }}</span>
-    </template>
-    <template #templateversion="{ record }">
-      <span>  {{ record.version }} </span>
-    </template>
-    <template #softwareversion="{ record }">
-      <span>  {{ record.softwareversion ? record.softwareversion : 'N/A' }} </span>
-    </template>
-    <template #access="{ record }">
-      <status :text="record.readonly ? 'ReadOnly' : 'ReadWrite'" displayText />
-    </template>
-    <template #requiresupgrade="{ record }">
-      <status :text="record.requiresupgrade ? 'warning' : ''" />
-      {{ record.requiresupgrade ? 'Yes' : 'No' }}
-    </template>
-    <template #loadbalancerrule="{ record }">
-      <span>  {{ record.loadbalancerrule }} </span>
-    </template>
-    <template #autoscalingenabled="{ record }">
-      <status :text="record.autoscalingenabled ? 'Enabled' : 'Disabled'" />
-      {{ record.autoscalingenabled ? 'Enabled' : 'Disabled' }}
-    </template>
-    <template #current="{record}">
-      <status :text="record.current ? record.current.toString() : 'false'" />
-    </template>
-    <template #created="{ text }">
-      {{ $toLocaleDate(text) }}
-    </template>
-    <template #sent="{ text }">
-      {{ $toLocaleDate(text) }}
-    </template>
-    <template #order="{ text, record }">
-      <div class="shift-btns">
-        <a-tooltip :name="text" placement="top">
-          <template #title>{{ $t('label.move.to.top') }}</template>
-          <a-button
-            shape="round"
-            @click="moveItemTop(record)"
-            class="shift-btn">
-            <DoubleLeftOutlined class="shift-btn shift-btn--rotated" />
-          </a-button>
-        </a-tooltip>
-        <a-tooltip placement="top">
-          <template #title>{{ $t('label.move.to.bottom') }}</template>
-          <a-button
-            shape="round"
-            @click="moveItemBottom(record)"
-            class="shift-btn">
-            <DoubleRightOutlined class="shift-btn shift-btn--rotated" />
-          </a-button>
-        </a-tooltip>
-        <a-tooltip placement="top">
-          <template #title>{{ $t('label.move.up.row') }}</template>
-          <a-button shape="round" @click="moveItemUp(record)" class="shift-btn">
-            <CaretUpOutlined class="shift-btn" />
-          </a-button>
-        </a-tooltip>
-        <a-tooltip placement="top">
-          <template #title>{{ $t('label.move.down.row') }}</template>
-          <a-button shape="round" @click="moveItemDown(record)" class="shift-btn">
-            <CaretDownOutlined class="shift-btn" />
-          </a-button>
-        </a-tooltip>
-      </div>
-    </template>
+      <template v-if="column.key === 'domainpath'">
+        <router-link v-if="record.domainid && !record.domainid.includes(',') && $router.resolve('/domain/' + record.domainid).matched[0].redirect !== '/exception/404'" :to="{ path: '/domain/' + record.domainid, query: { tab: 'details' } }">{{ text }}</router-link>
+        <span v-else>{{ text }}</span>
+      </template>
+      <template v-if="column.key === 'zone'">
+        <router-link v-if="record.zoneid && !record.zoneid.includes(',') && $router.resolve('/zone/' + record.zoneid).matched[0].redirect !== '/exception/404'" :to="{ path: '/zone/' + record.zoneid }">{{ text }}</router-link>
+        <span v-else>{{ text }}</span>
+      </template>
+      <template v-if="column.key === 'zonename'">
+        <router-link v-if="$router.resolve('/zone/' + record.zoneid).matched[0].redirect !== '/exception/404'" :to="{ path: '/zone/' + record.zoneid }">{{ text }}</router-link>
+        <span v-else>{{ text }}</span>
+      </template>
+      <template v-if="column.key === 'rolename'">
+        <router-link v-if="record.roleid && $router.resolve('/role/' + record.roleid).matched[0].redirect !== '/exception/404'" :to="{ path: '/role/' + record.roleid }">{{ text }}</router-link>
+        <span v-else>{{ text }}</span>
+      </template>
+      <template v-if="column.key === 'templateversion'">
+        <span>  {{ record.version }} </span>
+      </template>
+      <template v-if="column.key === 'softwareversion'">
+        <span>  {{ record.softwareversion ? record.softwareversion : 'N/A' }} </span>
+      </template>
+      <template v-if="column.key === 'access'">
+        <status :text="record.readonly ? 'ReadOnly' : 'ReadWrite'" displayText />
+      </template>
+      <template v-if="column.key === 'requiresupgrade'">
+        <status :text="record.requiresupgrade ? 'warning' : ''" />
+        {{ record.requiresupgrade ? 'Yes' : 'No' }}
+      </template>
+      <template v-if="column.key === 'loadbalancerrule'">
+        <span>  {{ record.loadbalancerrule }} </span>
+      </template>
+      <template v-if="column.key === 'autoscalingenabled'">
+        <status :text="record.autoscalingenabled ? 'Enabled' : 'Disabled'" />
+        {{ record.autoscalingenabled ? 'Enabled' : 'Disabled' }}
+      </template>
+      <template v-if="column.key === 'current'">
+        <status :text="record.current ? record.current.toString() : 'false'" />
+      </template>
+      <template v-if="column.key === 'enabled'">
+        <status :text="record.enabled ? record.enabled.toString() : 'false'" />
+        {{ record.enabled ? 'Enabled' : 'Disabled' }}
+      </template>
+      <template v-if="['created', 'sent'].includes(column.key)">
+        {{ $toLocaleDate(text) }}
+      </template>
+      <template v-if="['startdate', 'enddate'].includes(column.key) && ['vm'].includes($route.path.split('/')[1])">
+        {{ getDateAtTimeZone(text, record.timezone) }}
+      </template>
+      <template v-if="column.key === 'order'">
+        <div class="shift-btns">
+          <a-tooltip :name="text" placement="top">
+            <template #title>{{ $t('label.move.to.top') }}</template>
+            <a-button
+              shape="round"
+              @click="moveItemTop(record)"
+              class="shift-btn">
+              <DoubleLeftOutlined class="shift-btn shift-btn--rotated" />
+            </a-button>
+          </a-tooltip>
+          <a-tooltip placement="top">
+            <template #title>{{ $t('label.move.to.bottom') }}</template>
+            <a-button
+              shape="round"
+              @click="moveItemBottom(record)"
+              class="shift-btn">
+              <DoubleRightOutlined class="shift-btn shift-btn--rotated" />
+            </a-button>
+          </a-tooltip>
+          <a-tooltip placement="top">
+            <template #title>{{ $t('label.move.up.row') }}</template>
+            <a-button shape="round" @click="moveItemUp(record)" class="shift-btn">
+              <CaretUpOutlined class="shift-btn" />
+            </a-button>
+          </a-tooltip>
+          <a-tooltip placement="top">
+            <template #title>{{ $t('label.move.down.row') }}</template>
+            <a-button shape="round" @click="moveItemDown(record)" class="shift-btn">
+              <CaretDownOutlined class="shift-btn" />
+            </a-button>
+          </a-tooltip>
+        </div>
+      </template>
 
-    <template #value="{ text, record }">
-      <a-input
-        v-if="editableValueKey === record.key"
-        v-focus="true"
-        :defaultValue="record.value"
-        :disabled="!('updateConfiguration' in $store.getters.apis)"
-        v-model:value="editableValue"
-        @keydown.esc="editableValueKey = null"
-        @pressEnter="saveValue(record)">
-      </a-input>
-      <div v-else style="width: 200px; word-break: break-all">
-        {{ text }}
-      </div>
+      <template v-if="column.key === 'value'">
+        <a-input
+          v-if="editableValueKey === record.key"
+          v-focus="true"
+          :defaultValue="record.value"
+          :disabled="!('updateConfiguration' in $store.getters.apis)"
+          v-model:value="editableValue"
+          @keydown.esc="editableValueKey = null"
+          @pressEnter="saveValue(record)">
+        </a-input>
+        <div v-else style="width: 200px; word-break: break-all">
+          {{ text }}
+        </div>
+      </template>
+      <template v-if="column.key === 'actions'">
+        <tooltip-button
+          :tooltip="$t('label.edit')"
+          :disabled="!('updateConfiguration' in $store.getters.apis)"
+          v-if="editableValueKey !== record.key"
+          icon="edit-outlined"
+          @onClick="editValue(record)" />
+        <tooltip-button
+          :tooltip="$t('label.cancel')"
+          @onClick="editableValueKey = null"
+          v-if="editableValueKey === record.key"
+          iconType="CloseCircleTwoTone"
+          iconTwoToneColor="#f5222d" />
+        <tooltip-button
+          :tooltip="$t('label.ok')"
+          :disabled="!('updateConfiguration' in $store.getters.apis)"
+          @onClick="saveValue(record)"
+          v-if="editableValueKey === record.key"
+          iconType="CheckCircleTwoTone"
+          iconTwoToneColor="#52c41a" />
+        <tooltip-button
+          :tooltip="$t('label.reset.config.value')"
+          @onClick="resetConfig(record)"
+          v-if="editableValueKey !== record.key"
+          icon="reload-outlined"
+          :disabled="!('updateConfiguration' in $store.getters.apis)" />
+      </template>
+      <template v-if="column.key === 'tariffActions'">
+        <tooltip-button
+          :tooltip="$t('label.edit')"
+          v-if="editableValueKey !== record.key"
+          :disabled="!('quotaTariffUpdate' in $store.getters.apis)"
+          icon="edit-outlined"
+          @onClick="editTariffValue(record)" />
+        <slot></slot>
+      </template>
+      <template v-if="column.key === 'vmScheduleActions'">
+        <tooltip-button
+          :tooltip="$t('label.edit')"
+          :disabled="!('updateVMSchedule' in $store.getters.apis)"
+          icon="edit-outlined"
+          @onClick="updateVMSchedule(record)" />
+        <tooltip-button
+          :tooltip="$t('label.remove')"
+          :disabled="!('deleteVMSchedule' in $store.getters.apis)"
+          icon="delete-outlined"
+          :danger="true"
+          type="primary"
+          @onClick="removeVMSchedule(record)" />
+      </template>
     </template>
-    <template #actions="{ record }">
-      <tooltip-button
-        :tooltip="$t('label.edit')"
-        :disabled="!('updateConfiguration' in $store.getters.apis)"
-        v-if="editableValueKey !== record.key"
-        icon="edit-outlined"
-        @onClick="editValue(record)" />
-      <tooltip-button
-        :tooltip="$t('label.cancel')"
-        @onClick="editableValueKey = null"
-        v-if="editableValueKey === record.key"
-        iconType="CloseCircleTwoTone"
-        iconTwoToneColor="#f5222d" />
-      <tooltip-button
-        :tooltip="$t('label.ok')"
-        :disabled="!('updateConfiguration' in $store.getters.apis)"
-        @onClick="saveValue(record)"
-        v-if="editableValueKey === record.key"
-        iconType="CheckCircleTwoTone"
-        iconTwoToneColor="#52c41a" />
-      <tooltip-button
-        :tooltip="$t('label.reset.config.value')"
-        @onClick="resetConfig(record)"
-        v-if="editableValueKey !== record.key"
-        icon="reload-outlined"
-        :disabled="!('updateConfiguration' in $store.getters.apis)" />
-    </template>
-    <template #tariffActions="{ record }">
-      <tooltip-button
-        :tooltip="$t('label.edit')"
-        v-if="editableValueKey !== record.key"
-        :disabled="!('quotaTariffUpdate' in $store.getters.apis)"
-        icon="edit-outlined"
-        @onClick="editTariffValue(record)" />
-      <slot></slot>
+    <template #footer>
+      <span v-if="hasSelected">
+        {{ `Selected ${selectedRowKeys.length} items` }}
+      </span>
     </template>
   </a-table>
 </template>
@@ -435,6 +450,8 @@
 import ResourceIcon from '@/components/view/ResourceIcon'
 import ResourceLabel from '@/components/widgets/ResourceLabel'
 import { createPathBasedOnVmType } from '@/utils/plugins'
+import cronstrue from 'cronstrue/i18n'
+import moment from 'moment-timezone'
 
 export default {
   name: 'ListView',
@@ -542,7 +559,7 @@
         '/project', '/account',
         '/zone', '/pod', '/cluster', '/host', '/storagepool', '/imagestore', '/systemvm', '/router', '/ilbvm', '/annotation',
         '/computeoffering', '/systemoffering', '/diskoffering', '/backupoffering', '/networkoffering', '/vpcoffering',
-        '/tungstenfabric'].join('|'))
+        '/tungstenfabric', '/guestos', '/guestoshypervisormapping'].join('|'))
         .test(this.$route.path)
     },
     enableGroupAction () {
@@ -552,6 +569,9 @@
         'diskoffering', 'backupoffering', 'networkoffering', 'vpcoffering', 'ilbvm', 'kubernetes', 'comment'
       ].includes(this.$route.name)
     },
+    getDateAtTimeZone (date, timezone) {
+      return date ? moment(date).tz(timezone).format('YYYY-MM-DD HH:mm:ss') : null
+    },
     fetchColumns () {
       if (this.isOrderUpdatable()) {
         return this.columns
@@ -716,6 +736,12 @@
     editTariffValue (record) {
       this.$emit('edit-tariff-action', true, record)
     },
+    updateVMSchedule (record) {
+      this.$emit('update-vm-schedule', record)
+    },
+    removeVMSchedule (record) {
+      this.$emit('remove-vm-schedule', record)
+    },
     ipV6Address (text, record) {
       if (!record || !record.nic || record.nic.length === 0) {
         return ''
@@ -760,6 +786,9 @@
         default: return record.entitytype.toLowerCase().replace('_', '')
       }
     },
+    generateHumanReadableSchedule (schedule) {
+      return cronstrue.toString(schedule, { locale: this.$i18n.locale })
+    },
     entityTypeToPath (entitytype) {
       switch (entitytype) {
         case 'VM' : return 'vm'
@@ -822,6 +851,14 @@
     },
     updateSelectedColumns (name) {
       this.$emit('update-selected-columns', name)
+    },
+    getVmRouteUsingType (record) {
+      switch (record.virtualmachinetype) {
+        case 'DomainRouter' : return '/router/'
+        case 'ConsoleProxy' :
+        case 'SecondaryStorageVm': return '/systemvm/'
+        default: return '/vm/'
+      }
     }
   }
 }
diff --git a/ui/src/components/view/NicNetworkSelectForm.vue b/ui/src/components/view/NicNetworkSelectForm.vue
index f19b151..d54f775 100644
--- a/ui/src/components/view/NicNetworkSelectForm.vue
+++ b/ui/src/components/view/NicNetworkSelectForm.vue
@@ -33,11 +33,13 @@
         :dataSource="networks"
         :pagination="false"
         :rowKey="record => record.id">
-        <template #select="{record}">
-          <a-radio
-            @click="updateSelection(record)"
-            :checked="selectedNetwork != null && record.id === selectedNetwork.id">
-          </a-radio>
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.key === 'select'">
+            <a-radio
+              @click="updateSelection(record)"
+              :checked="selectedNetwork != null && record.id === selectedNetwork.id">
+            </a-radio>
+          </template>
         </template>
       </a-table>
       <a-pagination
@@ -97,24 +99,28 @@
       selectedNetwork: null,
       columns: [
         {
+          key: 'name',
           title: this.$t('label.networkid'),
           dataIndex: 'name'
         },
         {
+          key: 'type',
           title: this.$t('label.guestiptype'),
           dataIndex: 'type'
         },
         {
+          key: 'vpcName',
           title: this.$t('label.vpc'),
           dataIndex: 'vpcName'
         },
         {
+          key: 'cidr',
           title: this.$t('label.cidr'),
           dataIndex: 'cidr'
         },
         {
-          title: this.$t('label.select'),
-          slots: { customRender: 'select' }
+          key: 'select',
+          title: this.$t('label.select')
         }
       ]
     }
diff --git a/ui/src/components/view/SearchView.vue b/ui/src/components/view/SearchView.vue
index 190db44..bce8a6b 100644
--- a/ui/src/components/view/SearchView.vue
+++ b/ui/src/components/view/SearchView.vue
@@ -71,7 +71,7 @@
                       v-for="(opt, idx) in field.opts"
                       :key="idx"
                       :value="opt.id"
-                      :label="$t(opt.name)">
+                      :label="$t(opt.path || opt.name)">
                       <div>
                         <span v-if="(field.name.startsWith('zone'))">
                           <span v-if="opt.icon">
@@ -632,6 +632,7 @@
     },
     onClear () {
       this.formRef.value.resetFields()
+      this.form = reactive({})
       this.isFiltered = false
       this.inputKey = null
       this.inputValue = null
@@ -644,7 +645,6 @@
       this.formRef.value.validate().then(() => {
         const values = toRaw(this.form)
         this.isFiltered = true
-        console.log(values)
         for (const key in values) {
           const input = values[key]
           if (input === '' || input === null || input === undefined) {
diff --git a/ui/src/components/view/StoragePoolSelectView.vue b/ui/src/components/view/StoragePoolSelectView.vue
index 1422cea..8f006ed 100644
--- a/ui/src/components/view/StoragePoolSelectView.vue
+++ b/ui/src/components/view/StoragePoolSelectView.vue
@@ -32,45 +32,49 @@
       :dataSource="storagePools"
       :pagination="false"
       :rowKey="record => record.id">
-      <template #suitabilityCustomTitle>
-        {{ $t('label.suitability') }}
-        <a-tooltip :title="$t('message.volume.state.primary.storage.suitability')" placement="top">
-          <info-circle-outlined class="table-tooltip-icon" />
-        </a-tooltip>
+      <template #headerCell="{ column }">
+        <template v-if="column.key === 'suitability'">
+          {{ $t('label.suitability') }}
+          <a-tooltip :title="$t('message.volume.state.primary.storage.suitability')" placement="top">
+            <info-circle-outlined class="table-tooltip-icon" />
+          </a-tooltip>
+        </template>
       </template>
-      <template #name="{ record }">
-        {{ record.name }}
-        <a-tooltip v-if="record.name === $t('label.auto.assign')" :title="$t('message.migrate.volume.pool.auto.assign')" placement="top">
-          <info-circle-outlined class="table-tooltip-icon" />
-        </a-tooltip>
-      </template>
-      <template #suitability="{ record }">
-        <check-circle-two-tone
-          class="host-item__suitability-icon"
-          twoToneColor="#52c41a"
-          v-if="record.suitableformigration" />
-        <close-circle-two-tone
-          class="host-item__suitability-icon"
-          twoToneColor="#f5222d"
-          v-else />
-      </template>
-      <template #disksizetotal="{ record }">
-        <span v-if="record.disksizetotal">{{ $bytesToHumanReadableSize(record.disksizetotal) }}</span>
-      </template>
-      <template #disksizeused="{ record }">
-        <span v-if="record.disksizeused">{{ $bytesToHumanReadableSize(record.disksizeused) }}</span>
-      </template>
-      <template #disksizefree="{ record }">
-        <span v-if="record.disksizetotal && record.disksizeused">{{ $bytesToHumanReadableSize(record.disksizetotal * 1 - record.disksizeused * 1) }}</span>
-      </template>
-      <template #select="{ record }">
-        <a-tooltip placement="top" :title="record.state !== 'Up' ? $t('message.primary.storage.invalid.state') : ''">
-          <a-radio
-            :disabled="record.id !== -1 && record.state !== 'Up'"
-            @click="updateSelection(record)"
-            :checked="selectedStoragePool != null && record.id === selectedStoragePool.id">
-          </a-radio>
-        </a-tooltip>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'name'">
+          {{ record.name }}
+          <a-tooltip v-if="record.name === $t('label.auto.assign')" :title="$t('message.migrate.volume.pool.auto.assign')" placement="top">
+            <info-circle-outlined class="table-tooltip-icon" />
+          </a-tooltip>
+        </template>
+        <template v-if="column.key === 'suitability'">
+          <check-circle-two-tone
+            class="host-item__suitability-icon"
+            twoToneColor="#52c41a"
+            v-if="record.suitableformigration" />
+          <close-circle-two-tone
+            class="host-item__suitability-icon"
+            twoToneColor="#f5222d"
+            v-else />
+        </template>
+        <template v-if="column.key === 'disksizetotal'">
+          <span v-if="record.disksizetotal">{{ $bytesToHumanReadableSize(record.disksizetotal) }}</span>
+        </template>
+        <template v-if="column.key === 'disksizeused'">
+          <span v-if="record.disksizeused">{{ $bytesToHumanReadableSize(record.disksizeused) }}</span>
+        </template>
+        <template v-if="column.key === 'disksizefree'">
+          <span v-if="record.disksizetotal && record.disksizeused">{{ $bytesToHumanReadableSize(record.disksizetotal * 1 - record.disksizeused * 1) }}</span>
+        </template>
+        <template v-if="column.key === 'select'">
+          <a-tooltip placement="top" :title="record.state !== 'Up' ? $t('message.primary.storage.invalid.state') : ''">
+            <a-radio
+              :disabled="record.id !== -1 && record.state !== 'Up'"
+              @click="updateSelection(record)"
+              :checked="selectedStoragePool != null && record.id === selectedStoragePool.id">
+            </a-radio>
+          </a-tooltip>
+        </template>
       </template>
     </a-table>
     <a-pagination
@@ -132,8 +136,8 @@
       selectedStoragePool: null,
       columns: [
         {
-          title: this.$t('label.storageid'),
-          slots: { customRender: 'name' }
+          key: 'name',
+          title: this.$t('label.storageid')
         },
         {
           title: this.$t('label.clusterid'),
@@ -144,27 +148,27 @@
           dataIndex: 'podname'
         },
         {
-          title: this.$t('label.disksizetotal'),
-          slots: { customRender: 'disksizetotal' }
+          key: 'disksizetotal',
+          title: this.$t('label.disksizetotal')
         },
         {
-          title: this.$t('label.disksizeused'),
-          slots: { customRender: 'disksizeused' }
+          key: 'disksizeused',
+          title: this.$t('label.disksizeused')
         },
         {
-          title: this.$t('label.disksizefree'),
-          slots: { customRender: 'disksizefree' }
+          key: 'disksizefree',
+          title: this.$t('label.disksizefree')
         },
         {
-          title: this.$t('label.select'),
-          slots: { customRender: 'select' }
+          key: 'select',
+          title: this.$t('label.select')
         }
       ]
     }
   },
   created () {
     if (this.suitabilityEnabled) {
-      this.columns.splice(1, 0, { title: 'suitabilityCustomTitle', slots: 'suitability' })
+      this.columns.splice(1, 0, { key: 'suitability' })
     }
     this.preselectStoragePool()
     this.fetchStoragePools()
diff --git a/ui/src/components/view/TreeView.vue b/ui/src/components/view/TreeView.vue
index 47f199b..40cd6f0 100644
--- a/ui/src/components/view/TreeView.vue
+++ b/ui/src/components/view/TreeView.vue
@@ -42,8 +42,9 @@
               @select="onSelect"
               @expand="onExpand"
               :expandedKeys="arrExpand">
-              <template #parent><folder-outlined /></template>
-              <template #leaf><block-outlined /></template>
+              <template #icon="{data}">
+                <block-outlined v-if="data.isLeaf" />
+              </template>
             </a-tree>
           </a-spin>
         </a-card>
@@ -136,6 +137,10 @@
       default () {
         return {}
       }
+    },
+    treeDeletedKey: {
+      type: String,
+      default: null
     }
   },
   provide: function () {
@@ -183,11 +188,11 @@
       this.treeViewData = []
       this.arrExpand = []
       if (!this.loading) {
-        this.treeViewData = this.treeData
-        this.treeVerticalData = this.treeData
+        this.treeViewData = this.treeData.slice()
+        this.treeVerticalData = this.treeData.slice()
 
         if (this.treeViewData.length > 0) {
-          this.oldTreeViewData = this.treeViewData
+          this.oldTreeViewData = this.treeViewData.slice()
           this.rootKey = this.treeViewData[0].key
         }
       }
@@ -288,39 +293,47 @@
             }
           }
 
-          this.onSelectResource()
+          this.handleSelectResource(treeNode.eventKey)
           resolve()
         })
       })
     },
-    onSelectResource () {
-      if (this.treeStore.selected) {
-        this.selectedTreeKey = this.treeStore.selected
-        this.defaultSelected = [this.selectedTreeKey]
+    async handleSelectResource (treeKey) {
+      if (this.treeDeletedKey && this.treeDeletedKey === this.treeStore?.treeSelected?.key) {
+        const treeSelectedKey = this.treeStore.treeSelected.parentdomainid
+        if (treeSelectedKey === this.rootKey) {
+          this.resource = this.treeVerticalData[0]
 
-        const resource = this.treeVerticalData.filter(item => item.id === this.selectedTreeKey)
-        if (resource.length > 0) {
-          this.resource = resource[0]
+          this.selectedTreeKey = treeSelectedKey
+          this.defaultSelected = [treeSelectedKey]
           this.$emit('change-resource', this.resource)
-        } else {
-          const resourceIdx = this.treeVerticalData.findIndex(item => item.id === this.resource.id)
-          const parentIndex = this.treeVerticalData.findIndex(item => item.id === this.resource.parentdomainid)
-          if (resourceIdx !== -1) {
-            this.resource = this.treeVerticalData[resourceIdx]
-          } else if (parentIndex !== 1) {
-            this.resource = this.treeVerticalData[parentIndex]
-          } else {
-            this.resource = this.treeVerticalData[0]
-          }
-          this.selectedTreeKey = this.resource.key
-          this.defaultSelected = [this.selectedTreeKey]
+          await this.setTreeStore(false, false, this.resource)
+          return
+        }
+        const resourceIndex = await this.treeVerticalData.findIndex(item => item.id === treeSelectedKey)
+        if (resourceIndex > -1) {
+          const resource = await this.getDetailResource(treeSelectedKey)
+          this.resource = await this.createResourceData(resource)
+
+          this.selectedTreeKey = treeSelectedKey
+          this.defaultSelected = [treeSelectedKey]
           this.$emit('change-resource', this.resource)
+          await this.setTreeStore(false, false, this.resource)
+          return
         }
       }
+      const treeSelectedKey = this.treeStore.treeSelected.key
+      const resourceIndex = await this.treeVerticalData.findIndex(item => item.id === treeSelectedKey)
+      if (resourceIndex > -1) {
+        this.selectedTreeKey = treeSelectedKey
+        this.defaultSelected = [treeSelectedKey]
+
+        this.resource = this.treeStore.treeSelected
+        this.$emit('change-resource', this.resource)
+      }
     },
-    onSelect (selectedKeys, event) {
+    async onSelect (selectedKeys, event) {
       if (!event.selected) {
-        setTimeout(() => { event.node.$refs.selectHandle.click() })
         return
       }
 
@@ -331,20 +344,20 @@
 
       this.defaultSelected = []
       this.defaultSelected.push(this.selectedTreeKey)
+      const resource = await this.getDetailResource(this.selectedTreeKey)
+      this.resource = await this.createResourceData(resource)
+      const index = this.treeVerticalData.findIndex(item => item.key === this.selectedTreeKey)
+      this.treeVerticalData[index] = this.resource
 
-      const treeStore = this.treeStore
-      treeStore.expands = this.arrExpand
-      treeStore.selected = this.selectedTreeKey
-      this.$emit('change-tree-store', this.treeStore)
-
-      this.getDetailResource(this.selectedTreeKey)
+      this.$emit('change-resource', this.resource)
+      await this.setTreeStore(false, false, this.resource)
     },
     onExpand (treeExpand) {
       const treeStore = this.treeStore
       this.arrExpand = treeExpand
       treeStore.isExpand = true
       treeStore.expands = this.arrExpand
-      treeStore.selected = this.selectedTreeKey
+      treeStore.treeSelected = this.resource
       this.$emit('change-tree-store', treeStore)
     },
     onSearch (value) {
@@ -416,40 +429,35 @@
     onTabChange (key) {
       this.tabActive = key
     },
+    setTreeStore (arrExpand, isExpand, resource) {
+      const treeStore = this.treeStore
+      if (arrExpand) treeStore.expands = arrExpand
+      if (isExpand) treeStore.isExpand = true
+      if (resource) treeStore.treeSelected = resource
+      this.$emit('change-tree-store', treeStore)
+    },
     getDetailResource (selectedKey) {
-      // set api name and parameter
-      const apiName = this.$route.meta.permission[0]
-      const params = {}
+      return new Promise(resolve => {
+        // set api name and parameter
+        const apiName = this.$route.meta.permission[0]
+        const params = {}
 
-      // set id to parameter
-      params.id = selectedKey
-      params.listAll = true
-      params.showicon = true
-      params.page = 1
-      params.pageSize = 1
+        // set id to parameter
+        params.id = selectedKey
+        params.listAll = true
+        params.showicon = true
+        params.page = 1
+        params.pageSize = 1
 
-      this.detailLoading = true
-      api(apiName, params).then(json => {
-        const jsonResponse = this.getResponseJsonData(json)
-
-        // check json response is empty
-        if (!jsonResponse || jsonResponse.length === 0) {
-          this.resource = []
-        } else {
-          this.resource = jsonResponse[0]
-          this.resource = this.createResourceData(this.resource)
-          // set all value of resource tree data
-          this.treeVerticalData.filter((item, index) => {
-            if (item.id === this.resource.id) {
-              this.treeVerticalData[index] = this.resource
-            }
-          })
-        }
-
-        // emit change resource to parent
-        this.$emit('change-resource', this.resource)
-      }).finally(() => {
-        this.detailLoading = false
+        this.detailLoading = true
+        api(apiName, params).then(json => {
+          const jsonResponse = this.getResponseJsonData(json)
+          resolve(jsonResponse[0])
+        }).catch(() => {
+          resolve()
+        }).finally(() => {
+          this.detailLoading = false
+        })
       })
     },
     getResponseJsonData (json) {
@@ -524,15 +532,13 @@
       })
       resource.title = resource.name
       resource.key = resource.id
-      resource.slots = {
-        icon: 'parent'
+      if (resource?.icon) {
+        resource.resourceIcon = resource.icon
+        delete resource.icon
       }
 
       if (!resource.haschild) {
         resource.isLeaf = true
-        resource.slots = {
-          icon: 'leaf'
-        }
       }
 
       return resource
@@ -586,8 +592,9 @@
 </script>
 
 <style lang="less" scoped>
-.list-tree-view {
+:deep(.ant-tree).list-tree-view {
   overflow-y: hidden;
+  margin-top: 10px;
 }
 :deep(.ant-tree).ant-tree-directory {
   li.ant-tree-treenode-selected {
@@ -615,7 +622,7 @@
   }
 }
 
-:deep(.ant-tree) li span.ant-tree-switcher.ant-tree-switcher-noop {
+:deep(.ant-tree-show-line) .ant-tree-switcher.ant-tree-switcher-noop {
   display: none
 }
 
@@ -626,10 +633,38 @@
 
 :deep(.ant-tree-icon__customize) {
   padding-right: 5px;
+  background: transparent;
 }
 
-:deep(.ant-tree) li .ant-tree-node-content-wrapper {
-  padding-left: 0;
-  margin-left: 3px;
+:deep(.ant-tree) {
+  .ant-tree-treenode {
+    .ant-tree-node-content-wrapper {
+      margin-left: 0;
+      margin-bottom: 2px;
+
+      &:before {
+        border-left: 1px solid #d9d9d9;
+        content: " ";
+        height: 100%;
+        height: calc(100% - 15px);
+        left: 12px;
+        margin: 22px 0 0;
+        position: absolute;
+        width: 1px;
+        top: 0;
+      }
+    }
+
+    &.ant-tree-treenode-switcher-close, &.ant-tree-treenode-switcher-open, &.ant-tree-treenode-leaf-last {
+      .ant-tree-node-content-wrapper:before {
+        display: none;
+      }
+    }
+  }
+}
+
+:deep(.ant-tree-show-line) .ant-tree-indent-unit:before {
+  bottom: -2px;
+  top: -5px;
 }
 </style>
diff --git a/ui/src/components/view/VolumesTab.vue b/ui/src/components/view/VolumesTab.vue
index 939f708..e9165b1 100644
--- a/ui/src/components/view/VolumesTab.vue
+++ b/ui/src/components/view/VolumesTab.vue
@@ -24,20 +24,22 @@
     :rowKey="item => item.id"
     :pagination="false"
   >
-    <template #name="{ text, record }">
-      <hdd-outlined style="margin-right: 5px"/>
-      <router-link :to="{ path: '/volume/' + record.id }" style="margin-right: 5px">
-        {{ text }}
-      </router-link>
-      <a-tag v-if="record.provisioningtype">
-        {{  record.provisioningtype  }}
-      </a-tag>
-    </template>
-    <template #state="{ text }">
-      <status :text="text ? text : ''" />{{ text }}
-    </template>
-    <template #size="{ record }">
-      {{ parseFloat(record.size / (1024.0 * 1024.0 * 1024.0)).toFixed(2) }} GB
+    <template #bodyCell="{ column, text, record }">
+      <template v-if="column.key === 'name'">
+        <hdd-outlined style="margin-right: 5px"/>
+        <router-link :to="{ path: '/volume/' + record.id }" style="margin-right: 5px">
+          {{ text }}
+        </router-link>
+        <a-tag v-if="record.provisioningtype">
+          {{  record.provisioningtype  }}
+        </a-tag>
+      </template>
+      <template v-if="column.key === 'state'">
+        <status :text="text ? text : ''" />{{ text }}
+      </template>
+      <template v-if="column.key === 'size'">
+        {{ parseFloat(record.size / (1024.0 * 1024.0 * 1024.0)).toFixed(2) }} GB
+      </template>
     </template>
   </a-table>
 </template>
@@ -68,23 +70,23 @@
       volumes: [],
       volumeColumns: [
         {
+          key: 'name',
           title: this.$t('label.name'),
-          dataIndex: 'name',
-          slots: { customRender: 'name' }
+          dataIndex: 'name'
         },
         {
+          key: 'state',
           title: this.$t('label.state'),
-          dataIndex: 'state',
-          slots: { customRender: 'state' }
+          dataIndex: 'state'
         },
         {
           title: this.$t('label.type'),
           dataIndex: 'type'
         },
         {
+          key: 'size',
           title: this.$t('label.size'),
-          dataIndex: 'size',
-          slots: { customRender: 'size' }
+          dataIndex: 'size'
         }
       ]
     }
@@ -92,7 +94,6 @@
   created () {
     this.vm = this.resource
     this.fetchData()
-    console.log(this.resource.volumes)
   },
   watch: {
     resource: function (newItem) {
diff --git a/ui/src/components/widgets/Breadcrumb.vue b/ui/src/components/widgets/Breadcrumb.vue
index 097a922..147e779 100644
--- a/ui/src/components/widgets/Breadcrumb.vue
+++ b/ui/src/components/widgets/Breadcrumb.vue
@@ -40,7 +40,7 @@
           </span>
         </label>
         <label v-else>
-          {{ resource.displayname || resource.name || resource.displaytext || resource.hostname || resource.username || resource.ipaddress || $route.params.id }}
+          {{ resource.displayname || resource.name || resource.displaytext || resource.hostname || resource.username || resource.ipaddress || resource.osname || resource.osdisplayname || $route.params.id }}
         </label>
       </span>
       <span v-else>
diff --git a/ui/src/components/widgets/Console.vue b/ui/src/components/widgets/Console.vue
index 03a37a2..d73753c 100644
--- a/ui/src/components/widgets/Console.vue
+++ b/ui/src/components/widgets/Console.vue
@@ -20,7 +20,8 @@
     v-if="['vm', 'systemvm', 'router', 'ilbvm'].includes($route.meta.name) && 'listVirtualMachines' in $store.getters.apis && 'createConsoleEndpoint' in $store.getters.apis"
     @click="consoleUrl">
     <a-button style="margin-left: 5px" shape="circle" type="dashed" :size="size" :disabled="['Stopped', 'Error', 'Destroyed'].includes(resource.state) || resource.hostcontrolstate === 'Offline'" >
-      <code-outlined />
+      <code-outlined v-if="!copyUrlToClipboard"/>
+      <copy-outlined v-else />
     </a-button>
   </a>
 </template>
@@ -39,7 +40,8 @@
     size: {
       type: String,
       default: 'small'
-    }
+    },
+    copyUrlToClipboard: Boolean
   },
   data () {
     return {
@@ -53,7 +55,21 @@
       api('createConsoleEndpoint', params).then(json => {
         this.url = (json && json.createconsoleendpointresponse) ? json.createconsoleendpointresponse.consoleendpoint.url : '#/exception/404'
         if (json.createconsoleendpointresponse.consoleendpoint.success) {
-          window.open(this.url, '_blank')
+          if (this.copyUrlToClipboard) {
+            this.$message.success({
+              content: this.$t('label.copied.clipboard')
+            })
+            const hiddenElement = document.createElement('textarea')
+            hiddenElement.value = this.url
+            document.body.appendChild(hiddenElement)
+            hiddenElement.focus()
+            hiddenElement.select()
+
+            document.execCommand('copy')
+            document.body.removeChild(hiddenElement)
+          } else {
+            window.open(this.url, '_blank')
+          }
         } else {
           this.$notification.error({
             message: this.$t('error.execute.api.failed') + ' ' + 'createConsoleEndpoint',
diff --git a/ui/src/components/widgets/Status.vue b/ui/src/components/widgets/Status.vue
index 6243882..6575d40 100644
--- a/ui/src/components/widgets/Status.vue
+++ b/ui/src/components/widgets/Status.vue
@@ -16,14 +16,16 @@
 // under the License.
 
 <template>
-  <a-tooltip placement="bottom" :title="getTooltip(text)">
-    <a-badge
-      :style="getStyle()"
-      :title="text"
-      :color="getStatusColor(text)"
-      :status="getBadgeStatus(text)"
-      :text="getText()" />
-  </a-tooltip>
+  <div style="display: inline-flex;">
+    <a-tooltip placement="bottom" :title="getTooltip(text)">
+      <a-badge
+        :style="getStyle()"
+        :title="text"
+        :color="getStatusColor(text)"
+        :status="getBadgeStatus(text)"
+        :text="getText()" />
+    </a-tooltip>
+  </div>
 </template>
 
 <script>
diff --git a/ui/src/config/section/account.js b/ui/src/config/section/account.js
index 21878c1..3141b96 100644
--- a/ui/src/config/section/account.js
+++ b/ui/src/config/section/account.js
@@ -199,9 +199,8 @@
       label: 'label.action.delete.account',
       message: 'message.delete.account',
       dataView: true,
-      show: (record, store) => {
-        return ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) && !record.isdefault &&
-          !(record.domain === 'ROOT' && record.name === 'admin' && record.accounttype === 1)
+      disabled: (record, store) => {
+        return record.id !== 'undefined' && store.userInfo.accountid === record.id
       },
       groupAction: true,
       popup: true,
diff --git a/ui/src/config/section/compute.js b/ui/src/config/section/compute.js
index 6aa2bef..6d2c55b 100644
--- a/ui/src/config/section/compute.js
+++ b/ui/src/config/section/compute.js
@@ -455,7 +455,7 @@
       docHelp: 'plugins/cloudstack-kubernetes-service.html',
       permission: ['listKubernetesClusters'],
       columns: (store) => {
-        var fields = ['name', 'state', 'size', 'cpunumber', 'memory']
+        var fields = ['name', 'state', 'clustertype', 'size', 'cpunumber', 'memory']
         if (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) {
           fields.push('account')
         }
@@ -465,7 +465,11 @@
         fields.push('zonename')
         return fields
       },
-      details: ['name', 'description', 'zonename', 'kubernetesversionname', 'autoscalingenabled', 'minsize', 'maxsize', 'size', 'controlnodes', 'cpunumber', 'memory', 'keypair', 'associatednetworkname', 'account', 'domain', 'zonename', 'created'],
+      filters: () => {
+        const filters = ['cloud.managed', 'external.managed']
+        return filters
+      },
+      details: ['name', 'description', 'zonename', 'kubernetesversionname', 'autoscalingenabled', 'minsize', 'maxsize', 'size', 'controlnodes', 'cpunumber', 'memory', 'keypair', 'associatednetworkname', 'account', 'domain', 'zonename', 'clustertype', 'created'],
       tabs: [{
         name: 'k8s',
         component: shallowRef(defineAsyncComponent(() => import('@/views/compute/KubernetesServiceTab.vue')))
@@ -488,7 +492,7 @@
           message: 'message.kubernetes.cluster.start',
           docHelp: 'plugins/cloudstack-kubernetes-service.html#starting-a-stopped-kubernetes-cluster',
           dataView: true,
-          show: (record) => { return ['Stopped'].includes(record.state) },
+          show: (record) => { return ['Stopped'].includes(record.state) && record.clustertype === 'CloudManaged' },
           groupAction: true,
           popup: true,
           groupMap: (selection) => { return selection.map(x => { return { id: x } }) }
@@ -500,7 +504,7 @@
           message: 'message.kubernetes.cluster.stop',
           docHelp: 'plugins/cloudstack-kubernetes-service.html#stopping-kubernetes-cluster',
           dataView: true,
-          show: (record) => { return !['Stopped', 'Destroyed', 'Destroying'].includes(record.state) },
+          show: (record) => { return !['Stopped', 'Destroyed', 'Destroying'].includes(record.state) && record.clustertype === 'CloudManaged' },
           groupAction: true,
           popup: true,
           groupMap: (selection) => { return selection.map(x => { return { id: x } }) }
@@ -512,7 +516,7 @@
           message: 'message.kubernetes.cluster.scale',
           docHelp: 'plugins/cloudstack-kubernetes-service.html#scaling-kubernetes-cluster',
           dataView: true,
-          show: (record) => { return ['Created', 'Running', 'Stopped'].includes(record.state) },
+          show: (record) => { return ['Created', 'Running', 'Stopped'].includes(record.state) && record.clustertype === 'CloudManaged' },
           popup: true,
           component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ScaleKubernetesCluster.vue')))
         },
@@ -523,7 +527,7 @@
           message: 'message.kubernetes.cluster.upgrade',
           docHelp: 'plugins/cloudstack-kubernetes-service.html#upgrading-kubernetes-cluster',
           dataView: true,
-          show: (record) => { return ['Created', 'Running'].includes(record.state) },
+          show: (record) => { return ['Created', 'Running'].includes(record.state) && record.clustertype === 'CloudManaged' },
           popup: true,
           component: shallowRef(defineAsyncComponent(() => import('@/views/compute/UpgradeKubernetesCluster.vue')))
         },
@@ -537,7 +541,11 @@
           show: (record) => { return !['Destroyed', 'Destroying'].includes(record.state) },
           groupAction: true,
           popup: true,
-          groupMap: (selection) => { return selection.map(x => { return { id: x } }) }
+          args: (record, store, group) => {
+            return (['Admin'].includes(store.userInfo.roletype) || store.features.allowuserexpungerecovervm)
+              ? ['cleanup', 'expunge'] : ['cleanup']
+          },
+          groupMap: (selection, values) => { return selection.map(x => { return { id: x, expunge: values.expunge, cleanup: values.cleanup } }) }
         }
       ]
     },
diff --git a/ui/src/config/section/config.js b/ui/src/config/section/config.js
index c7e0972..3cddc63 100644
--- a/ui/src/config/section/config.js
+++ b/ui/src/config/section/config.js
@@ -25,6 +25,7 @@
       name: 'globalsetting',
       title: 'label.global.settings',
       icon: 'setting-outlined',
+      docHelp: 'adminguide/index.html#tuning',
       permission: ['listConfigurations'],
       listView: true,
       popup: true,
@@ -34,6 +35,7 @@
       name: 'ldapsetting',
       title: 'label.ldap.configuration',
       icon: 'team-outlined',
+      docHelp: 'adminguide/accounts.html#using-an-ldap-server-for-user-authentication',
       permission: ['listLdapConfigurations'],
       columns: ['hostname', 'port', 'domainid'],
       details: ['hostname', 'port', 'domainid'],
@@ -72,6 +74,7 @@
       name: 'hypervisorcapability',
       title: 'label.hypervisor.capabilities',
       icon: 'database-outlined',
+      docHelp: 'adminguide/hosts.html?highlight=Hypervisor%20capabilities#hypervisor-capabilities',
       permission: ['listHypervisorCapabilities'],
       columns: ['hypervisor', 'hypervisorversion', 'maxguestslimit', 'maxhostspercluster'],
       details: ['hypervisor', 'hypervisorversion', 'maxguestslimit', 'maxdatavolumeslimit', 'maxhostspercluster', 'securitygroupenabled', 'storagemotionenabled'],
@@ -84,6 +87,102 @@
           args: ['maxguestslimit']
         }
       ]
+    },
+    {
+      name: 'guestos',
+      title: 'label.guest.os',
+      docHelp: 'adminguide/guest_os.html#guest-os',
+      icon: 'laptop-outlined',
+      permission: ['listOsTypes', 'listOsCategories'],
+      columns: ['name', 'oscategoryname', 'isuserdefined'],
+      details: ['name', 'oscategoryname', 'isuserdefined'],
+      related: [{
+        name: 'guestoshypervisormapping',
+        title: 'label.guest.os.hypervisor.mappings',
+        param: 'ostypeid'
+      }],
+      actions: [
+        {
+          api: 'addGuestOs',
+          icon: 'plus-outlined',
+          label: 'label.add.guest.os',
+          listView: true,
+          dataView: false,
+          args: ['osdisplayname', 'oscategoryid'],
+          mapping: {
+            oscategoryid: {
+              api: 'listOsCategories',
+              params: (record) => { return { oscategoryid: record.id } }
+            }
+          }
+        },
+        {
+          api: 'updateGuestOs',
+          icon: 'edit-outlined',
+          label: 'label.edit',
+          dataView: true,
+          popup: true,
+          args: ['osdisplayname']
+        },
+        {
+          api: 'addGuestOsMapping',
+          icon: 'link-outlined',
+          label: 'label.add.guest.os.hypervisor.mapping',
+          dataView: true,
+          popup: true,
+          args: ['ostypeid', 'hypervisor', 'hypervisorversion', 'osnameforhypervisor', 'osmappingcheckenabled', 'forced'],
+          mapping: {
+            ostypeid: {
+              value: (record) => { return record.id }
+            }
+          }
+        },
+        {
+          api: 'removeGuestOs',
+          icon: 'delete-outlined',
+          label: 'label.action.delete.guest.os',
+          message: 'message.action.delete.guest.os',
+          dataView: true,
+          popup: true
+        }
+      ]
+    },
+    {
+      name: 'guestoshypervisormapping',
+      title: 'label.guest.os.hypervisor.mappings',
+      docHelp: 'adminguide/guest_os.html#guest-os-hypervisor-mapping',
+      icon: 'api-outlined',
+      permission: ['listGuestOsMapping'],
+      columns: ['hypervisor', 'hypervisorversion', 'osdisplayname', 'osnameforhypervisor'],
+      details: ['hypervisor', 'hypervisorversion', 'osdisplayname', 'osnameforhypervisor', 'isuserdefined'],
+      filters: ['all', 'kvm', 'vmware', 'xenserver', 'lxc', 'ovm3'],
+      searchFilters: ['osdisplayname', 'osnameforhypervisor', 'hypervisor', 'hypervisorversion'],
+      actions: [
+        {
+          api: 'addGuestOsMapping',
+          icon: 'plus-outlined',
+          label: 'label.add.guest.os.hypervisor.mapping',
+          listView: true,
+          dataView: false,
+          args: ['ostypeid', 'hypervisor', 'hypervisorversion', 'osnameforhypervisor', 'osmappingcheckenabled', 'forced']
+        },
+        {
+          api: 'updateGuestOsMapping',
+          icon: 'edit-outlined',
+          label: 'label.edit',
+          dataView: true,
+          popup: true,
+          args: ['osnameforhypervisor', 'osmappingcheckenabled']
+        },
+        {
+          api: 'removeGuestOsMapping',
+          icon: 'delete-outlined',
+          label: 'label.action.delete.guest.os.hypervisor.mapping',
+          message: 'message.action.delete.guest.os.hypervisor.mapping',
+          dataView: true,
+          popup: true
+        }
+      ]
     }
   ]
 }
diff --git a/ui/src/config/section/event.js b/ui/src/config/section/event.js
index 4673a64..5f4b27b 100644
--- a/ui/src/config/section/event.js
+++ b/ui/src/config/section/event.js
@@ -29,6 +29,9 @@
     title: 'label.event.timeline',
     param: 'startid'
   }],
+  filters: () => {
+    return ['active', 'archived']
+  },
   actions: [
     {
       api: 'archiveEvents',
@@ -45,6 +48,12 @@
         ids: {
           value: (record) => { return record.id }
         }
+      },
+      show: (record) => {
+        return !(record.archived)
+      },
+      groupShow: (selectedItems) => {
+        return selectedItems.filter(x => { return !(x.archived) }).length > 0
       }
     },
     {
diff --git a/ui/src/config/section/image.js b/ui/src/config/section/image.js
index c95e0b9..049ec15 100644
--- a/ui/src/config/section/image.js
+++ b/ui/src/config/section/image.js
@@ -93,6 +93,7 @@
           api: 'registerTemplate',
           icon: 'cloud-upload-outlined',
           label: 'label.upload.template.from.local',
+          show: () => { return 'getUploadParamsForTemplate' in store.getters.apis },
           docHelp: 'adminguide/templates.html#uploading-templates-and-isos-from-a-local-computer',
           listView: true,
           popup: true,
@@ -233,6 +234,7 @@
           api: 'registerIso',
           icon: 'cloud-upload-outlined',
           label: 'label.upload.iso.from.local',
+          show: () => { return 'getUploadParamsForIso' in store.getters.apis },
           docHelp: 'adminguide/templates.html#id10',
           listView: true,
           popup: true,
diff --git a/ui/src/config/section/infra/clusters.js b/ui/src/config/section/infra/clusters.js
index 904938c..ca6dde7 100644
--- a/ui/src/config/section/infra/clusters.js
+++ b/ui/src/config/section/infra/clusters.js
@@ -22,6 +22,7 @@
   name: 'cluster',
   title: 'label.clusters',
   icon: 'cluster-outlined',
+  docHelp: 'conceptsandterminology/concepts.html#about-clusters',
   permission: ['listClustersMetrics'],
   columns: () => {
     const fields = ['name', 'state', 'allocationstate', 'clustertype', 'hypervisortype', 'hosts']
diff --git a/ui/src/config/section/infra/hosts.js b/ui/src/config/section/infra/hosts.js
index 9f2c629..60f30e3 100644
--- a/ui/src/config/section/infra/hosts.js
+++ b/ui/src/config/section/infra/hosts.js
@@ -22,6 +22,7 @@
   name: 'host',
   title: 'label.hosts',
   icon: 'desktop-outlined',
+  docHelp: 'conceptsandterminology/concepts.html#about-hosts',
   permission: ['listHostsMetrics'],
   resourceType: 'Host',
   filters: () => {
@@ -102,8 +103,9 @@
       label: 'label.disable.host',
       message: 'message.confirm.disable.host',
       dataView: true,
-      defaultArgs: { allocationstate: 'Disable' },
-      show: (record) => { return record.resourcestate === 'Enabled' }
+      show: (record) => { return record.resourcestate === 'Enabled' },
+      popup: true,
+      component: shallowRef(defineAsyncComponent(() => import('@/views/infra/HostEnableDisable')))
     },
     {
       api: 'updateHost',
@@ -111,8 +113,9 @@
       label: 'label.enable.host',
       message: 'message.confirm.enable.host',
       dataView: true,
-      defaultArgs: { allocationstate: 'Enable' },
-      show: (record) => { return record.resourcestate === 'Disabled' }
+      show: (record) => { return record.resourcestate === 'Disabled' },
+      popup: true,
+      component: shallowRef(defineAsyncComponent(() => import('@/views/infra/HostEnableDisable')))
     },
     {
       api: 'prepareHostForMaintenance',
diff --git a/ui/src/config/section/infra/ilbvms.js b/ui/src/config/section/infra/ilbvms.js
index beba33e..fa20d69 100644
--- a/ui/src/config/section/infra/ilbvms.js
+++ b/ui/src/config/section/infra/ilbvms.js
@@ -20,6 +20,7 @@
   name: 'ilbvm',
   title: 'label.internal.lb',
   icon: 'share-alt-outlined',
+  docHelp: 'adminguide/networking_and_traffic.html#creating-an-internal-lb-rule',
   permission: ['listInternalLoadBalancerVMs'],
   params: { projectid: '-1' },
   columns: ['name', 'state', 'publicip', 'guestnetworkname', 'vpcname', 'version', 'softwareversion', 'hostname', 'account', 'zonename', 'requiresupgrade'],
diff --git a/ui/src/config/section/infra/managementServers.js b/ui/src/config/section/infra/managementServers.js
index 6059af9..d1dfa6d 100644
--- a/ui/src/config/section/infra/managementServers.js
+++ b/ui/src/config/section/infra/managementServers.js
@@ -22,7 +22,9 @@
   name: 'managementserver',
   title: 'label.management.servers',
   icon: 'CloudServerOutlined',
+  docHelp: 'conceptsandterminology/concepts.html#management-server-overview',
   permission: ['listManagementServersMetrics'],
+  resourceType: 'ManagementServer',
   columns: () => {
     const fields = ['name', 'state', 'version']
     const metricsFields = ['collectiontime', 'availableprocessors', 'cpuload', 'heapmemoryused', 'agentcount']
@@ -36,6 +38,53 @@
     {
       name: 'details',
       component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
+    },
+    {
+      name: 'pending.jobs',
+      component: shallowRef(defineAsyncComponent(() => import('@/views/infra/AsyncJobsTab.vue')))
+    },
+    {
+      name: 'comments',
+      component: shallowRef(defineAsyncComponent(() => import('@/components/view/AnnotationsTab.vue')))
+    }
+  ],
+  actions: [
+    {
+      api: 'prepareForShutdown',
+      icon: 'exclamation-circle-outlined',
+      label: 'label.prepare.for.shutdown',
+      message: 'message.prepare.for.shutdown',
+      dataView: true,
+      popup: true,
+      confirmationText: 'SHUTDOWN',
+      show: (record, store) => { return record.state === 'Up' },
+      component: shallowRef(defineAsyncComponent(() => import('@/views/infra/Confirmation.vue')))
+    },
+    {
+      api: 'triggerShutdown',
+      icon: 'poweroff-outlined',
+      label: 'label.trigger.shutdown',
+      message: 'message.trigger.shutdown',
+      dataView: true,
+      popup: true,
+      confirmationText: 'SHUTDOWN',
+      show: (record, store) => { return ['Up', 'PreparingToShutDown', 'ReadyToShutDown'].includes(record.state) },
+      component: shallowRef(defineAsyncComponent(() => import('@/views/infra/Confirmation.vue')))
+    },
+    {
+      api: 'cancelShutdown',
+      icon: 'close-circle-outlined',
+      label: 'label.cancel.shutdown',
+      message: 'message.cancel.shutdown',
+      docHelp: 'installguide/configuration.html#adding-a-zone',
+      dataView: true,
+      popup: true,
+      show: (record, store) => { return ['PreparingToShutDown', 'ReadyToShutDown', 'ShuttingDown'].includes(record.state) },
+      mapping: {
+        managementserverid: {
+          value: (record, params) => { return record.id }
+        }
+      }
     }
   ]
 }
diff --git a/ui/src/config/section/infra/pods.js b/ui/src/config/section/infra/pods.js
index a462478..eff62e0 100644
--- a/ui/src/config/section/infra/pods.js
+++ b/ui/src/config/section/infra/pods.js
@@ -22,6 +22,7 @@
   name: 'pod',
   title: 'label.pods',
   icon: 'appstore-outlined',
+  docHelp: 'conceptsandterminology/concepts.html#about-pods',
   permission: ['listPods'],
   columns: ['name', 'allocationstate', 'gateway', 'netmask', 'zonename'],
   details: ['name', 'id', 'allocationstate', 'netmask', 'gateway', 'zonename'],
diff --git a/ui/src/config/section/infra/zones.js b/ui/src/config/section/infra/zones.js
index cc9fa16..b2768f7 100644
--- a/ui/src/config/section/infra/zones.js
+++ b/ui/src/config/section/infra/zones.js
@@ -22,6 +22,7 @@
   name: 'zone',
   title: 'label.zones',
   icon: 'global-outlined',
+  docHelp: 'conceptsandterminology/concepts.html#about-zones',
   permission: ['listZonesMetrics'],
   columns: () => {
     const fields = ['name', 'allocationstate', 'type', 'networktype', 'clusters']
diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js
index 2f4b5b0..b5ebc0f 100644
--- a/ui/src/config/section/network.js
+++ b/ui/src/config/section/network.js
@@ -30,6 +30,7 @@
       name: 'guestnetwork',
       title: 'label.guest.networks',
       icon: 'apartment-outlined',
+      docHelp: 'adminguide/networking_and_traffic.html#adding-an-additional-guest-network',
       permission: ['listNetworks'],
       resourceType: 'Network',
       columns: () => {
@@ -59,7 +60,7 @@
       }, {
         name: 'egress.rules',
         component: shallowRef(defineAsyncComponent(() => import('@/views/network/EgressRulesTab.vue'))),
-        show: (record, route, user) => { return record.type === 'Isolated' && !('vpcid' in record) && 'listEgressFirewallRules' in store.getters.apis && (['Admin', 'DomainAdmin'].includes(user.roletype) || record.account === user.account || record.projectid) }
+        show: (record, route, user) => { return record.type === 'Isolated' && !('vpcname' in record) && 'listEgressFirewallRules' in store.getters.apis && (['Admin', 'DomainAdmin'].includes(user.roletype) || record.account === user.account || record.projectid) }
       }, {
         name: 'ip.v6.firewall',
         component: shallowRef(defineAsyncComponent(() => import('@/views/network/Ipv6FirewallRulesTab.vue'))),
@@ -67,7 +68,7 @@
       }, {
         name: 'public.ip.addresses',
         component: shallowRef(defineAsyncComponent(() => import('@/views/network/IpAddressesTab.vue'))),
-        show: (record, route, user) => { return 'listPublicIpAddresses' in store.getters.apis && (record.type === 'Shared' || (record.type === 'Isolated' && !('vpcid' in record) && (['Admin', 'DomainAdmin'].includes(user.roletype) || record.account === user.account || record.projectid))) }
+        show: (record, route, user) => { return 'listPublicIpAddresses' in store.getters.apis && (record.type === 'Shared' || (record.type === 'Isolated' && !('vpcname' in record) && (['Admin', 'DomainAdmin'].includes(user.roletype) || record.account === user.account || record.projectid))) }
       }, {
         name: 'virtual.routers',
         component: shallowRef(defineAsyncComponent(() => import('@/views/network/RoutersTab.vue'))),
@@ -129,6 +130,7 @@
           icon: 'edit-outlined',
           label: 'label.update.network',
           dataView: true,
+          disabled: (record, user) => { return (record.account !== user.userInfo.account && !['Admin', 'DomainAdmin'].includes(user.userInfo.roletype)) },
           popup: true,
           component: shallowRef(defineAsyncComponent(() => import('@/views/network/UpdateNetwork.vue')))
         },
@@ -138,6 +140,7 @@
           label: 'label.restart.network',
           message: 'message.restart.network',
           dataView: true,
+          disabled: (record, user) => { return (record.account !== user.userInfo.account && !['Admin', 'DomainAdmin'].includes(user.userInfo.roletype)) },
           args: (record, store, isGroupAction) => {
             var fields = []
             if (isGroupAction || record.vpcid == null) {
@@ -176,6 +179,7 @@
           label: 'label.action.delete.network',
           message: 'message.action.delete.network',
           dataView: true,
+          disabled: (record, user) => { return (record.account !== user.userInfo.account && !['Admin', 'DomainAdmin'].includes(user.userInfo.roletype)) },
           groupAction: true,
           popup: true,
           groupMap: (selection) => { return selection.map(x => { return { id: x } }) }
@@ -224,7 +228,7 @@
           icon: 'edit-outlined',
           label: 'label.edit',
           dataView: true,
-          args: ['name', 'displaytext', 'publicmtu']
+          args: ['name', 'displaytext', 'publicmtu', 'sourcenatipaddress']
         },
         {
           api: 'restartVPC',
@@ -319,7 +323,7 @@
       docHelp: 'adminguide/networking_and_traffic.html#reserving-public-ip-addresses-and-vlans-for-accounts',
       permission: ['listPublicIpAddresses'],
       resourceType: 'PublicIpAddress',
-      columns: ['ipaddress', 'state', 'associatednetworkname', 'virtualmachinename', 'allocated', 'account', 'zonename'],
+      columns: ['ipaddress', 'state', 'associatednetworkname', 'vpcname', 'virtualmachinename', 'allocated', 'account', 'zonename'],
       details: ['ipaddress', 'id', 'associatednetworkname', 'virtualmachinename', 'networkid', 'issourcenat', 'isstaticnat', 'virtualmachinename', 'vmipaddress', 'vlan', 'allocated', 'account', 'zonename'],
       filters: ['allocated', 'reserved', 'free'],
       component: shallowRef(() => import('@/views/network/PublicIpResource.vue')),
@@ -905,6 +909,7 @@
       name: 'guestvlans',
       title: 'label.guest.vlan',
       icon: 'folder-outlined',
+      docHelp: 'conceptsandterminology/network_setup.html#vlan-allocation-example',
       permission: ['listGuestVlans'],
       resourceType: 'GuestVlan',
       filters: ['allocatedonly', 'all'],
diff --git a/ui/src/config/section/project.js b/ui/src/config/section/project.js
index a9bfb95..adbfac7 100644
--- a/ui/src/config/section/project.js
+++ b/ui/src/config/section/project.js
@@ -101,7 +101,7 @@
       icon: 'edit-outlined',
       label: 'label.edit.project.details',
       dataView: true,
-      args: ['displaytext'],
+      args: ['name', 'displaytext'],
       show: (record, store) => {
         return (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) || record.isCurrentUserProjectAdmin
       }
diff --git a/ui/src/config/section/storage.js b/ui/src/config/section/storage.js
index e8a5ecd..bec5404 100644
--- a/ui/src/config/section/storage.js
+++ b/ui/src/config/section/storage.js
@@ -108,6 +108,7 @@
           icon: 'cloud-upload-outlined',
           docHelp: 'adminguide/storage.html#uploading-an-existing-volume-to-a-virtual-machine',
           label: 'label.upload.volume.from.local',
+          show: () => { return 'getUploadParamsForVolume' in store.getters.apis },
           listView: true,
           popup: true,
           component: shallowRef(defineAsyncComponent(() => import('@/views/storage/UploadLocalVolume.vue')))
diff --git a/ui/src/config/section/user.js b/ui/src/config/section/user.js
index 894e4a6..eef9ea3 100644
--- a/ui/src/config/section/user.js
+++ b/ui/src/config/section/user.js
@@ -68,6 +68,7 @@
       api: 'registerUserKeys',
       icon: 'file-protect-outlined',
       label: 'label.action.generate.keys',
+      hoverLabel: 'label.action.generate.api.secret.keys',
       message: 'message.generate.keys',
       dataView: true
     },
@@ -144,9 +145,8 @@
       label: 'label.action.delete.user',
       message: 'message.delete.user',
       dataView: true,
-      show: (record, store) => {
-        return ['Admin', 'DomainAdmin'].includes(store.userInfo.roletype) && !record.isdefault &&
-          !(record.domain === 'ROOT' && record.account === 'admin' && record.accounttype === 1)
+      disabled: (record, store) => {
+        return record.id !== 'undefined' && store.userInfo.id === record.id
       }
     }
   ]
diff --git a/ui/src/core/lazy_lib/components_use.js b/ui/src/core/lazy_lib/components_use.js
index 10790d6..1c2e8ee 100644
--- a/ui/src/core/lazy_lib/components_use.js
+++ b/ui/src/core/lazy_lib/components_use.js
@@ -68,6 +68,9 @@
 import VueClipboard from 'vue3-clipboard'
 import VueCropper from 'vue-cropper'
 
+import cronAnt from '@vue-js-cron/ant'
+import '@vue-js-cron/ant/dist/ant.css'
+
 export default {
   install: (app) => {
     app.config.globalProperties.$confirm = Modal.confirm
@@ -77,6 +80,7 @@
     app.config.globalProperties.$error = Modal.error
     app.config.globalProperties.$warning = Modal.warning
 
+    app.use(cronAnt)
     app.use(VueClipboard, { autoSetContainer: true })
     app.use(VueCropper)
     app.use(ConfigProvider)
diff --git a/ui/src/core/lazy_lib/icons_use.js b/ui/src/core/lazy_lib/icons_use.js
index ec2d67d..0a95fac 100644
--- a/ui/src/core/lazy_lib/icons_use.js
+++ b/ui/src/core/lazy_lib/icons_use.js
@@ -16,6 +16,7 @@
 // under the License.
 
 import {
+  AimOutlined,
   ApartmentOutlined,
   ApiOutlined,
   AppstoreOutlined,
@@ -118,6 +119,7 @@
   MoreOutlined,
   NotificationOutlined,
   NumberOutlined,
+  LaptopOutlined,
   OrderedListOutlined,
   PaperClipOutlined,
   PauseCircleOutlined,
@@ -170,6 +172,7 @@
 
 export default {
   install: (app) => {
+    app.component('AimOutlined', AimOutlined)
     app.component('ApartmentOutlined', ApartmentOutlined)
     app.component('ApiOutlined', ApiOutlined)
     app.component('AppstoreOutlined', AppstoreOutlined)
@@ -272,6 +275,7 @@
     app.component('MoreOutlined', MoreOutlined)
     app.component('NotificationOutlined', NotificationOutlined)
     app.component('NumberOutlined', NumberOutlined)
+    app.component('LaptopOutlined', LaptopOutlined)
     app.component('OrderedListOutlined', OrderedListOutlined)
     app.component('PaperClipOutlined', PaperClipOutlined)
     app.component('PauseCircleOutlined', PauseCircleOutlined)
diff --git a/ui/src/layouts/UserLayout.vue b/ui/src/layouts/UserLayout.vue
index 24ed6b4..6c81c85 100644
--- a/ui/src/layouts/UserLayout.vue
+++ b/ui/src/layouts/UserLayout.vue
@@ -46,6 +46,7 @@
 <script>
 import RouteView from '@/layouts/RouteView'
 import { mixinDevice } from '@/utils/mixin.js'
+import notification from 'ant-design-vue/es/notification'
 
 export default {
   name: 'UserLayout',
@@ -90,7 +91,7 @@
   },
   methods: {
     onClearNotification () {
-      this.$notification.destroy()
+      notification.destroy()
       this.$store.commit('SET_COUNT_NOTIFY', 0)
     }
   }
diff --git a/ui/src/permission.js b/ui/src/permission.js
index ec6a816..b780073 100644
--- a/ui/src/permission.js
+++ b/ui/src/permission.js
@@ -26,7 +26,7 @@
 import message from 'ant-design-vue/es/message'
 import notification from 'ant-design-vue/es/notification'
 import { setDocumentTitle } from '@/utils/domUtil'
-import { ACCESS_TOKEN, APIS, SERVER_MANAGER } from '@/store/mutation-types'
+import { ACCESS_TOKEN, APIS, SERVER_MANAGER, CURRENT_PROJECT } from '@/store/mutation-types'
 
 NProgress.configure({ showSpinner: false }) // NProgress Configuration
 
@@ -104,7 +104,8 @@
               } else {
                 next({ path: redirect })
               }
-              store.dispatch('ToggleTheme', 'light')
+              const project = vueProps.$localStorage.get(CURRENT_PROJECT)
+              store.dispatch('ToggleTheme', project.id === undefined ? 'light' : 'dark')
             })
           })
           .catch(() => {
diff --git a/ui/src/store/getters.js b/ui/src/store/getters.js
index f6a6dab..d795e33 100644
--- a/ui/src/store/getters.js
+++ b/ui/src/store/getters.js
@@ -44,6 +44,7 @@
   countNotify: state => state.user.countNotify,
   customColumns: state => state.user.customColumns,
   logoutFlag: state => state.user.logoutFlag,
+  shutdownTriggered: state => state.user.shutdownTriggered,
   twoFaEnabled: state => state.user.twoFaEnabled,
   twoFaProvider: state => state.user.twoFaProvider,
   twoFaIssuer: state => state.user.twoFaIssuer,
diff --git a/ui/src/store/modules/app.js b/ui/src/store/modules/app.js
index 8ed27f8..f8753a1 100644
--- a/ui/src/store/modules/app.js
+++ b/ui/src/store/modules/app.js
@@ -121,6 +121,9 @@
     SET_CUSTOM_COLUMNS: (state, customColumns) => {
       vueProps.$localStorage.set(CUSTOM_COLUMNS, customColumns)
       state.customColumns = customColumns
+    },
+    SET_SHUTDOWN_TRIGGERED: (state, shutdownTriggered) => {
+      state.shutdownTriggered = shutdownTriggered
     }
   },
   actions: {
@@ -177,6 +180,9 @@
     },
     SetCustomColumns ({ commit }, bool) {
       commit('SET_CUSTOM_COLUMNS', bool)
+    },
+    SetShutdownTriggered ({ commit }, bool) {
+      commit('SET_SHUTDOWN_TRIGGERED', bool)
     }
   }
 }
diff --git a/ui/src/store/modules/user.js b/ui/src/store/modules/user.js
index 3e9aef7..0513802 100644
--- a/ui/src/store/modules/user.js
+++ b/ui/src/store/modules/user.js
@@ -61,6 +61,7 @@
     loginFlag: false,
     logoutFlag: false,
     customColumns: {},
+    shutdownTriggered: false,
     twoFaEnabled: false,
     twoFaProvider: '',
     twoFaIssuer: ''
@@ -133,6 +134,9 @@
       vueProps.$localStorage.set(CUSTOM_COLUMNS, customColumns)
       state.customColumns = customColumns
     },
+    SET_SHUTDOWN_TRIGGERED: (state, shutdownTriggered) => {
+      state.shutdownTriggered = shutdownTriggered
+    },
     SET_LOGOUT_FLAG: (state, flag) => {
       state.logoutFlag = flag
     },
diff --git a/ui/src/style/common/function.less b/ui/src/style/common/function.less
index 76d3fe9..b6ab109 100644
--- a/ui/src/style/common/function.less
+++ b/ui/src/style/common/function.less
@@ -1380,4 +1380,4 @@
 // It is hacky way to make this function will be compiled preferentially by less
 // resolve error: `ReferenceError: colorPalette is not defined`
 // https://github.com/ant-design/ant-motion/issues/44
-.colorPaletteMixin();
\ No newline at end of file
+.colorPaletteMixin();
diff --git a/ui/src/style/dark-mode.less b/ui/src/style/dark-mode.less
index 1b338ea..5ff6d5d 100644
--- a/ui/src/style/dark-mode.less
+++ b/ui/src/style/dark-mode.less
@@ -83,6 +83,7 @@
 
   .sider.light {
     background: @dark-secondary-bgColor;
+    padding-top: 15px;
 
     .logo {
       background-color: @dark-secondary-bgColor;
@@ -139,6 +140,10 @@
         color: @dark-text-color-3;
       }
     }
+
+    &-inline, &-vertical, &-vertical-left {
+      border-color: transparent;
+    }
   }
 
   .kubernet-icon path
@@ -289,6 +294,10 @@
       & > tr > th.ant-table-column-sort {
         background-color: @dark-bgColor;
       }
+
+      & > tr.ant-table-row:hover > td, & > tr > td.ant-table-cell-row-hover {
+        background: transparent;
+      }
     }
 
     &-footer {
@@ -336,6 +345,12 @@
         border-color: @dark-border-color;
       }
     }
+
+    &-small {
+      .ant-table-thead > tr > th {
+        background-color: transparent;
+      }
+    }
   }
 
   .light-row, .dark-row {
@@ -524,13 +539,17 @@
       background-color: #1890ff;
     }
 
-    &-loading-icon, &:after {
+    &-loading-icon, &::before {
       background-color: @dark-secondary-bgColor;
     }
 
     &:disabled {
       background-color: @disabled-bgColor;
     }
+
+    &-handle::before {
+      background-color: @dark-secondary-bgColor;
+    }
   }
 
   .ant-select-dropdown {
@@ -783,7 +802,7 @@
     background-color: @dark-secondary-bgColor;
   }
 
-  .ant-upload.ant-upload-drag {
+  .ant-form-item .ant-upload.ant-upload-drag {
     background-color: transparent;
     border-color: @dark-border-color;
   }
@@ -792,12 +811,43 @@
     color: @dark-text-color-3;
   }
 
-  .ant-tree.ant-tree-show-line li span.ant-tree-switcher {
+  .ant-upload-list {
+    color: @dark-text-color-3;
+
+    &-item {
+      &:hover {
+        .ant-upload-list-item-info {
+          background: @dark-bgColor;
+        }
+
+        .ant-upload-list-item-card-actions-btn {
+          border-color: transparent;
+        }
+
+        .ant-upload-list-item-card-actions .anticon {
+          color: @dark-text-color-3;
+        }
+      }
+    }
+  }
+
+  .ant-upload-list-item-info {
+    .anticon-loading .anticon,
+    .ant-upload-text-icon .anticon {
+      color: rgba(255, 255, 255, 0.65);
+    }
+  }
+
+  .ant-tree {
+    background: transparent;
+  }
+
+  .ant-tree-show-line .ant-tree-switcher {
     background-color: transparent;
     color: @dark-text-color-3;
   }
 
-  .ant-tree li .ant-tree-node-content-wrapper {
+  .ant-tree .ant-tree-node-content-wrapper {
     color: @dark-text-color-3;
   }
 
@@ -806,7 +856,7 @@
     background-color: transparent;
   }
 
-  .ant-tree li .ant-tree-node-content-wrapper.ant-tree-node-selected {
+  .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected {
     .ant-tree-icon__customize {
       color: #000;
     }
@@ -814,7 +864,7 @@
     color: #000;
   }
 
-  .ant-tree li .ant-tree-node-content-wrapper:hover {
+  .ant-tree .ant-tree-node-content-wrapper:hover {
     .ant-tree-icon__customize {
       color: #000;
     }
@@ -959,4 +1009,4 @@
   .button-clear-notification {
     background-color: @dark-secondary-bgColor;
   }
-}
\ No newline at end of file
+}
diff --git a/ui/src/style/frame/content.less b/ui/src/style/frame/content.less
index aa11574..bc47d35 100644
--- a/ui/src/style/frame/content.less
+++ b/ui/src/style/frame/content.less
@@ -24,4 +24,4 @@
       margin-right: 8px;
     }
   }
-}
\ No newline at end of file
+}
diff --git a/ui/src/style/frame/search.less b/ui/src/style/frame/search.less
index 3e0f952..3c98626 100644
--- a/ui/src/style/frame/search.less
+++ b/ui/src/style/frame/search.less
@@ -49,4 +49,4 @@
     white-space: nowrap;
   }
 
-}
\ No newline at end of file
+}
diff --git a/ui/src/style/frame/sider.less b/ui/src/style/frame/sider.less
index c021946..80304dd 100644
--- a/ui/src/style/frame/sider.less
+++ b/ui/src/style/frame/sider.less
@@ -84,4 +84,4 @@
     }
   }
 
-}
\ No newline at end of file
+}
diff --git a/ui/src/style/frame/top-menu.less b/ui/src/style/frame/top-menu.less
index 4998735..3712902 100644
--- a/ui/src/style/frame/top-menu.less
+++ b/ui/src/style/frame/top-menu.less
@@ -20,4 +20,4 @@
     max-width: 1200px;
     margin: 0 auto;
   }
-}
\ No newline at end of file
+}
diff --git a/ui/src/style/index.less b/ui/src/style/index.less
index 38b4c6b..c0f1866 100644
--- a/ui/src/style/index.less
+++ b/ui/src/style/index.less
@@ -16,8 +16,8 @@
 // under the License.
 
 //* import all  ## official ant ##  variables; mixins and styles
-@import "~ant-design-vue/lib/style/themes/default";
-@import "~ant-design-vue/lib/style/core/index";
+@import "~ant-design-vue/es/style/themes/default.less";
+@import "~ant-design-vue/es/style/core/index.less";
 
 //* import all  ## custom ##  variables, mixins and styles
 
diff --git a/ui/src/style/objects/table.less b/ui/src/style/objects/table.less
index 8b51257..6992543 100644
--- a/ui/src/style/objects/table.less
+++ b/ui/src/style/objects/table.less
@@ -17,4 +17,4 @@
 
 .table-alert {
   margin-bottom: 16px;
-}
\ No newline at end of file
+}
diff --git a/ui/src/style/vars.less b/ui/src/style/vars.less
index 6d219a1..b80e2b0 100644
--- a/ui/src/style/vars.less
+++ b/ui/src/style/vars.less
@@ -505,4 +505,33 @@
 .ant-dropdown-menu-item:hover,
 .ant-dropdown-menu-submenu-title:hover {
   background-color: color(~`colorPalette("@{primary-color}", 1)`) !important;
-}
\ No newline at end of file
+}
+
+.ant-tabs.tab-center {
+  > .ant-tabs-nav, > div > .ant-tabs-nav,
+  > .ant-tabs-nav .ant-tabs-nav-wrap,
+  > div > .ant-tabs-nav .ant-tabs-nav-wrap {
+    justify-content: center;
+  }
+}
+
+.ant-tabs-large>.ant-tabs-nav .ant-tabs-tab {
+  padding: 16px;
+}
+
+.ant-steps {
+  &-item-container {
+    &:hover {
+      .ant-steps-item-content .ant-steps-item-description {
+        color: inherit !important;
+      }
+    }
+  }
+
+  &-item-process {
+    .ant-steps-item-content .ant-steps-item-title {
+      color: inherit !important;
+      font-weight: 600;
+    }
+  }
+}
diff --git a/ui/src/utils/request.js b/ui/src/utils/request.js
index 9b9ce27..5f22307 100644
--- a/ui/src/utils/request.js
+++ b/ui/src/utils/request.js
@@ -193,6 +193,7 @@
   cancel: () => {
     if (!source) sourceToken.init()
     source.cancel()
+    source = null
   }
 }
 
diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue
index c8e931b..3c476e1 100644
--- a/ui/src/views/AutogenView.vue
+++ b/ui/src/views/AutogenView.vue
@@ -17,10 +17,10 @@
 
 <template>
   <div>
-    <a-affix :offsetTop="78">
+    <a-affix :offsetTop="this.$store.getters.shutdownTriggered ? 103 : 78">
       <a-card class="breadcrumb-card" style="z-index: 10">
         <a-row>
-          <a-col :span="device === 'mobile' ? 24 : 12" style="padding-left: 12px">
+          <a-col :span="device === 'mobile' ? 24 : 12" style="padding-left: 12px; margin-top: 10px">
             <breadcrumb :resource="resource">
               <template #end>
                 <a-button
@@ -34,14 +34,14 @@
                 </a-button>
                 <a-switch
                   v-if="!dataView && ['vm', 'volume', 'zone', 'cluster', 'host', 'storagepool', 'managementserver'].includes($route.name)"
-                  style="margin-left: 8px"
+                  style="margin-left: 8px; margin-bottom: 3px"
                   :checked-children="$t('label.metrics')"
                   :un-checked-children="$t('label.metrics')"
                   :checked="$store.getters.metrics"
                   @change="(checked, event) => { $store.dispatch('SetMetrics', checked) }"/>
                 <a-switch
                   v-if="!projectView && hasProjectId"
-                  style="margin-left: 8px"
+                  style="margin-left: 8px; margin-bottom: 3px"
                   :checked-children="$t('label.projects')"
                   :un-checked-children="$t('label.projects')"
                   :checked="$store.getters.listAllProjects"
@@ -53,14 +53,8 @@
                   <a-select
                     v-if="!dataView && filters && filters.length > 0"
                     :placeholder="$t('label.filterby')"
-                    :value="$route.query.filter || (projectView && $route.name === 'vm' ||
-                      ['Admin', 'DomainAdmin'].includes($store.getters.userInfo.roletype) &&
-                      ['vm', 'iso', 'template', 'pod', 'cluster', 'host', 'systemvm', 'router', 'storagepool'].includes($route.name)
-                        ? 'all' : ['publicip'].includes($route.name)
-                        ? 'allocated' : ['account', 'guestnetwork', 'guestvlans'].includes($route.name)
-                        ? 'all' : ['volume'].includes($route.name)
-                        ? 'user' : 'self')"
-                    style="min-width: 120px; margin-left: 10px"
+                    :value="filterValue"
+                    style="min-width: 120px; margin-left: 10px; margin-top: -4px"
                     @change="changeFilter"
                     showSearch
                     optionFilterProp="label"
@@ -70,7 +64,7 @@
                     <template #suffixIcon><filter-outlined class="ant-select-suffix" /></template>
                     <a-select-option
                       v-if="['Admin', 'DomainAdmin'].includes($store.getters.userInfo.roletype) &&
-                      ['vm', 'iso', 'template', 'pod', 'cluster', 'host', 'systemvm', 'router', 'storagepool'].includes($route.name) ||
+                      ['vm', 'iso', 'template', 'pod', 'cluster', 'host', 'systemvm', 'router', 'storagepool', 'kubernetes'].includes($route.name) ||
                       ['account'].includes($route.name)"
                       key="all"
                       :label="$t('label.all')">
@@ -90,7 +84,7 @@
           </a-col>
           <a-col
             :span="device === 'mobile' ? 24 : 12"
-            :style="device === 'mobile' ? { float: 'right', 'margin-top': '12px', 'margin-bottom': '-6px', display: 'table' } : { float: 'right', display: 'table', 'margin-bottom': '-6px' }" >
+            :style="device === 'mobile' ? { float: 'right', 'margin-top': '12px', 'margin-bottom': '-6px', display: 'table' } : { float: 'right', display: 'table', 'margin-bottom': '-4px' }" >
             <slot name="action" v-if="dataView && $route.path.startsWith('/publicip')"></slot>
             <action-button
               v-else
@@ -105,6 +99,7 @@
             <search-view
               v-if="!dataView"
               :searchFilters="searchFilters"
+              style="min-width: 120px; margin-left: 10px; margin-top: 5px"
               :searchParams="searchParams"
               :apiName="apiName"
               @search="onSearch"
@@ -252,11 +247,14 @@
                   showSearch
                   optionFilterProp="label"
                   :filterOption="(input, option) => {
-                    return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                   }"
                 >
-                  <a-select-option key="" >{{ }}</a-select-option>
-                  <a-select-option v-for="(opt, optIndex) in currentAction.mapping[field.name].options" :key="optIndex">
+                  <a-select-option key="" label="">{{ }}</a-select-option>
+                  <a-select-option
+                    v-for="(opt, optIndex) in currentAction.mapping[field.name].options"
+                    :key="optIndex"
+                    :label="opt">
                     {{ opt }}
                   </a-select-option>
                 </a-select>
@@ -269,12 +267,15 @@
                   :loading="field.loading"
                   :placeholder="field.description"
                   :filterOption="(input, option) => {
-                    return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                   }"
                   v-focus="fieldIndex === firstIndex"
                 >
-                  <a-select-option key="">{{ }}</a-select-option>
-                  <a-select-option v-for="(opt, optIndex) in field.opts" :key="optIndex">
+                  <a-select-option key="" label="">{{ }}</a-select-option>
+                  <a-select-option
+                    v-for="(opt, optIndex) in field.opts"
+                    :key="optIndex"
+                    :label="opt.name || opt.description || opt.traffictype || opt.publicip">
                     {{ opt.name || opt.description || opt.traffictype || opt.publicip }}
                   </a-select-option>
                 </a-select>
@@ -343,10 +344,13 @@
                   showSearch
                   optionFilterProp="label"
                   :filterOption="(input, option) => {
-                    return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                   }"
                 >
-                  <a-select-option v-for="(opt, optIndex) in field.opts" :key="optIndex">
+                  <a-select-option
+                    v-for="(opt, optIndex) in field.opts"
+                    :key="optIndex"
+                    :label="opt.name && opt.type ? opt.name + ' (' + opt.type + ')' : opt.name || opt.description">
                     {{ opt.name && opt.type ? opt.name + ' (' + opt.type + ')' : opt.name || opt.description }}
                   </a-select-option>
                 </a-select>
@@ -389,44 +393,46 @@
       </a-modal>
     </div>
 
-    <div v-if="dataView" style="margin-top: -10px">
-      <slot name="resource" v-if="$route.path.startsWith('/quotasummary') || $route.path.startsWith('/publicip')"></slot>
-      <resource-view
-        v-else
-        :resource="resource"
-        :loading="loading"
-        :tabs="$route.meta.tabs" />
-    </div>
-    <div class="row-element" v-else>
-      <list-view
-        :loading="loading"
-        :columns="columns"
-        :items="items"
-        :actions="actions"
-        :columnKeys="columnKeys"
-        :selectedColumns="selectedColumns"
-        ref="listview"
-        @update-selected-columns="updateSelectedColumns"
-        @selection-change="onRowSelectionChange"
-        @refresh="this.fetchData"
-        @edit-tariff-action="(showAction, record) => $emit('edit-tariff-action', showAction, record)"/>
-      <a-pagination
-        class="row-element"
-        style="margin-top: 10px"
-        size="small"
-        :current="page"
-        :pageSize="pageSize"
-        :total="itemCount"
-        :showTotal="total => `${$t('label.showing')} ${Math.min(total, 1+((page-1)*pageSize))}-${Math.min(page*pageSize, total)} ${$t('label.of')} ${total} ${$t('label.items')}`"
-        :pageSizeOptions="pageSizeOptions"
-        @change="changePage"
-        @showSizeChange="changePageSize"
-        showSizeChanger
-        showQuickJumper>
-        <template #buildOptionText="props">
-          <span>{{ props.value }} / {{ $t('label.page') }}</span>
-        </template>
-      </a-pagination>
+    <div :style="this.$store.getters.shutdownTriggered ? 'margin-top: 25px;' : null">
+      <div v-if="dataView" style="margin-top: -10px">
+        <slot name="resource" v-if="$route.path.startsWith('/quotasummary') || $route.path.startsWith('/publicip')"></slot>
+        <resource-view
+          v-else
+          :resource="resource"
+          :loading="loading"
+          :tabs="$route.meta.tabs" />
+      </div>
+      <div class="row-element" v-else>
+        <list-view
+          :loading="loading"
+          :columns="columns"
+          :items="items"
+          :actions="actions"
+          :columnKeys="columnKeys"
+          :selectedColumns="selectedColumns"
+          ref="listview"
+          @update-selected-columns="updateSelectedColumns"
+          @selection-change="onRowSelectionChange"
+          @refresh="fetchData"
+          @edit-tariff-action="(showAction, record) => $emit('edit-tariff-action', showAction, record)"/>
+        <a-pagination
+          class="row-element"
+          style="margin-top: 10px"
+          size="small"
+          :current="page"
+          :pageSize="pageSize"
+          :total="itemCount"
+          :showTotal="total => `${$t('label.showing')} ${Math.min(total, 1+((page-1)*pageSize))}-${Math.min(page*pageSize, total)} ${$t('label.of')} ${total} ${$t('label.items')}`"
+          :pageSizeOptions="pageSizeOptions"
+          @change="changePage"
+          @showSizeChange="changePageSize"
+          showSizeChanger
+          showQuickJumper>
+          <template #buildOptionText="props">
+            <span>{{ props.value }} / {{ $t('label.page') }}</span>
+          </template>
+        </a-pagination>
+      </div>
     </div>
     <bulk-action-progress
       :showGroupActionModal="showGroupActionModal"
@@ -664,6 +670,25 @@
       return [...new Set(sizes)].sort(function (a, b) {
         return a - b
       }).map(String)
+    },
+    filterValue () {
+      if (this.$route.query.filter) {
+        return this.$route.query.filter
+      }
+      const routeName = this.$route.name
+      if ((this.projectView && routeName === 'vm') || (['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype) && ['vm', 'iso', 'template', 'pod', 'cluster', 'host', 'systemvm', 'router', 'storagepool'].includes(routeName)) || ['account', 'guestnetwork', 'guestvlans', 'guestos', 'guestoshypervisormapping', 'kubernetes'].includes(routeName)) {
+        return 'all'
+      }
+      if (['publicip'].includes(routeName)) {
+        return 'allocated'
+      }
+      if (['volume'].includes(routeName)) {
+        return 'user'
+      }
+      if (['event'].includes(routeName)) {
+        return 'active'
+      }
+      return 'self'
     }
   },
   methods: {
@@ -810,7 +835,6 @@
         })
       }
 
-      const customRender = {}
       for (var columnKey of this.columnKeys) {
         let key = columnKey
         let title = columnKey === 'cidr' && this.columnKeys.includes('ip6cidr') ? 'ipv4.cidr' : columnKey
@@ -818,18 +842,16 @@
           if ('customTitle' in columnKey && 'field' in columnKey) {
             key = columnKey.field
             title = columnKey.customTitle
-            customRender[key] = columnKey[key]
           } else {
             key = Object.keys(columnKey)[0]
             title = Object.keys(columnKey)[0]
-            customRender[key] = columnKey[key]
           }
         }
         this.columns.push({
+          key: key,
           title: this.$t('label.' + String(title).toLowerCase()),
           dataIndex: key,
-          slots: { customRender: key },
-          sorter: function (a, b) { return genericCompare(a[this.dataIndex] || '', b[this.dataIndex] || '') }
+          sorter: function (a, b) { return genericCompare(a[key] || '', b[key] || '') }
         })
         this.selectedColumns.push(key)
       }
@@ -851,6 +873,7 @@
           this.$t('label.linklocalip'), this.$t('label.size'), this.$t('label.sizegb'), this.$t('label.current'),
           this.$t('label.created'), this.$t('label.order')].includes(column.title)
       })
+      this.chosenColumns.splice(this.chosenColumns.length - 1, 1)
 
       if (['listTemplates', 'listIsos'].includes(this.apiName) && this.dataView) {
         delete params.showunique
@@ -958,12 +981,6 @@
 
         for (let idx = 0; idx < this.items.length; idx++) {
           this.items[idx].key = idx
-          for (const key in customRender) {
-            const func = customRender[key]
-            if (func && typeof func === 'function') {
-              this.items[idx][key] = func(this.items[idx])
-            }
-          }
           if (this.$route.path.startsWith('/ldapsetting')) {
             this.items[idx].id = this.items[idx].hostname
           }
@@ -1117,6 +1134,14 @@
                 description: self.$t('label.confirmpassword.description')
               }
             }
+            if (arg === 'ostypeid') {
+              return {
+                type: 'uuid',
+                name: 'ostypeid',
+                required: true,
+                description: self.$t('label.select.guest.os.type')
+              }
+            }
             return paramFields.filter(function (param) {
               return param.name.toLowerCase() === arg.toLowerCase()
             })[0]
@@ -1305,9 +1330,9 @@
           this.bulkColumns = this.chosenColumns
           this.selectedItems = this.selectedItems.map(v => ({ ...v, status: 'InProgress' }))
           this.bulkColumns.splice(0, 0, {
+            key: 'status',
             dataIndex: 'status',
             title: this.$t('label.operation.status'),
-            slots: { customRender: 'status' },
             filters: [
               { text: 'In Progress', value: 'InProgress' },
               { text: 'Success', value: 'success' },
@@ -1559,13 +1584,17 @@
       }
 
       this.columns = this.allColumns.filter(x => this.selectedColumns.includes(x.dataIndex))
-      this.columns.push({
-        dataIndex: 'dropdownFilter',
-        slots: {
-          filterDropdown: 'filterDropdown',
-          filterIcon: 'filterIcon'
-        }
-      })
+      const filterColumn = {
+        key: 'filtercolumn',
+        dataIndex: 'filtercolumn',
+        title: '',
+        customFilterDropdown: true,
+        width: 5
+      }
+      if (this.columns.length === 0) {
+        filterColumn.width = 'auto'
+      }
+      this.columns.push(filterColumn)
       if (!this.$store.getters.customColumns[this.$store.getters.userInfo.id]) {
         this.$store.getters.customColumns[this.$store.getters.userInfo.id] = {}
       }
@@ -1638,6 +1667,24 @@
         } else if (filter === 'allocatedonly') {
           query.allocatedonly = 'true'
         }
+      } else if (this.$route.name === 'event') {
+        if (filter === 'archived') {
+          query.archived = true
+        } else {
+          delete query.archived
+        }
+      } else if (this.$route.name === 'guestoshypervisormapping') {
+        if (filter === 'all') {
+          delete query.hypervisor
+        } else {
+          query.hypervisor = filter
+        }
+      } else if (this.$route.name === 'kubernetes') {
+        if (filter === 'all') {
+          delete query.clustertype
+        } else {
+          query.clustertype = filter === 'cloud.managed' ? 'CloudManaged' : 'ExternalManaged'
+        }
       }
       query.filter = filter
       query.page = '1'
@@ -1663,6 +1710,10 @@
               query.templatetype = value
             } else if (this.$route.name === 'globalsetting') {
               query.name = value
+            } else if (this.$route.name === 'guestoshypervisormapping') {
+              query.hypervisor = value
+            } else if (this.$route.name === 'guestos') {
+              query.description = value
             } else {
               query.keyword = value
             }
@@ -1808,7 +1859,6 @@
           this.rules[field.name].push(rule)
           break
         default:
-          console.log('hererere')
           rule.required = field.required
           rule.message = this.$t('message.error.required.input')
           this.rules[field.name].push(rule)
diff --git a/ui/src/views/auth/Login.vue b/ui/src/views/auth/Login.vue
index 34f5a70..56ac141 100644
--- a/ui/src/views/auth/Login.vue
+++ b/ui/src/views/auth/Login.vue
@@ -26,6 +26,7 @@
     v-ctrl-enter="handleSubmit"
   >
     <a-tabs
+      class="tab-center"
       :activeKey="customActiveKey"
       size="large"
       :tabBarStyle="{ textAlign: 'center', borderBottom: 'unset' }"
@@ -48,9 +49,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }">
-            <a-select-option v-for="item in $config.servers" :key="(item.apiHost || '') + item.apiBase">
+            <a-select-option v-for="item in $config.servers" :key="(item.apiHost || '') + item.apiBase" :label="item.name">
               <template #prefix>
                 <database-outlined />
               </template>
@@ -113,9 +114,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option v-for="item in $config.servers" :key="(item.apiHost || '') + item.apiBase">
+            <a-select-option v-for="item in $config.servers" :key="(item.apiHost || '') + item.apiBase" :label="item.name">
               <template #prefix>
                 <database-outlined />
               </template>
@@ -129,9 +130,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option v-for="(idp, idx) in idps" :key="idx" :value="idp.id">
+            <a-select-option v-for="(idp, idx) in idps" :key="idx" :value="idp.id" :label="idp.orgName">
               {{ idp.orgName }}
             </a-select-option>
           </a-select>
diff --git a/ui/src/views/compute/AssignInstance.vue b/ui/src/views/compute/AssignInstance.vue
index 9acc821..ed3efbc 100644
--- a/ui/src/views/compute/AssignInstance.vue
+++ b/ui/src/views/compute/AssignInstance.vue
@@ -35,9 +35,9 @@
           v-model:value="selectedAccountType"
           v-focus="true"
           showSearch
-          optionFilterProp="label"
+          optionFilterProp="value"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }">
           <a-select-option :value="$t('label.account')">{{ $t('label.account') }}</a-select-option>
           <a-select-option :value="$t('label.project')">{{ $t('label.project') }}</a-select-option>
@@ -71,7 +71,7 @@
             @change="changeAccount"
             v-model:value="selectedAccount"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
               return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
diff --git a/ui/src/views/compute/AttachIso.vue b/ui/src/views/compute/AttachIso.vue
index 20b9e4e..ba54219 100644
--- a/ui/src/views/compute/AttachIso.vue
+++ b/ui/src/views/compute/AttachIso.vue
@@ -31,9 +31,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }">
-            <a-select-option v-for="iso in isos" :key="iso.id">
+            <a-select-option v-for="iso in isos" :key="iso.id" :label="iso.displaytext || iso.name">
               {{ iso.displaytext || iso.name }}
             </a-select-option>
           </a-select>
diff --git a/ui/src/views/compute/AutoScaleDownPolicyTab.vue b/ui/src/views/compute/AutoScaleDownPolicyTab.vue
index ecbc584..422d1ab 100644
--- a/ui/src/views/compute/AutoScaleDownPolicyTab.vue
+++ b/ui/src/views/compute/AutoScaleDownPolicyTab.vue
@@ -36,12 +36,13 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-                      return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                      return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                     }" >
           <a-select-option
             v-for="(scalepolicy, index) in this.policies"
             :value="scalepolicy.id"
-            :key="index">
+            :key="index"
+            :label="scalepolicy.displaytext || scalepolicy.name" >
             {{ scalepolicy.name || scalepolicy.id }}
           </a-select-option>
         </a-select>
@@ -109,28 +110,24 @@
       :dataSource="policy.conditions"
       :pagination="false"
       :rowKey="record => record.id">
-      <template #name="{ record }">
-        {{ record.name }}
-      </template>
-      <template #relationaloperator="{ record }">
-        {{ getOperator(record.relationaloperator) }}
-      </template>
-      <template #threshold="{ record }">
-        {{ record.threshold }}
-      </template>
-      <template #actions="{ record }">
-        <tooltip-button
-          :tooltip="$t('label.edit')"
-          :disabled="!('updateCondition' in $store.getters.apis) || resource.state !== 'DISABLED'"
-          icon="edit-outlined"
-          @onClick="() => openUpdateConditionModal(record)" />
-        <tooltip-button
-          :tooltip="$t('label.delete')"
-          :disabled="!('deleteCondition' in $store.getters.apis) || resource.state !== 'DISABLED'"
-          type="primary"
-          :danger="true"
-          icon="delete-outlined"
-          @onClick="deleteConditionFromAutoScalePolicy(record.id)" />
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'relationaloperator'">
+          {{ getOperator(record.relationaloperator) }}
+        </template>
+        <template v-if="column.key === 'actions'">
+          <tooltip-button
+            :tooltip="$t('label.edit')"
+            :disabled="!('updateCondition' in $store.getters.apis) || resource.state !== 'DISABLED'"
+            icon="edit-outlined"
+            @onClick="() => openUpdateConditionModal(record)" />
+          <tooltip-button
+            :tooltip="$t('label.delete')"
+            :disabled="!('deleteCondition' in $store.getters.apis) || resource.state !== 'DISABLED'"
+            type="primary"
+            :danger="true"
+            icon="delete-outlined"
+            @onClick="deleteConditionFromAutoScalePolicy(record.id)" />
+        </template>
       </template>
     </a-table>
 
@@ -147,11 +144,15 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             v-focus="true"
             v-model:value="newCondition.counterid">
-            <a-select-option v-for="(counter, index) in countersList" :value="counter.id" :key="index">
+            <a-select-option
+              v-for="(counter, index) in countersList"
+              :value="counter.id"
+              :key="index"
+              :label="counter.name" >
               {{ counter.name }}
             </a-select-option>
           </a-select>
@@ -165,11 +166,11 @@
           <a-select
             v-model:value="newCondition.relationaloperator"
             style="width: 100%;"
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="LT">{{ getOperator('LT') }}</a-select-option>
+            <a-select-option value="LT" >{{ getOperator('LT') }}</a-select-option>
           </a-select>
           <span class="error-text">{{ $t('label.required') }}</span>
         </div>
@@ -216,11 +217,11 @@
           <a-select
             v-model:value="updateConditionDetails.relationaloperator"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="LT">{{ getOperator('LT') }}</a-select-option>
+            <a-select-option value="LT" >{{ getOperator('LT') }}</a-select-option>
           </a-select>
         </div>
         <div class="update-condition__item">
@@ -277,10 +278,14 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             v-model:value="newPolicy.counterid">
-            <a-select-option v-for="(counter, index) in countersList" :value="counter.id" :key="index">
+            <a-select-option
+              v-for="(counter, index) in countersList"
+              :value="counter.id"
+              :key="index"
+              :label="counter.name">
               {{ counter.name }}
             </a-select-option>
           </a-select>
@@ -293,11 +298,11 @@
           <a-select
             v-model:value="newPolicy.relationaloperator"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="LT">{{ getOperator('LT') }}</a-select-option>
+            <a-select-option value="LT" >{{ getOperator('LT') }}</a-select-option>
           </a-select>
         </div>
         <div class="update-condition__item">
@@ -338,7 +343,7 @@
   },
   data () {
     return {
-      filterColumns: ['Action'],
+      filterColumns: ['Actions'],
       loading: true,
       policies: [],
       isEditable: false,
@@ -377,15 +382,15 @@
         },
         {
           title: this.$t('label.relationaloperator'),
-          slots: { customRender: 'relationaloperator' }
+          key: 'relationaloperator'
         },
         {
           title: this.$t('label.threshold'),
-          slots: { customRender: 'threshold' }
+          dataIndex: 'threshold'
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          title: this.$t('label.actions'),
+          key: 'actions'
         }
       ]
     }
diff --git a/ui/src/views/compute/AutoScaleLoadBalancing.vue b/ui/src/views/compute/AutoScaleLoadBalancing.vue
index f6e29b3..6091689 100644
--- a/ui/src/views/compute/AutoScaleLoadBalancing.vue
+++ b/ui/src/views/compute/AutoScaleLoadBalancing.vue
@@ -33,16 +33,37 @@
       :dataSource="lbRules"
       :pagination="false"
       :rowKey="record => record.id">
-      <template #algorithm="{ record }">
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'algorithm'">
         {{ returnAlgorithmName(record.algorithm) }}
-      </template>
-      <template #protocol="{record}">
-        {{ getCapitalise(record.protocol) }}
-      </template>
-      <template #stickiness="{record}">
-        <a-button @click="() => openStickinessModal(record.id)">
-          {{ returnStickinessLabel(record.id) }}
-        </a-button>
+        </template>
+        <template v-if="column.key === 'protocol'">
+          {{ getCapitalise(record.protocol) }}
+        </template>
+        <template v-if="column.key === 'stickiness'">
+          <a-button @click="() => openStickinessModal(record.id)">
+            {{ returnStickinessLabel(record.id) }}
+          </a-button>
+        </template>
+        <template v-if="column.key === 'actions'">
+          <div class="actions">
+            <tooltip-button :tooltip="$t('label.edit')" icon="edit-outlined" @onClick="() => openEditRuleModal(record)" />
+            <tooltip-button :tooltip="$t('label.edit.tags')" :disabled="!('updateLoadBalancerRule' in $store.getters.apis)" icon="tag-outlined" @onClick="() => openTagsModal(record.id)" />
+            <a-popconfirm
+              :title="$t('label.delete') + '?'"
+              @confirm="handleDeleteRule(record)"
+              :okText="$t('label.yes')"
+              :cancelText="$t('label.no')"
+            >
+              <tooltip-button
+                :tooltip="$t('label.delete')"
+                :disabled="!('deleteLoadBalancerRule' in $store.getters.apis) || record.autoscalevmgroup"
+                type="primary"
+                :danger="true"
+                icon="delete-outlined" />
+            </a-popconfirm>
+          </div>
+        </template>
       </template>
       <template #expandedRowRender="{ record }">
         <div class="rule-instance-list">
@@ -67,25 +88,6 @@
           </div>
         </div>
       </template>
-      <template #actions="{record}">
-        <div class="actions">
-          <tooltip-button :tooltip="$t('label.edit')" icon="edit-outlined" @onClick="() => openEditRuleModal(record)" />
-          <tooltip-button :tooltip="$t('label.edit.tags')" :disabled="!('updateLoadBalancerRule' in $store.getters.apis)" icon="tag-outlined" @onClick="() => openTagsModal(record.id)" />
-          <a-popconfirm
-            :title="$t('label.delete') + '?'"
-            @confirm="handleDeleteRule(record)"
-            :okText="$t('label.yes')"
-            :cancelText="$t('label.no')"
-          >
-            <tooltip-button
-              :tooltip="$t('label.delete')"
-              :disabled="!('deleteLoadBalancerRule' in $store.getters.apis) || record.autoscalevmgroup"
-              type="primary"
-              :danger="true"
-              icon="delete-outlined" />
-          </a-popconfirm>
-        </div>
-      </template>
     </a-table>
     <a-modal
       v-if="tagsModalVisible"
@@ -169,12 +171,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="LbCookie">{{ $t('label.lb.cookie') }}</a-select-option>
-            <a-select-option value="AppCookie">{{ $t('label.app.cookie') }}</a-select-option>
-            <a-select-option value="SourceBased">{{ $t('label.source.based') }}</a-select-option>
-            <a-select-option value="none">{{ $t('label.none') }}</a-select-option>
+            <a-select-option value="LbCookie" :label="$t('label.lb.cookie')">{{ $t('label.lb.cookie') }}</a-select-option>
+            <a-select-option value="AppCookie" :label="$t('label.lb.cookie')">{{ $t('label.app.cookie') }}</a-select-option>
+            <a-select-option value="SourceBased" :label="$t('label.lb.cookie')">{{ $t('label.source.based') }}</a-select-option>
+            <a-select-option value="none" :label="$t('label.lb.cookie')">{{ $t('label.none') }}</a-select-option>
           </a-select>
         </a-form-item>
         <a-form-item
@@ -261,9 +263,9 @@
           <a-select
             v-model:value="editRuleDetails.algorithm"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option value="roundrobin">{{ $t('label.lb.algorithm.roundrobin') }}</a-select-option>
             <a-select-option value="leastconn">{{ $t('label.lb.algorithm.leastconn') }}</a-select-option>
@@ -275,9 +277,9 @@
           <a-select
             v-model:value="editRuleDetails.protocol"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option value="tcp-proxy">{{ $t('label.tcp.proxy') }}</a-select-option>
             <a-select-option value="tcp">{{ $t('label.tcp') }}</a-select-option>
@@ -355,11 +357,11 @@
         },
         {
           title: this.$t('label.algorithm'),
-          slots: { customRender: 'algorithm' }
+          key: 'algorithm'
         },
         {
           title: this.$t('label.protocol'),
-          slots: { customRender: 'protocol' }
+          key: 'protocol'
         },
         {
           title: this.$t('label.state'),
@@ -367,11 +369,11 @@
         },
         {
           title: this.$t('label.action.configure.stickiness'),
-          slots: { customRender: 'stickiness' }
+          key: 'stickiness'
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          title: this.$t('label.actions'),
+          key: 'actions'
         }
       ],
       tiers: {
@@ -382,13 +384,13 @@
         {
           title: this.$t('label.name'),
           dataIndex: 'name',
-          slots: { customRender: 'name' },
+          key: 'name',
           width: 220
         },
         {
           title: this.$t('label.state'),
           dataIndex: 'state',
-          slots: { customRender: 'state' }
+          key: 'state'
         },
         {
           title: this.$t('label.displayname'),
@@ -404,8 +406,8 @@
         },
         {
           title: this.$t('label.select'),
-          dataIndex: 'action',
-          slots: { customRender: 'action' },
+          dataIndex: 'actions',
+          key: 'actions',
           width: 80
         }
       ],
diff --git a/ui/src/views/compute/AutoScaleUpPolicyTab.vue b/ui/src/views/compute/AutoScaleUpPolicyTab.vue
index 450b954..4ddd67a 100644
--- a/ui/src/views/compute/AutoScaleUpPolicyTab.vue
+++ b/ui/src/views/compute/AutoScaleUpPolicyTab.vue
@@ -36,12 +36,13 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-                      return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                      return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                     }" >
           <a-select-option
             v-for="(scalepolicy, index) in this.policies"
             :value="scalepolicy.id"
-            :key="index">
+            :key="index"
+            :label="scalepolicy.displaytext || scalepolicy.name">
             {{ scalepolicy.name || scalepolicy.id }}
           </a-select-option>
         </a-select>
@@ -109,28 +110,24 @@
       :dataSource="policy.conditions"
       :pagination="false"
       :rowKey="record => record.id">
-      <template #name="{ record }">
-        {{ record.name }}
-      </template>
-      <template #relationaloperator="{ record }">
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'relationaloperator'">
         {{ getOperator(record.relationaloperator) }}
-      </template>
-      <template #threshold="{ record }">
-        {{ record.threshold }}
-      </template>
-      <template #actions="{ record }">
-        <tooltip-button
-          :tooltip="$t('label.edit')"
-          :disabled="!('updateCondition' in $store.getters.apis) || resource.state !== 'DISABLED'"
-          icon="edit-outlined"
-          @onClick="() => openUpdateConditionModal(record)" />
-        <tooltip-button
-          :tooltip="$t('label.delete')"
-          :disabled="!('deleteCondition' in $store.getters.apis) || resource.state !== 'DISABLED'"
-          type="primary"
-          :danger="true"
-          icon="delete-outlined"
-          @onClick="deleteConditionFromAutoScalePolicy(record.id)" />
+        </template>
+        <template v-if="column.key === 'actions'">
+          <tooltip-button
+            :tooltip="$t('label.edit')"
+            :disabled="!('updateCondition' in $store.getters.apis) || resource.state !== 'DISABLED'"
+            icon="edit-outlined"
+            @onClick="() => openUpdateConditionModal(record)" />
+          <tooltip-button
+            :tooltip="$t('label.delete')"
+            :disabled="!('deleteCondition' in $store.getters.apis) || resource.state !== 'DISABLED'"
+            type="primary"
+            :danger="true"
+            icon="delete-outlined"
+            @onClick="deleteConditionFromAutoScalePolicy(record.id)" />
+        </template>
       </template>
     </a-table>
 
@@ -147,11 +144,15 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             v-focus="true"
             v-model:value="newCondition.counterid">
-            <a-select-option v-for="(counter, index) in countersList" :value="counter.id" :key="index">
+            <a-select-option
+              v-for="(counter, index) in countersList"
+              :value="counter.id"
+              :key="index"
+              :label="counter.name">>
               {{ counter.name }}
             </a-select-option>
           </a-select>
@@ -165,9 +166,9 @@
           <a-select
             v-model:value="newCondition.relationaloperator"
             style="width: 100%;"
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option value="GT">{{ getOperator('GT') }}</a-select-option>
           </a-select>
@@ -216,9 +217,9 @@
           <a-select
             v-model:value="updateConditionDetails.relationaloperator"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option value="GT">{{ getOperator('GT') }}</a-select-option>
           </a-select>
@@ -277,10 +278,14 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             v-model:value="newPolicy.counterid">
-            <a-select-option v-for="(counter, index) in countersList" :value="counter.id" :key="index">
+            <a-select-option
+              v-for="(counter, index) in countersList"
+              :value="counter.id"
+              :key="index"
+              :label="counter.name">
               {{ counter.name }}
             </a-select-option>
           </a-select>
@@ -293,9 +298,9 @@
           <a-select
             v-model:value="newPolicy.relationaloperator"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option value="GT">{{ getOperator('GT') }}</a-select-option>
           </a-select>
@@ -338,7 +343,7 @@
   },
   data () {
     return {
-      filterColumns: ['Action'],
+      filterColumns: ['Actions'],
       loading: true,
       policies: [],
       isEditable: false,
@@ -377,15 +382,15 @@
         },
         {
           title: this.$t('label.relationaloperator'),
-          slots: { customRender: 'relationaloperator' }
+          key: 'relationaloperator'
         },
         {
           title: this.$t('label.threshold'),
-          slots: { customRender: 'threshold' }
+          dataIndex: 'threshold'
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          title: this.$t('label.actions'),
+          key: 'actions'
         }
       ]
     }
diff --git a/ui/src/views/compute/AutoScaleVmProfile.vue b/ui/src/views/compute/AutoScaleVmProfile.vue
index 4594775..705bfb5 100644
--- a/ui/src/views/compute/AutoScaleVmProfile.vue
+++ b/ui/src/views/compute/AutoScaleVmProfile.vue
@@ -35,11 +35,15 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             v-focus="true"
             v-model:value="autoscaleuserid">
-            <a-select-option v-for="(user, index) in usersList" :value="user.id" :key="index">
+            <a-select-option
+              v-for="(user, index) in usersList"
+              :value="user.id"
+              :key="index"
+              :label="user.username">
               {{ user.username }}
             </a-select-option>
           </a-select>
@@ -90,9 +94,9 @@
           <a-select
             style="width: 100%"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             v-focus="true"
             v-model:value="newParam.name">
@@ -126,13 +130,8 @@
       :dataSource="allParams"
       :pagination="false"
       :rowKey="record => record.name">
-      <template #name="{ record }">
-        {{ record.name }}
-      </template>
-      <template #threshold="{ record }">
-        {{ record.threshold }}
-      </template>
-      <template #actions="{ record }">
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'actions'">
         <a-popconfirm
           :title="$t('label.delete') + '?'"
           @confirm="deleteParam(record.name)"
@@ -146,6 +145,7 @@
             :danger="true"
             icon="delete-outlined" />
         </a-popconfirm>
+        </template>
       </template>
     </a-table>
 
@@ -166,11 +166,15 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }"
             v-focus="true"
             v-model:value="autoscaleuserid">
-            <a-select-option v-for="(user, index) in usersList" :value="user.id" :key="index">
+            <a-select-option
+              v-for="(user, index) in usersList"
+              :value="user.id"
+              :key="index"
+              :label="user.username">
               {{ user.username }}
             </a-select-option>
           </a-select>
@@ -194,11 +198,15 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
             v-focus="true"
             v-model:value="templateid">
-            <a-select-option v-for="(template, index) in templatesList" :value="template.id" :key="index">
+            <a-select-option
+              v-for="(template, index) in templatesList"
+              :value="template.id"
+              :key="index"
+              :label="template.name">
               {{ template.name }}
             </a-select-option>
           </a-select>
@@ -214,11 +222,15 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
             v-focus="true"
             v-model:value="serviceofferingid">
-            <a-select-option v-for="(offering, index) in serviceOfferingsList" :value="offering.id" :key="index">
+            <a-select-option
+              v-for="(offering, index) in serviceOfferingsList"
+              :value="offering.id"
+              :key="index"
+              :label="offering.name">
               {{ offering.name }}
             </a-select-option>
           </a-select>
@@ -263,7 +275,7 @@
   },
   data () {
     return {
-      filterColumns: ['Action'],
+      filterColumns: ['Actions'],
       loading: true,
       editProfileModalVisible: false,
       profileid: null,
@@ -292,8 +304,8 @@
           dataIndex: 'value'
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          title: this.$t('label.actions'),
+          key: 'actions'
         }
       ]
     }
diff --git a/ui/src/views/compute/CreateAutoScaleVmGroup.vue b/ui/src/views/compute/CreateAutoScaleVmGroup.vue
index 4dcb295..3797077 100644
--- a/ui/src/views/compute/CreateAutoScaleVmGroup.vue
+++ b/ui/src/views/compute/CreateAutoScaleVmGroup.vue
@@ -42,19 +42,17 @@
                               v-model:value="form.zoneid"
                               @change="onSelectZoneId(zoneItem.id)">
                               <a-col :span="8">
-                                <a-card-grid style="width:200px;" :title="zoneItem.name" :hoverable="false">
-                                  <a-radio :value="zoneItem.id">
-                                    <div>
+                                <a-card style="width:200px;" :hoverable="false">
+                                  <a-radio :value="zoneItem.id" />
+                                  <div :style="{fontSize: '36px', marginLeft: '60px', marginTop: '-30px', marginBottom: '10px'}">
                                       <resource-icon
                                         v-if="zoneItem && zoneItem.icon && zoneItem.icon.base64image"
                                         :image="zoneItem.icon.base64image"
-                                        size="36"
-                                        style="marginTop: -30px; marginLeft: 60px" />
-                                      <global-outlined v-else :style="{fontSize: '36px', marginLeft: '60px', marginTop: '-40px'}"/>
+                                        size="36" />
+                                      <global-outlined v-else />
                                     </div>
-                                  </a-radio>
                                   <a-card-meta title="" :description="zoneItem.name" style="text-align:center; paddingTop: 10px;" />
-                                </a-card-grid>
+                                </a-card>
                               </a-col>
                             </a-radio-group>
                           </div>
@@ -152,7 +150,7 @@
                         }"
                         @change="onSelectTemplateConfigurationId"
                       >
-                        <a-select-option v-for="opt in templateConfigurations" :key="opt.id">
+                        <a-select-option v-for="opt in templateConfigurations" :key="opt.id" :label="opt.name || opt.description">
                           {{ opt.name || opt.description }}
                         </a-select-option>
                       </a-select>
@@ -420,11 +418,11 @@
                         <span v-else-if="property.type && property.type==='string' && property.qualifiers && property.qualifiers.startsWith('ValueMap')">
                           <a-select
                             showSearch
-                            optionFilterProp="label"
+                            optionFilterProp="value"
                             v-model:value="form['properties.' + escapePropertyKey(property.key)]"
                             :placeholder="property.description"
                             :filterOption="(input, option) => {
-                              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
                             }"
                           >
                             <a-select-option v-for="opt in getPropertyQualifiers(property.qualifiers, 'select')" :key="opt">
@@ -463,11 +461,12 @@
                       showSearch
                       optionFilterProp="label"
                       :filterOption="(input, option) => {
-                        return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                        return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                       }" >
                       <a-select-option
                         v-for="policy in this.scaleUpPolicies"
-                        :key="policy.id">
+                        :key="policy.id"
+                        :label="policy.name">
                         {{ policy.name }}
                       </a-select-option>
                     </a-select>
@@ -516,11 +515,15 @@
                         showSearch
                         optionFilterProp="label"
                         :filterOption="(input, option) => {
-                          return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                          return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                         }"
                         v-focus="true"
                         v-model:value="newScaleUpCondition.counterid">
-                        <a-select-option v-for="(counter, index) in countersList" :value="counter.id" :key="index">
+                        <a-select-option
+                          v-for="(counter, index) in countersList"
+                          :value="counter.id"
+                          :key="index"
+                          :label="counter.name">
                           {{ counter.name }}
                         </a-select-option>
                       </a-select>
@@ -534,9 +537,9 @@
                       <a-select
                         v-model:value="newScaleUpCondition.relationaloperator"
                         style="width: 100%;"
-                        optionFilterProp="label"
+                        optionFilterProp="value"
                         :filterOption="(input, option) => {
-                          return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                          return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
                         }" >
                         <a-select-option value="GT">{{ getOperator('GT') }}</a-select-option>
                       </a-select>
@@ -568,20 +571,16 @@
                       :dataSource="scaleUpConditions"
                       :pagination="false"
                       :rowKey="record => record.counterid">
-                      <template #countername="{ record }">
-                        {{ record.countername }}
-                      </template>
-                      <template #relationaloperator="{ record }">
-                        {{ getOperator(record.relationaloperator) }}
-                      </template>
-                      <template #threshold="{ record }">
-                        {{ record.threshold }}
-                      </template>
-                      <template #actions="{ record }">
+                      <template #bodyCell="{ column, record }">
+                        <template v-if="column.key === 'relationaloperator'">
+                          {{ getOperator(record.relationaloperator) }}
+                        </template>
+                        <template v-if="column.key === 'actions'">
                           <a-button ref="submit" type="primary" :danger="true" @click="deleteScaleUpCondition(record.counterid)">
                             <template #icon><delete-outlined /></template>
                             {{ $t('label.delete') }}
                           </a-button>
+                        </template>
                       </template>
                     </a-table>
                   </div>
@@ -603,11 +602,12 @@
                       showSearch
                       optionFilterProp="label"
                       :filterOption="(input, option) => {
-                        return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                        return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                       }" >
                       <a-select-option
                         v-for="policy in this.scaleDownPolicies"
-                        :key="policy.id">
+                        :key="policy.id"
+                        :label="policy.name">
                         {{ policy.name }}
                       </a-select-option>
                     </a-select>
@@ -656,11 +656,15 @@
                         showSearch
                         optionFilterProp="label"
                         :filterOption="(input, option) => {
-                          return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                          return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                         }"
                         v-focus="true"
                         v-model:value="newScaleDownCondition.counterid">
-                        <a-select-option v-for="(counter, index) in countersList" :value="counter.id" :key="index">
+                        <a-select-option
+                          v-for="(counter, index) in countersList"
+                          :value="counter.id"
+                          :key="index"
+                          :label="counter.name">
                           {{ counter.name }}
                         </a-select-option>
                       </a-select>
@@ -674,9 +678,9 @@
                       <a-select
                         v-model:value="newScaleDownCondition.relationaloperator"
                         style="width: 100%;"
-                        optionFilterProp="label"
+                        optionFilterProp="value"
                         :filterOption="(input, option) => {
-                          return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                          return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
                         }" >
                         <a-select-option value="LT">{{ getOperator('LT') }}</a-select-option>
                       </a-select>
@@ -699,7 +703,7 @@
                     </div>
                   </div>
                   <a-divider/>
-                  <div>
+                  <div style="display: block">
                     <a-table
                       size="small"
                       style="overflow-y: auto"
@@ -708,20 +712,16 @@
                       :dataSource="scaleDownConditions"
                       :pagination="false"
                       :rowKey="record => record.counterid">
-                      <template #countername="{ record }">
-                        {{ record.countername }}
-                      </template>
-                      <template #relationaloperator="{ record }">
-                        {{ getOperator(record.relationaloperator) }}
-                      </template>
-                      <template #threshold="{ record }">
-                        {{ record.threshold }}
-                      </template>
-                      <template #actions="{ record }">
-                        <a-button ref="submit" type="primary" :danger="true" @click="deleteScaleDownCondition(record.counterid)">
-                          <template #icon><delete-outlined /></template>
-                          {{ $t('label.delete') }}
-                        </a-button>
+                      <template #bodyCell="{ column, record }">
+                        <template v-if="column.key === 'relationaloperator'">
+                          {{ getOperator(record.relationaloperator) }}
+                        </template>
+                        <template v-if="column.key === 'actions'">
+                          <a-button ref="submit" type="primary" :danger="true" @click="deleteScaleDownCondition(record.counterid)">
+                            <template #icon><delete-outlined /></template>
+                            {{ $t('label.delete') }}
+                          </a-button>
+                        </template>
                       </template>
                     </a-table>
                   </div>
@@ -790,11 +790,15 @@
                         showSearch
                         optionFilterProp="label"
                         :filterOption="(input, option) => {
-                          return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                          return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                         }"
                         v-focus="true"
                         v-model:value="form.autoscaleuserid">
-                        <a-select-option v-for="(user, index) in usersList" :value="user.id" :key="index">
+                        <a-select-option
+                          v-for="(user, index) in usersList"
+                          :value="user.id"
+                          :key="index"
+                          :label="user.username">
                           {{ user.username }}
                         </a-select-option>
                       </a-select>
@@ -1079,15 +1083,15 @@
         },
         {
           title: this.$t('label.relationaloperator'),
-          slots: { customRender: 'relationaloperator' }
+          key: 'relationaloperator'
         },
         {
           title: this.$t('label.threshold'),
-          slots: { customRender: 'threshold' }
+          dataIndex: 'threshold'
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          title: this.$t('label.actions'),
+          key: 'actions'
         }
       ],
       scaleDownPolicies: [],
@@ -1107,15 +1111,15 @@
         },
         {
           title: this.$t('label.relationaloperator'),
-          slots: { customRender: 'relationaloperator' }
+          key: 'relationaloperator'
         },
         {
           title: this.$t('label.threshold'),
-          slots: { customRender: 'threshold' }
+          dataIndex: 'threshold'
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          title: this.$t('label.actions'),
+          key: 'actions'
         }
       ],
       usersList: [],
diff --git a/ui/src/views/compute/CreateKubernetesCluster.vue b/ui/src/views/compute/CreateKubernetesCluster.vue
index 9ca7b0a..5c725b7 100644
--- a/ui/src/views/compute/CreateKubernetesCluster.vue
+++ b/ui/src/views/compute/CreateKubernetesCluster.vue
@@ -75,12 +75,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="kubernetesVersionLoading"
             :placeholder="apiParams.kubernetesversionid.description"
             @change="val => { handleKubernetesVersionChange(kubernetesVersions[val]) }">
-            <a-select-option v-for="(opt, optIndex) in kubernetesVersions" :key="optIndex">
+            <a-select-option v-for="(opt, optIndex) in kubernetesVersions" :key="optIndex" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -95,11 +95,11 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="serviceOfferingLoading"
             :placeholder="apiParams.serviceofferingid.description">
-            <a-select-option v-for="(opt, optIndex) in serviceOfferings" :key="optIndex">
+            <a-select-option v-for="(opt, optIndex) in serviceOfferings" :key="optIndex" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -122,11 +122,11 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="networkLoading"
             :placeholder="apiParams.networkid.description">
-            <a-select-option v-for="(opt, optIndex) in networks" :key="optIndex">
+            <a-select-option v-for="(opt, optIndex) in networks" :key="optIndex" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -171,11 +171,11 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="keyPairLoading"
             :placeholder="apiParams.keypair.description">
-            <a-select-option v-for="(opt, optIndex) in keyPairs" :key="optIndex">
+            <a-select-option v-for="(opt, optIndex) in keyPairs" :key="optIndex" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -284,7 +284,6 @@
       })
       this.rules = reactive({
         name: [{ required: true, message: this.$t('message.error.kubecluster.name') }],
-        description: [{ required: true, message: this.$t('message.error.cluster.description') }],
         zoneid: [{ required: true, message: this.$t('message.error.zone.for.cluster') }],
         kubernetesversionid: [{ required: true, message: this.$t('message.error.version.for.cluster') }],
         serviceofferingid: [{ required: true, message: this.$t('message.error.serviceoffering.for.cluster') }],
@@ -460,7 +459,8 @@
           zoneid: this.zones[values.zoneid].id,
           kubernetesversionid: this.kubernetesVersions[values.kubernetesversionid].id,
           serviceofferingid: this.serviceOfferings[values.serviceofferingid].id,
-          size: values.size
+          size: values.size,
+          clustertype: 'CloudManaged'
         }
         if (this.isValidValueForKey(values, 'noderootdisksize') && values.noderootdisksize > 0) {
           params.noderootdisksize = values.noderootdisksize
diff --git a/ui/src/views/compute/CreateSSHKeyPair.vue b/ui/src/views/compute/CreateSSHKeyPair.vue
index 164fbe1..0f879cb 100644
--- a/ui/src/views/compute/CreateSSHKeyPair.vue
+++ b/ui/src/views/compute/CreateSSHKeyPair.vue
@@ -62,12 +62,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="domainLoading"
             :placeholder="apiParams.domainid.description"
             @change="val => { handleDomainChanged(domains[val]) }">
-            <a-select-option v-for="(opt, optIndex) in domains" :key="optIndex">
+            <a-select-option v-for="(opt, optIndex) in domains" :key="optIndex" :label=" opt.path || opt.name || opt.description || ''">
               {{ opt.path || opt.name || opt.description }}
             </a-select-option>
           </a-select>
diff --git a/ui/src/views/compute/CreateSnapshotWizard.vue b/ui/src/views/compute/CreateSnapshotWizard.vue
index bcd7d0f..0da4299 100644
--- a/ui/src/views/compute/CreateSnapshotWizard.vue
+++ b/ui/src/views/compute/CreateSnapshotWizard.vue
@@ -37,11 +37,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }">
             <a-select-option
               v-for="volume in listVolumes"
-              :key="volume.id">
+              :key="volume.id"
+              :label="volume.name">
               {{ volume.name }}
             </a-select-option>
           </a-select>
diff --git a/ui/src/views/compute/DeployVM.vue b/ui/src/views/compute/DeployVM.vue
index c637696..507b902e 100644
--- a/ui/src/views/compute/DeployVM.vue
+++ b/ui/src/views/compute/DeployVM.vue
@@ -42,19 +42,17 @@
                               v-model:value="form.zoneid"
                               @change="onSelectZoneId(zoneItem.id)">
                               <a-col :span="8">
-                                <a-card-grid style="width:200px;" :title="zoneItem.name" :hoverable="false">
-                                  <a-radio :value="zoneItem.id">
-                                    <div>
+                                <a-card style="width:200px;" :hoverable="false">
+                                  <a-radio :value="zoneItem.id" />
+                                  <div :style="{fontSize: '36px', marginLeft: '60px', marginTop: '-30px', marginBottom: '10px'}">
                                       <resource-icon
                                         v-if="zoneItem && zoneItem.icon && zoneItem.icon.base64image"
                                         :image="zoneItem.icon.base64image"
-                                        size="36"
-                                        style="marginTop: -30px; marginLeft: 60px" />
-                                      <global-outlined v-else :style="{fontSize: '36px', marginLeft: '60px', marginTop: '-40px'}"/>
+                                        size="36" />
+                                      <global-outlined v-else/>
                                     </div>
-                                  </a-radio>
                                   <a-card-meta title="" :description="zoneItem.name" style="text-align:center; paddingTop: 10px;" />
-                                </a-card-grid>
+                                </a-card>
                               </a-col>
                             </a-radio-group>
                           </div>
@@ -221,7 +219,7 @@
                         }"
                         @change="onSelectTemplateConfigurationId"
                       >
-                        <a-select-option v-for="opt in templateConfigurations" :key="opt.id">
+                        <a-select-option v-for="opt in templateConfigurations" :key="opt.id" :label="opt.name || opt.description">
                           {{ opt.name || opt.description }}
                         </a-select-option>
                       </a-select>
@@ -389,7 +387,10 @@
                 :status="zoneSelected ? 'process' : 'wait'"
                 v-if="zone && zone.networktype !== 'Basic'">
                 <template #description>
-                  <div v-if="zoneSelected">
+                  <div v-if="zoneSelected" style="margin-top: 5px">
+                    <div style="margin-bottom: 10px">
+                      {{ $t('message.network.selection') }}
+                    </div>
                     <div v-if="vm.templateid && templateNics && templateNics.length > 0">
                       <instance-nics-network-select-list-view
                         :nics="templateNics"
@@ -483,11 +484,11 @@
                         <span v-else-if="property.type && property.type==='string' && property.qualifiers && property.qualifiers.startsWith('ValueMap')">
                           <a-select
                             showSearch
-                            optionFilterProp="label"
+                            optionFilterProp="value"
                             v-model:value="form['properties.' + escapePropertyKey(property.key)]"
                             :placeholder="property.description"
                             :filterOption="(input, option) => {
-                              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
                             }"
                           >
                             <a-select-option v-for="opt in getPropertyQualifiers(property.qualifiers, 'select')" :key="opt">
@@ -528,7 +529,7 @@
                           showSearch
                           optionFilterProp="label"
                           :filterOption="filterOption">
-                          <a-select-option v-for="bootType in options.bootTypes" :key="bootType.id">
+                          <a-select-option v-for="bootType in options.bootTypes" :key="bootType.id" :label="bootType.description">
                             {{ bootType.description }}
                           </a-select-option>
                         </a-select>
@@ -539,7 +540,7 @@
                           showSearch
                           optionFilterProp="label"
                           :filterOption="filterOption">
-                          <a-select-option v-for="bootMode in options.bootModes" :key="bootMode.id">
+                          <a-select-option v-for="bootMode in options.bootModes" :key="bootMode.id" :label="bootMode.description">
                             {{ bootMode.description }}
                           </a-select-option>
                         </a-select>
@@ -582,8 +583,10 @@
                                 :dataSource="templateUserDataParams"
                                 :pagination="false"
                                 :rowKey="record => record.key">
-                                <template #value="{ record }">
-                                  <a-input v-model:value="templateUserDataValues[record.key]" />
+                                <template #bodyCell="{ column, record }">
+                                  <template v-if="column.key === 'value'">
+                                    <a-input v-model:value="templateUserDataValues[record.key]" />
+                                  </template>
                                 </template>
                               </a-table>
                             </a-input-group>
@@ -605,8 +608,10 @@
                                 :dataSource="templateUserDataParams"
                                 :pagination="false"
                                 :rowKey="record => record.key">
-                                <template #value="{ record }">
-                                  <a-input v-model:value="templateUserDataValues[record.key]" />
+                                <template #bodyCell="{ column, record }">
+                                  <template v-if="column.key === 'value'">
+                                    <a-input v-model:value="templateUserDataValues[record.key]" />
+                                  </template>
                                 </template>
                               </a-table>
                             </a-input-group>
@@ -654,8 +659,10 @@
                                                 :dataSource="userDataParams"
                                                 :pagination="false"
                                                 :rowKey="record => record.key">
-                                                <template #value="{ record }">
-                                                  <a-input v-model:value="userDataValues[record.key]" />
+                                                <template #bodyCell="{ column, record }">
+                                                  <template v-if="column.key === 'value'">
+                                                    <a-input v-model:value="userDataValues[record.key]" />
+                                                  </template>
                                                 </template>
                                               </a-table>
                                             </a-input-group>
@@ -690,6 +697,23 @@
                         @select-affinity-group-item="($event) => updateAffinityGroups($event)"
                         @handle-search-filter="($event) => handleSearchFilter('affinityGroups', $event)"/>
                     </a-form-item>
+                    <a-form-item name="nicmultiqueuenumber" ref="nicmultiqueuenumber" v-if="vm.templateid && ['KVM'].includes(hypervisor)">
+                      <template #label>
+                        <tooltip-label :title="$t('label.nicmultiqueuenumber')" :tooltip="$t('label.nicmultiqueuenumber.tooltip')"/>
+                      </template>
+                      <a-input-number
+                        style="width: 100%;"
+                        v-model:value="form.nicmultiqueuenumber" />
+                    </a-form-item>
+                    <a-form-item name="nicpackedvirtqueuesenabled" ref="nicpackedvirtqueuesenabled" v-if="vm.templateid && ['KVM'].includes(hypervisor)">
+                      <template #label>
+                        <tooltip-label :title="$t('label.nicpackedvirtqueuesenabled')" :tooltip="$t('label.nicpackedvirtqueuesenabled.tooltip')"/>
+                      </template>
+                      <a-switch
+                        v-model:checked="form.nicpackedvirtqueuesenabled"
+                        :checked="nicpackedvirtqueuesenabled"
+                        @change="val => { nicpackedvirtqueuesenabled = val }"/>
+                    </a-form-item>
                     <a-form-item name="iothreadsenabled" ref="iothreadsenabled" v-if="vm.templateid && ['KVM'].includes(hypervisor)">
                       <template #label>
                         <tooltip-label :title="$t('label.iothreadsenabled')" :tooltip="$t('label.iothreadsenabled.tooltip')"/>
@@ -709,7 +733,7 @@
                         v-model:value="form.iodriverpolicy"
                         optionFilterProp="label"
                         :filterOption="filterOption">
-                        <a-select-option v-for="iodriverpolicy in options.ioPolicyTypes" :key="iodriverpolicy.id">
+                        <a-select-option v-for="iodriverpolicy in options.ioPolicyTypes" :key="iodriverpolicy.id" :label="iodriverpolicy.description">
                           {{ iodriverpolicy.description }}
                         </a-select-option>
                       </a-select>
@@ -966,7 +990,7 @@
         {
           title: this.$t('label.value'),
           dataIndex: 'value',
-          slots: { customRender: 'value' }
+          key: 'value'
         }
       ],
       userDataValues: {},
@@ -1671,7 +1695,7 @@
       this.fetchInstaceGroups()
       this.fetchIoPolicyTypes()
       nextTick().then(() => {
-        ['name', 'keyboard', 'boottype', 'bootmode', 'userdata', 'iothreadsenabled', 'iodriverpolicy'].forEach(this.fillValue)
+        ['name', 'keyboard', 'boottype', 'bootmode', 'userdata', 'iothreadsenabled', 'iodriverpolicy', 'nicmultiqueuenumber', 'nicpackedvirtqueues'].forEach(this.fillValue)
         this.form.boottype = this.defaultBootType ? this.defaultBootType : this.options.bootTypes && this.options.bootTypes.length > 0 ? this.options.bootTypes[0].id : undefined
         this.form.bootmode = this.defaultBootMode ? this.defaultBootMode : this.options.bootModes && this.options.bootModes.length > 0 ? this.options.bootModes[0].id : undefined
         this.instanceConfig = toRaw(this.form)
@@ -1884,8 +1908,8 @@
       this.templateUserDataParams = []
 
       api('listUserData', { id: id }).then(json => {
-        const resp = json?.listuserdataresponse?.userdata || []
-        if (resp) {
+        const resp = json.listuserdataresponse.userdata || []
+        if (resp.length > 0) {
           var params = resp[0].params
           if (params) {
             var dataParams = params.split(',')
@@ -1969,6 +1993,8 @@
         deployVmData.dynamicscalingenabled = values.dynamicscalingenabled
         deployVmData.iothreadsenabled = values.iothreadsenabled
         deployVmData.iodriverpolicy = values.iodriverpolicy
+        deployVmData.nicmultiqueuenumber = values.nicmultiqueuenumber
+        deployVmData.nicpackedvirtqueuesenabled = values.nicpackedvirtqueuesenabled
         const isUserdataAllowed = !this.userdataDefaultOverridePolicy || (this.userdataDefaultOverridePolicy === 'ALLOWOVERRIDE' && this.doUserdataOverride) || (this.userdataDefaultOverridePolicy === 'APPEND' && this.doUserdataAppend)
         if (isUserdataAllowed && values.userdata && values.userdata.length > 0) {
           deployVmData.userdata = this.$toBase64AndURIEncoded(values.userdata)
diff --git a/ui/src/views/compute/DestroyVM.vue b/ui/src/views/compute/DestroyVM.vue
index de7b6da..c66c3bd 100644
--- a/ui/src/views/compute/DestroyVM.vue
+++ b/ui/src/views/compute/DestroyVM.vue
@@ -54,9 +54,9 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
-              <a-select-option v-for="volume in volumes" :key="volume.id">
+              <a-select-option v-for="volume in volumes" :key="volume.id" :label="volume.name">
                 {{ volume.name }}
               </a-select-option>
             </a-select>
@@ -102,12 +102,12 @@
                     showSearch
                     optionFilterProp="label"
                     :filterOption="(input, option) => {
-                      return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                      return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                     }"
                     :loading="listVolumes[record.id].loading"
                     :placeholder="$t('label.delete.volumes')"
                     @change="(value) => onChangeVolume(record.id, value)">
-                    <a-select-option v-for="item in listVolumes[record.id].opts" :key="item.id">
+                    <a-select-option v-for="item in listVolumes[record.id].opts" :key="item.id" :label="item.name || item.description">
                       {{ item.name || item.description }}
                     </a-select-option>
                   </a-select>
@@ -317,9 +317,9 @@
       this.selectedItemsProgress = Array.from(this.selectedItems)
       this.selectedItemsProgress = this.selectedItemsProgress.map(v => ({ ...v, status: 'InProgress' }))
       this.selectedColumns.splice(0, 0, {
+        key: 'status',
         dataIndex: 'status',
         title: this.$t('label.operation.status'),
-        scopedSlots: { customRender: 'status' },
         filters: [
           { text: 'In Progress', value: 'InProgress' },
           { text: 'Success', value: 'success' },
diff --git a/ui/src/views/compute/EditVM.vue b/ui/src/views/compute/EditVM.vue
index 1fbbd5e..3601901 100644
--- a/ui/src/views/compute/EditVM.vue
+++ b/ui/src/views/compute/EditVM.vue
@@ -52,11 +52,11 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }"
           :loading="osTypes.loading"
           v-model:value="form.ostypeid">
-          <a-select-option v-for="(ostype) in osTypes.opts" :key="ostype.id">
+          <a-select-option v-for="(ostype) in osTypes.opts" :key="ostype.id" :label="ostype.description">
             {{ ostype.description }}
           </a-select-option>
         </a-select>
@@ -103,7 +103,7 @@
           }"
           :loading="securitygroups.loading"
           v-focus="true">
-          <a-select-option v-for="securitygroup in securitygroups.opts" :key="securitygroup.id" :label="securitygroup.name">
+          <a-select-option v-for="securitygroup in securitygroups.opts" :key="securitygroup.id" :label="securitygroup.name ||  securitygroup.id">
             <div>
               {{ securitygroup.name ||  securitygroup.id }}
             </div>
diff --git a/ui/src/views/compute/InstanceSchedules.vue b/ui/src/views/compute/InstanceSchedules.vue
new file mode 100644
index 0000000..41694ad
--- /dev/null
+++ b/ui/src/views/compute/InstanceSchedules.vue
@@ -0,0 +1,461 @@
+// 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.
+
+<template>
+  <div>
+    <a-button
+      type="dashed"
+      style="width: 100%; margin-bottom: 10px"
+      @click="showAddModal"
+      :loading="loading"
+      :disabled="!('createVMSchedule' in $store.getters.apis)">
+      <template #icon><plus-outlined/></template> {{ $t('label.schedule.add') }}
+    </a-button>
+    <list-view
+      :loading="tabLoading"
+      :columns="columns"
+      :items="schedules"
+      :columnKeys="columnKeys"
+      :selectedColumns="selectedColumnKeys"
+      ref="listview"
+      @update-selected-columns="updateSelectedColumns"
+      @update-vm-schedule="updateVMSchedule"
+      @remove-vm-schedule="removeVMSchedule"
+      @refresh="this.fetchData"/>
+    <a-pagination
+      class="row-element"
+      style="margin-top: 10px"
+      size="small"
+      :current="page"
+      :pageSize="pageSize"
+      :total="totalCount"
+      :showTotal="total => `${$t('label.showing')} ${Math.min(total, 1+((page-1)*pageSize))}-${Math.min(page*pageSize, total)} ${$t('label.of')} ${total} ${$t('label.items')}`"
+      :pageSizeOptions="pageSizeOptions"
+      @change="changePage"
+      @showSizeChange="changePage"
+      showSizeChanger
+      showQuickJumper>
+      <template #buildOptionText="props">
+        <span>{{ props.value }} / {{ $t('label.page') }}</span>
+      </template>
+    </a-pagination>
+  </div>
+
+  <a-modal
+    :visible="showModal"
+    :title="$t('label.schedule')"
+    :maskClosable="false"
+    :closable="true"
+    :footer="null"
+    @cancel="closeModal">
+    <a-form
+      layout="vertical"
+      :ref="formRef"
+      :model="form"
+      :rules="rules"
+      @finish="submitForm"
+      v-ctrl-enter="submitForm">
+      <a-form-item name="description" ref="description">
+        <template #label>
+          <tooltip-label :title="$t('label.description')" :tooltip="apiParams.description.description"/>
+        </template>
+        <a-input
+          v-model:value="form.description"
+          v-focus="true" />
+      </a-form-item>
+      <a-form-item name="action" ref="action">
+        <template #label>
+          <tooltip-label :title="$t('label.action')" :tooltip="apiParams.action.description"/>
+        </template>
+        <a-radio-group
+          v-model:value="form.action"
+          button-style="solid"
+          :disabled="isEdit">
+          <a-radio-button v-for="action in actions" :key="action.id" :value="action.value">
+            {{ $t(action.label) }}
+          </a-radio-button>
+        </a-radio-group>
+      </a-form-item>
+      <a-form-item name="schedule" ref="schedule">
+        <template #label>
+          <tooltip-label :title="$t('label.schedule')" :tooltip="apiParams.schedule.description"/>
+        </template>
+        <label>{{ $t('label.advanced.mode') }}</label>
+        <a-switch
+          v-model:checked="form.useCronFormat"
+          >
+        </a-switch>
+        <br/>
+        <span v-if="!form.useCronFormat">
+        <cron-ant
+          v-model="form.schedule"
+          :periods="periods"
+          :button-props="{ type: 'primary', size: 'small', disabled: form.useCronFormat }"
+          @error="error=$event"/>
+      </span>
+      <span v-if="form.useCronFormat">
+        <label>{{ generateHumanReadableSchedule(form.schedule) }}</label>
+        <br/>
+      </span>
+        <a-input
+          :addonBefore="$t('label.cron')"
+          v-model:value="form.schedule"
+          :disabled="!form.useCronFormat"
+          v-focus="true" />
+      </a-form-item>
+      <a-form-item name="timezone" ref="timezone">
+        <template #label>
+          <tooltip-label :title="$t('label.timezone')" :tooltip="apiParams.timezone.description"/>
+        </template>
+        <a-select
+          showSearch
+          v-model:value="form.timezone"
+          optionFilterProp="label"
+          :filterOption="(input, option) => {
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+          }"
+          :loading="fetching">
+          <a-select-option v-for="opt in timeZoneMap" :key="opt.id" :label="opt.name || opt.description">
+            {{ opt.name || opt.description }}
+          </a-select-option>
+        </a-select>
+      </a-form-item>
+      <a-form-item name="startDate" ref="startDate">
+        <template #label>
+          <tooltip-label :title="$t('label.start.date.and.time')" :tooltip="apiParams.startdate.description"/>
+        </template>
+        <a-date-picker
+          v-model:value="form.startDate"
+          show-time
+          :locale="this.$i18n.locale"
+          :placeholder="$t('message.select.start.date.and.time')"/>
+      </a-form-item>
+      <a-form-item name="endDate" ref="endDate">
+        <template #label>
+          <tooltip-label :title="$t('label.end.date.and.time')" :tooltip="apiParams.enddate.description"/>
+        </template>
+        <a-date-picker
+          v-model:value="form.endDate"
+          show-time
+          :locale="this.$i18n.locale"
+          :placeholder="$t('message.select.end.date.and.time')"/>
+      </a-form-item>
+      <a-form-item name="enabled" ref="enabled">
+        <template #label>
+          <tooltip-label :title="$t('label.enabled')" :tooltip="apiParams.enabled.description"/>
+        </template>
+        <a-switch
+          v-model:checked="form.enabled">
+        </a-switch>
+      </a-form-item>
+      <div :span="24" class="action-button">
+        <a-button
+          :loading="loading"
+          @click="closeModal">
+          {{ $t('label.cancel') }}
+        </a-button>
+        <a-button
+          :loading="loading"
+          ref="submit"
+          type="primary"
+          htmlType="submit">
+          {{ $t('label.ok') }}
+        </a-button>
+      </div>
+    </a-form>
+  </a-modal>
+</template>
+
+<script>
+
+import { reactive, ref, toRaw } from 'vue'
+import { api } from '@/api'
+import ListView from '@/components/view/ListView'
+import Status from '@/components/widgets/Status'
+import TooltipLabel from '@/components/widgets/TooltipLabel'
+import { mixinForm } from '@/utils/mixin'
+import { timeZone } from '@/utils/timezone'
+import debounce from 'lodash/debounce'
+import cronstrue from 'cronstrue/i18n'
+import moment from 'moment-timezone'
+
+export default {
+  name: 'InstanceSchedules',
+  mixins: [mixinForm],
+  components: {
+    Status,
+    ListView,
+    TooltipLabel
+  },
+  props: {
+    virtualmachine: {
+      type: Object,
+      required: true
+    },
+    loading: {
+      type: Boolean,
+      required: true
+    }
+  },
+  data () {
+    this.fetchTimeZone = debounce(this.fetchTimeZone, 800)
+    return {
+      tabLoading: false,
+      columnKeys: ['action', 'enabled', 'description', 'schedule', 'timezone', 'startdate', 'enddate', 'created', 'vmScheduleActions'],
+      selectedColumnKeys: [],
+      columns: [],
+      schedules: [],
+      timeZoneMap: [],
+      actions: [
+        { value: 'START', label: 'label.start' },
+        { value: 'STOP', label: 'label.stop' },
+        { value: 'REBOOT', label: 'label.reboot' },
+        { value: 'FORCE_STOP', label: 'label.force.stop' },
+        { value: 'FORCE_REBOOT', label: 'label.force.reboot' }
+      ],
+      periods: [
+        { id: 'year', value: ['month', 'day', 'dayOfWeek', 'hour', 'minute'] },
+        { id: 'month', value: ['day', 'dayOfWeek', 'hour', 'minute'] },
+        { id: 'week', value: ['dayOfWeek', 'hour', 'minute'] },
+        { id: 'day', value: ['hour', 'minute'] }
+      ],
+      page: 1,
+      pageSize: 20,
+      totalCount: 0,
+      showModal: false,
+      isSubmitted: false,
+      isEdit: false,
+      error: '',
+      pattern: 'YYYY-MM-DD HH:mm:ss'
+    }
+  },
+  beforeCreate () {
+    this.apiParams = this.$getApiParams('createVMSchedule')
+  },
+  computed: {
+    pageSizeOptions () {
+      var sizes = [20, 50, 100, 200, this.$store.getters.defaultListViewPageSize]
+      if (this.device !== 'desktop') {
+        sizes.unshift(10)
+      }
+      return [...new Set(sizes)].sort(function (a, b) {
+        return a - b
+      }).map(String)
+    }
+  },
+  created () {
+    this.selectedColumnKeys = this.columnKeys
+    this.updateColumns()
+    this.pageSize = this.pageSizeOptions[0] * 1
+    this.initForm()
+    this.fetchData()
+    this.fetchTimeZone()
+  },
+  watch: {
+    virtualmachine: {
+      handler () {
+        this.fetchSchedules()
+      }
+    }
+  },
+  methods: {
+    initForm () {
+      this.formRef = ref()
+      this.form = reactive({
+        action: 'START',
+        schedule: '* * * * *',
+        description: '',
+        timezone: 'UTC',
+        startDate: '',
+        endDate: '',
+        enabled: true,
+        useCronFormat: false
+      })
+      this.rules = reactive({
+        schedule: [{ type: 'string', required: true, message: this.$t('message.error.required.input') }],
+        action: [{ type: 'string', required: true, message: this.$t('message.error.required.input') }],
+        timezone: [{ required: true, message: `${this.$t('message.error.select')}` }],
+        startDate: [{ required: false, message: `${this.$t('message.error.select')}` }],
+        endDate: [{ required: false, message: `${this.$t('message.error.select')}` }]
+      })
+    },
+    createVMSchedule (schedule) {
+      this.resetForm()
+      this.showAddModal()
+    },
+    removeVMSchedule (schedule) {
+      api('deleteVMSchedule', {
+        id: schedule.id,
+        virtualmachineid: this.virtualmachine.id
+      }).then(() => {
+        if (this.totalCount - 1 === this.pageSize * (this.page - 1)) {
+          this.page = this.page - 1 > 0 ? this.page - 1 : 1
+        }
+        const message = `${this.$t('label.removing')} ${schedule.description}`
+        this.$message.success(message)
+      }).catch(error => {
+        console.error(error)
+        this.$message.error(this.$t('message.error.remove.vm.schedule'))
+        this.$notification.error({
+          message: this.$t('label.error'),
+          description: this.$t('message.error.remove.vm.schedule')
+        })
+      }).finally(() => {
+        this.fetchData()
+      })
+    },
+    updateVMSchedule (schedule) {
+      this.resetForm()
+      this.isEdit = true
+      Object.assign(this.form, schedule)
+      // Some weird issue when we directly pass in the moment with tz object
+      this.form.startDate = moment(moment(schedule.startdate).tz(schedule.timezone).format(this.pattern))
+      this.form.endDate = schedule.enddate ? moment(moment(schedule.enddate).tz(schedule.timezone).format(this.pattern)) : ''
+      this.showAddModal()
+    },
+    showAddModal () {
+      this.showModal = true
+    },
+    submitForm () {
+      if (this.isSubmitted) return
+      this.isSubmitted = true
+      this.formRef.value.validate().then(() => {
+        const formRaw = toRaw(this.form)
+        const values = this.handleRemoveFields(formRaw)
+        var params = {
+          description: values.description,
+          schedule: values.schedule,
+          timezone: values.timezone,
+          action: values.action,
+          virtualmachineid: this.virtualmachine.id,
+          enabled: values.enabled,
+          startdate: (values.startDate) ? values.startDate.format(this.pattern) : null,
+          enddate: (values.endDate) ? values.endDate.format(this.pattern) : null
+        }
+        let command = null
+        if (this.form.id === null || this.form.id === undefined) {
+          command = 'createVMSchedule'
+        } else {
+          params.id = this.form.id
+          command = 'updateVMSchedule'
+        }
+
+        api(command, params).then(response => {
+          this.$notification.success({
+            message: this.$t('label.schedule'),
+            description: this.$t('message.success.config.vm.schedule')
+          })
+          this.isSubmitted = false
+          this.fetchData()
+          this.closeModal()
+        }).catch(error => {
+          this.$notifyError(error)
+          this.isSubmitted = false
+        })
+      }).catch(error => {
+        this.$notifyError(error)
+        if (error.errorFields !== undefined) {
+          this.formRef.value.scrollToField(error.errorFields[0].name)
+        }
+      }).finally(() => {
+        this.isSubmitted = false
+      })
+    },
+    resetForm () {
+      this.isEdit = false
+      if (this.formRef.value) {
+        this.formRef.value.resetFields()
+      }
+    },
+    fetchTimeZone (value) {
+      this.timeZoneMap = []
+      this.fetching = true
+
+      timeZone(value).then(json => {
+        this.timeZoneMap = json
+        this.fetching = false
+      })
+    },
+    closeModal () {
+      this.resetForm()
+      this.initForm()
+      this.showModal = false
+    },
+    fetchData () {
+      this.fetchSchedules()
+    },
+    fetchSchedules () {
+      this.schedules = []
+      if (!this.virtualmachine.id) {
+        return
+      }
+      const params = {
+        page: this.page,
+        pagesize: this.pageSize,
+        virtualmachineid: this.virtualmachine.id,
+        listall: true
+      }
+      this.tabLoading = true
+      api('listVMSchedule', params).then(json => {
+        this.schedules = []
+        this.totalCount = json?.listvmscheduleresponse?.count || 0
+        this.schedules = json?.listvmscheduleresponse?.vmschedule || []
+        this.tabLoading = false
+      })
+    },
+    changePage (page, pageSize) {
+      this.page = page
+      this.pageSize = pageSize
+      this.fetchData()
+    },
+    updateSelectedColumns (key) {
+      if (this.selectedColumnKeys.includes(key)) {
+        this.selectedColumnKeys = this.selectedColumnKeys.filter(x => x !== key)
+      } else {
+        this.selectedColumnKeys.push(key)
+      }
+      this.updateColumns()
+    },
+    generateHumanReadableSchedule (schedule) {
+      return cronstrue.toString(schedule, { locale: this.$i18n.locale, throwExceptionOnParseError: false })
+    },
+    updateColumns () {
+      this.columns = []
+      for (var columnKey of this.columnKeys) {
+        if (!this.selectedColumnKeys.includes(columnKey)) continue
+        this.columns.push({
+          key: columnKey,
+          // If columnKey is 'enabled', then title is 'state'
+          // If columnKey is 'startdate', then the title is `start.date.and.time`
+          // else title is columnKey
+          title: columnKey === 'enabled'
+            ? this.$t('label.state')
+            : columnKey === 'startdate'
+              ? this.$t('label.start.date.and.time')
+              : columnKey === 'enddate'
+                ? this.$t('label.end.date.and.time')
+                : this.$t('label.' + String(columnKey).toLowerCase()),
+          dataIndex: columnKey
+        })
+      }
+      if (this.columns.length > 0) {
+        this.columns[this.columns.length - 1].customFilterDropdown = true
+      }
+    }
+  }
+}
+</script>
diff --git a/ui/src/views/compute/InstanceTab.vue b/ui/src/views/compute/InstanceTab.vue
index 2b1572b..927fa3d 100644
--- a/ui/src/views/compute/InstanceTab.vue
+++ b/ui/src/views/compute/InstanceTab.vue
@@ -116,6 +116,11 @@
           :routerlinks="(record) => { return { name: '/securitygroups/' + record.id } }"
           :showSearch="false"/>
       </a-tab-pane>
+      <a-tab-pane :tab="$t('label.schedules')" key="schedules" v-if="'listVMSchedule' in $store.getters.apis">
+        <InstanceSchedules
+          :virtualmachine="vm"
+          :loading="loading"/>
+      </a-tab-pane>
       <a-tab-pane :tab="$t('label.settings')" key="settings">
         <DetailSettings :resource="dataResource" :loading="loading" />
       </a-tab-pane>
@@ -192,9 +197,9 @@
             :loading="listIps.loading"
             v-focus="editNicResource.type==='Shared'"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }">
             <a-select-option v-for="ip in listIps.opts" :key="ip.ipaddress">
               {{ ip.ipaddress }}
@@ -235,9 +240,9 @@
             :loading="listIps.loading"
             v-focus="editNicResource.type==='Shared'"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }">
             <a-select-option v-for="ip in listIps.opts" :key="ip.ipaddress">
               {{ ip.ipaddress }}
@@ -290,6 +295,7 @@
 import EventsTab from '@/components/view/EventsTab'
 import DetailSettings from '@/components/view/DetailSettings'
 import NicsTable from '@/views/network/NicsTable'
+import InstanceSchedules from '@/views/compute/InstanceSchedules.vue'
 import ListResourceTable from '@/components/view/ListResourceTable'
 import TooltipButton from '@/components/widgets/TooltipButton'
 import ResourceIcon from '@/components/view/ResourceIcon'
@@ -305,6 +311,7 @@
     EventsTab,
     DetailSettings,
     NicsTable,
+    InstanceSchedules,
     ListResourceTable,
     TooltipButton,
     ResourceIcon,
diff --git a/ui/src/views/compute/KubernetesServiceTab.vue b/ui/src/views/compute/KubernetesServiceTab.vue
index 96a9958..b3556cb6 100644
--- a/ui/src/views/compute/KubernetesServiceTab.vue
+++ b/ui/src/views/compute/KubernetesServiceTab.vue
@@ -25,7 +25,7 @@
       <a-tab-pane :tab="$t('label.details')" key="details">
         <DetailsTab :resource="resource" :loading="loading" />
       </a-tab-pane>
-      <a-tab-pane :tab="$t('label.access')" key="access">
+      <a-tab-pane v-if="resource.clustertype == 'CloudManaged'" :tab="$t('label.access')" key="access">
         <a-card :title="$t('label.kubeconfig.cluster')" :loading="versionLoading">
           <div v-if="clusterConfig !== ''">
             <a-textarea :value="clusterConfig" :rows="5" readonly />
@@ -106,36 +106,37 @@
           :rowKey="item => item.id"
           :pagination="false"
         >
-          <template #name="{ text, record }" :name="text">
-            <router-link :to="{ path: '/vm/' + record.id }">{{ record.name }}</router-link>
-          </template>
-          <template #state="{ text }">
-            <status :text="text ? text : ''" displayText />
-          </template>
-          <template #port="{ text, record, index }" :name="text" :record="record">
-            {{ cksSshStartingPort + index }}
-          </template>
-          <template #action="{record}">
-            <a-tooltip placement="bottom" >
-              <template #title>
-                {{ $t('label.action.delete.node') }}
-              </template>
-              <a-popconfirm
-                :title="$t('message.action.delete.node')"
-                @confirm="deleteNode(record)"
-                :okText="$t('label.yes')"
-                :cancelText="$t('label.no')"
-                :disabled="!['Created', 'Running'].includes(resource.state) || resource.autoscalingenabled"
-              >
-                <a-button
-                  danger
-                  type="primary"
-                  shape="circle"
-                  :disabled="!['Created', 'Running'].includes(resource.state) || resource.autoscalingenabled">
-                  <template #icon><delete-outlined /></template>
-                </a-button>
-              </a-popconfirm>
-            </a-tooltip>
+          <template #bodyCell="{ column, text, record, index }">
+            <template v-if="column.key === 'name'" :name="text">
+              <router-link :to="{ path: '/vm/' + record.id }">{{ record.name }}</router-link>
+            </template>
+            <template v-if="column.key === 'state'">
+              <status :text="text ? text : ''" displayText />
+            </template>
+            <template v-if="column.key === 'port'" :name="text" :record="record">
+              {{ cksSshStartingPort + index }}
+            </template>
+            <template v-if="column.key === 'actions'">
+              <a-tooltip placement="bottom" >
+                <template #title>
+                  {{ $t('label.action.delete.node') }}
+                </template>
+                <a-popconfirm
+                  :title="$t('message.action.delete.node')"
+                  @confirm="deleteNode(record)"
+                  :okText="$t('label.yes')"
+                  :cancelText="$t('label.no')"
+                  :disabled="!['Created', 'Running'].includes(resource.state) || resource.autoscalingenabled"
+                >
+                  <a-button
+                    type="danger"
+                    shape="circle"
+                    :disabled="!['Created', 'Running'].includes(resource.state) || resource.autoscalingenabled">
+                    <template #icon><delete-outlined /></template>
+                  </a-button>
+                </a-popconfirm>
+              </a-tooltip>
+            </template>
           </template>
         </a-table>
       </a-tab-pane>
@@ -214,14 +215,14 @@
   created () {
     this.vmColumns = [
       {
+        key: 'name',
         title: this.$t('label.name'),
-        dataIndex: 'name',
-        slots: { customRender: 'name' }
+        dataIndex: 'name'
       },
       {
+        key: 'state',
         title: this.$t('label.state'),
-        dataIndex: 'state',
-        slots: { customRender: 'state' }
+        dataIndex: 'state'
       },
       {
         title: this.$t('label.instancename'),
@@ -232,9 +233,9 @@
         dataIndex: 'ipaddress'
       },
       {
+        key: 'port',
         title: this.$t('label.ssh.port'),
-        dataIndex: 'port',
-        slots: { customRender: 'port' }
+        dataIndex: 'port'
       },
       {
         title: this.$t('label.zonename'),
@@ -244,6 +245,9 @@
     if (!isAdmin()) {
       this.vmColumns = this.vmColumns.filter(x => x.dataIndex !== 'instancename')
     }
+    if (this.resource.clustertype === 'ExternalManaged') {
+      this.vmColumns = this.vmColumns.filter(x => x.dataIndex !== 'port')
+    }
     this.handleFetchData()
     const self = this
     window.addEventListener('popstate', function () {
@@ -271,9 +275,9 @@
   mounted () {
     if (this.$store.getters.apis.scaleKubernetesCluster.params.filter(x => x.name === 'nodeids').length > 0) {
       this.vmColumns.push({
-        title: this.$t('label.action'),
-        dataIndex: 'action',
-        slots: { customRender: 'action' }
+        key: 'actions',
+        title: this.$t('label.actions'),
+        dataIndex: 'actions'
       })
     }
     this.handleFetchData()
diff --git a/ui/src/views/compute/MigrateWizard.vue b/ui/src/views/compute/MigrateWizard.vue
index 9687138..8aad50d 100644
--- a/ui/src/views/compute/MigrateWizard.vue
+++ b/ui/src/views/compute/MigrateWizard.vue
@@ -37,45 +37,47 @@
       :dataSource="hosts"
       :pagination="false"
       :rowKey="record => record.id">
-      <template #name="{ record }">
-        {{ record.name }}
-        <a-tooltip v-if="record.name === $t('label.auto.assign')" :title="$t('message.migrate.instance.host.auto.assign')" placement="top">
-          <info-circle-outlined class="table-tooltip-icon" />
-        </a-tooltip>
-      </template>
-      <template #suitability="{ record }">
-        <check-circle-two-tone
-          class="host-item__suitability-icon"
-          twoToneColor="#52c41a"
-          v-if="record.suitableformigration" />
-        <close-circle-two-tone
-          class="host-item__suitability-icon"
-          twoToneColor="#f5222d"
-          v-else />
-      </template>
-      <template #memused="{ record }">
-        <span v-if="record.memoryused">
-          {{ $bytesToHumanReadableSize(record.memoryused) }}
-        </span>
-      </template>
-      <template #memoryallocatedpercentage="{ record }">
-        {{ record.memoryallocatedpercentage }}
-      </template>
-      <template #cluster="{ record }">
-        {{ record.clustername }}
-      </template>
-      <template #pod="{ record }">
-        {{ record.podname }}
-      </template>
-      <template #requiresstoragemigration="{ record }">
-        {{ record.requiresStorageMotion ? $t('label.yes') : $t('label.no') }}
-      </template>
-      <template #select="{record}">
-        <a-radio
-          class="host-item__radio"
-          @click="handleSelectedHostChange(record)"
-          :checked="record.id === selectedHost.id"
-          :disabled="!record.suitableformigration"></a-radio>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'name'">
+          {{ record.name }}
+          <a-tooltip v-if="record.name === $t('label.auto.assign')" :title="$t('message.migrate.instance.host.auto.assign')" placement="top">
+            <info-circle-outlined class="table-tooltip-icon" />
+          </a-tooltip>
+        </template>
+        <template v-if="column.key === 'suitability'">
+          <check-circle-two-tone
+            class="host-item__suitability-icon"
+            twoToneColor="#52c41a"
+            v-if="record.suitableformigration" />
+          <close-circle-two-tone
+            class="host-item__suitability-icon"
+            twoToneColor="#f5222d"
+            v-else />
+        </template>
+        <template v-if="column.key === 'memused'">
+          <span v-if="record.memoryused">
+            {{ $bytesToHumanReadableSize(record.memoryused) }}
+          </span>
+        </template>
+        <template v-if="column.key === 'memoryallocatedpercentage'">
+          {{ record.memoryallocatedpercentage }}
+        </template>
+        <template v-if="column.key === 'cluster'">
+          {{ record.clustername }}
+        </template>
+        <template v-if="column.key === 'pod'">
+          {{ record.podname }}
+        </template>
+        <template v-if="column.key === 'requiresstoragemigration'">
+          {{ record.requiresStorageMotion ? $t('label.yes') : $t('label.no') }}
+        </template>
+        <template v-if="column.key === 'select'">
+          <a-radio
+            class="host-item__radio"
+            @click="handleSelectedHostChange(record)"
+            :checked="record.id === selectedHost.id"
+            :disabled="!record.suitableformigration"></a-radio>
+        </template>
       </template>
     </a-table>
     <a-pagination
@@ -149,44 +151,45 @@
       pageSize: 10,
       columns: [
         {
-          title: this.$t('label.hostid'),
-          slots: { customRender: 'name' }
+          key: 'name',
+          title: this.$t('label.hostid')
         },
         {
-          title: this.$t('label.suitability'),
-          slots: { customRender: 'suitability' }
+          key: 'suitability',
+          title: this.$t('label.suitability')
         },
         {
           title: this.$t('label.cpuused'),
           dataIndex: 'cpuused'
         },
         {
-          title: this.$t('label.memoryallocated'),
-          slots: { customRender: 'memoryallocatedpercentage' }
+          key: 'memoryallocatedpercentage',
+          title: this.$t('label.memoryallocated')
         },
         {
-          title: this.$t('label.memused'),
-          slots: { customRender: 'memused' }
+          key: 'memused',
+          title: this.$t('label.memused')
         },
         {
-          title: this.$t('label.cluster'),
-          slots: { customRender: 'cluster' }
+          key: 'cluster',
+          title: this.$t('label.cluster')
         },
         {
-          title: this.$t('label.pod'),
-          slots: { customRender: 'pod' }
+          key: 'pod',
+          title: this.$t('label.pod')
         },
         {
-          title: this.$t('label.storage.migration.required'),
-          slots: { customRender: 'requiresstoragemigration' }
+          key: 'requiresstoragemigration',
+          title: this.$t('label.storage.migration.required')
         },
         {
-          title: this.$t('label.select'),
-          slots: { customRender: 'select' }
+          key: 'select',
+          title: this.$t('label.select')
         }
       ],
       migrateWithStorage: false,
-      volumeToPoolSelection: []
+      volumeToPoolSelection: [],
+      volumes: []
     }
   },
   created () {
@@ -246,6 +249,7 @@
     handleSelectedHostChange (host) {
       if (host.id === -1) {
         this.migrateWithStorage = false
+        this.fetchVolumes()
       }
       this.selectedHost = host
       this.selectedVolumeForStoragePoolSelection = {}
@@ -257,6 +261,31 @@
     handleVolumeToPoolChange (volumeToPool) {
       this.volumeToPoolSelection = volumeToPool
     },
+    fetchVolumes () {
+      this.loading = true
+      this.volumes = []
+      api('listVolumes', {
+        listAll: true,
+        virtualmachineid: this.resource.id
+      }).then(response => {
+        this.volumes = response.listvolumesresponse.volume
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    requiresStorageMigration () {
+      if (this.selectedHost.requiresStorageMotion || this.volumeToPoolSelection.length > 0) {
+        return true
+      }
+      if (this.selectedHost.id === -1 && this.volumes && this.volumes.length > 0) {
+        for (var volume of this.volumes) {
+          if (volume.storagetype === 'local') {
+            return true
+          }
+        }
+      }
+      return false
+    },
     handleKeyboardSubmit () {
       if (this.selectedHost.id) {
         this.submitForm()
@@ -269,7 +298,7 @@
       if (this.loading) return
       this.loading = true
       const migrateApi = this.isUserVm
-        ? (this.selectedHost.requiresStorageMotion || this.volumeToPoolSelection.length > 0)
+        ? this.requiresStorageMigration()
           ? 'migrateVirtualMachineWithVolume'
           : 'migrateVirtualMachine'
         : 'migrateSystemVm'
diff --git a/ui/src/views/compute/RegisterUserData.vue b/ui/src/views/compute/RegisterUserData.vue
index a8e5577..a1322a1 100644
--- a/ui/src/views/compute/RegisterUserData.vue
+++ b/ui/src/views/compute/RegisterUserData.vue
@@ -51,9 +51,9 @@
             mode="tags"
             v-model:value="form.params"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children?.[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :placeholder="apiParams.params.description">
             <a-select-option v-for="opt in params" :key="opt">
@@ -71,12 +71,15 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
               :loading="domainLoading"
             :placeholder="apiParams.domainid.description"
             @change="val => { handleDomainChanged(domains[val]) }">
-            <a-select-option v-for="(opt, optIndex) in domains" :key="optIndex">
+            <a-select-option
+              v-for="(opt, optIndex) in domains"
+              :key="optIndex"
+              :label="opt.path || opt.name || opt.description || ''">
               {{ opt.path || opt.name || opt.description }}
             </a-select-option>
           </a-select>
diff --git a/ui/src/views/compute/ResetSshKeyPair.vue b/ui/src/views/compute/ResetSshKeyPair.vue
index 12c0e6c..7babb95 100644
--- a/ui/src/views/compute/ResetSshKeyPair.vue
+++ b/ui/src/views/compute/ResetSshKeyPair.vue
@@ -42,8 +42,10 @@
           @handle-search-filter="handleTableChange"
           style="overflow-y: auto" >
 
-          <template #account><user-outlined /> {{ $t('label.account') }}</template>
-          <template #domain><block-outlined /> {{ $t('label.domain') }}</template>
+          <template #headerCell="{ column }">
+            <template v-if="column.key === 'account'"><user-outlined /> {{ $t('label.account') }}</template>
+            <template v-if="column.key === 'domain'"><block-outlined /> {{ $t('label.domain') }}</template>
+          </template>
 
         </a-table>
       </div>
@@ -81,13 +83,13 @@
           width: '40%'
         },
         {
+          key: 'account',
           dataIndex: 'account',
-          slots: { title: 'account' },
           width: '30%'
         },
         {
+          key: 'domain',
           dataIndex: 'domain',
-          slots: { title: 'domain' },
           width: '30%'
         }
       ],
diff --git a/ui/src/views/compute/ResetUserData.vue b/ui/src/views/compute/ResetUserData.vue
index 46561f1..7be1dad 100644
--- a/ui/src/views/compute/ResetUserData.vue
+++ b/ui/src/views/compute/ResetUserData.vue
@@ -41,8 +41,10 @@
               :dataSource="templateUserDataParams"
               :pagination="false"
               :rowKey="record => record.key">
-              <template #value="{ record }">
-                <a-input v-model:value="templateUserDataValues[record.key]" />
+              <template #bodyCell="{ column, record }">
+                <template v-if="column.key === 'value'">
+                  <a-input v-model:value="templateUserDataValues[record.key]" />
+                </template>
               </template>
             </a-table>
           </a-input-group>
@@ -87,8 +89,10 @@
                               :dataSource="userDataParams"
                               :pagination="false"
                               :rowKey="record => record.key">
-                              <template #value="{ record }">
-                                <a-input v-model:value="userDataValues[record.key]" />
+                              <template #bodyCell="{ column, record }">
+                                <template v-if="column.key === 'value'">
+                                  <a-input v-model:value="userDataValues[record.key]" />
+                                </template>
                               </template>
                             </a-table>
                           </a-input-group>
@@ -152,12 +156,12 @@
         },
         {
           dataIndex: 'account',
-          slots: { title: 'account' },
+          title: this.$t('account'),
           width: '30%'
         },
         {
           dataIndex: 'domain',
-          slots: { title: 'domain' },
+          title: this.$t('domain'),
           width: '30%'
         }
       ],
@@ -188,7 +192,7 @@
         {
           title: this.$t('label.value'),
           dataIndex: 'value',
-          slots: { customRender: 'value' }
+          key: 'value'
         }
       ],
       userDataValues: {},
@@ -301,7 +305,7 @@
       this.userDataParams = []
       api('listUserData', { id: id }).then(json => {
         const resp = json?.listuserdataresponse?.userdata || []
-        if (resp) {
+        if (resp.length > 0) {
           var params = resp[0].params
           if (params) {
             var dataParams = params.split(',')
diff --git a/ui/src/views/compute/ScaleKubernetesCluster.vue b/ui/src/views/compute/ScaleKubernetesCluster.vue
index f9af2ef..8d73ac8 100644
--- a/ui/src/views/compute/ScaleKubernetesCluster.vue
+++ b/ui/src/views/compute/ScaleKubernetesCluster.vue
@@ -38,11 +38,11 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="serviceOfferingLoading"
             :placeholder="apiParams.serviceofferingid.description">
-            <a-select-option v-for="(opt, optIndex) in serviceOfferings" :key="optIndex">
+            <a-select-option v-for="(opt, optIndex) in serviceOfferings" :key="optIndex" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
diff --git a/ui/src/views/compute/StartVirtualMachine.vue b/ui/src/views/compute/StartVirtualMachine.vue
index 4440153..7438ebc 100644
--- a/ui/src/views/compute/StartVirtualMachine.vue
+++ b/ui/src/views/compute/StartVirtualMachine.vue
@@ -38,13 +38,13 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="podsLoading"
               :placeholder="apiParams.podid.description"
               @change="handlePodChange"
               v-focus="$store.getters.userInfo.roletype === 'Admin'">
-              <a-select-option v-for="pod in pods" :key="pod.id">
+              <a-select-option v-for="pod in pods" :key="pod.id" :label="pod.name">
                 {{ pod.name }}
               </a-select-option>
             </a-select>
@@ -59,12 +59,12 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="clustersLoading"
               :placeholder="apiParams.clusterid.description"
               @change="handleClusterChange">
-              <a-select-option v-for="cluster in clusters" :key="cluster.id">
+              <a-select-option v-for="cluster in clusters" :key="cluster.id" :label="cluster.name">
                 {{ cluster.name }}
               </a-select-option>
             </a-select>
@@ -79,11 +79,11 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="hostsLoading"
               :placeholder="apiParams.hostid.description">
-              <a-select-option v-for="host in hosts" :key="host.id">
+              <a-select-option v-for="host in hosts" :key="host.id" :label="host.name">
                 {{ host.name }}
               </a-select-option>
             </a-select>
diff --git a/ui/src/views/compute/UpgradeKubernetesCluster.vue b/ui/src/views/compute/UpgradeKubernetesCluster.vue
index 02d4ffe..22cfb0f 100644
--- a/ui/src/views/compute/UpgradeKubernetesCluster.vue
+++ b/ui/src/views/compute/UpgradeKubernetesCluster.vue
@@ -38,12 +38,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="kubernetesVersionLoading"
             :placeholder="apiParams.kubernetesversionid.description"
             v-focus="true" >
-            <a-select-option v-for="(opt, optIndex) in this.kubernetesVersions" :key="optIndex">
+            <a-select-option v-for="(opt, optIndex) in this.kubernetesVersions" :key="optIndex" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
diff --git a/ui/src/views/compute/backup/BackupSchedule.vue b/ui/src/views/compute/backup/BackupSchedule.vue
index 914a112..26c655a 100644
--- a/ui/src/views/compute/backup/BackupSchedule.vue
+++ b/ui/src/views/compute/backup/BackupSchedule.vue
@@ -24,49 +24,51 @@
       :rowKey="record => record.virtualmachineid"
       :pagination="false"
       :loading="loading">
-      <template #icon="{ text, record }" :name="text">
-        <label class="interval-icon">
-          <span v-if="record.intervaltype==='HOURLY'">
-            <clock-circle-outlined />
+      <template #bodyCell="{ column, text, record }">
+        <template v-if="column.key === 'icon'" :name="text">
+          <label class="interval-icon">
+            <span v-if="record.intervaltype==='HOURLY'">
+              <clock-circle-outlined />
+            </span>
+            <span class="custom-icon icon-daily" v-else-if="record.intervaltype==='DAILY'">
+              <calendar-outlined />
+            </span>
+            <span class="custom-icon icon-weekly" v-else-if="record.intervaltype==='WEEKLY'">
+              <calendar-outlined />
+            </span>
+            <span class="custom-icon icon-monthly" v-else-if="record.intervaltype==='MONTHLY'">
+              <calendar-outlined />
+            </span>
+          </label>
+        </template>
+        <template v-if="column.key === 'time'" :name="text">
+          <label class="interval-content">
+            <span v-if="record.intervaltype==='HOURLY'">{{ record.schedule + ' ' + $t('label.min.past.hour') }}</span>
+            <span v-else>{{ record.schedule.split(':')[1] + ':' + record.schedule.split(':')[0] }}</span>
+          </label>
+        </template>
+        <template v-if="column.key === 'interval'" :name="text">
+          <span v-if="record.intervaltype==='WEEKLY'">
+            {{ `${$t('label.every')} ${$t(listDayOfWeek[record.schedule.split(':')[2] - 1])}` }}
           </span>
-          <span class="custom-icon icon-daily" v-else-if="record.intervaltype==='DAILY'">
-            <calendar-outlined />
+          <span v-else-if="record.intervaltype==='MONTHLY'">
+            {{ `${$t('label.day')} ${record.schedule.split(':')[2]} ${$t('label.of.month')}` }}
           </span>
-          <span class="custom-icon icon-weekly" v-else-if="record.intervaltype==='WEEKLY'">
-            <calendar-outlined />
-          </span>
-          <span class="custom-icon icon-monthly" v-else-if="record.intervaltype==='MONTHLY'">
-            <calendar-outlined />
-          </span>
-        </label>
-      </template>
-      <template #time="{ text, record }" :name="text">
-        <label class="interval-content">
-          <span v-if="record.intervaltype==='HOURLY'">{{ record.schedule + ' ' + $t('label.min.past.hour') }}</span>
-          <span v-else>{{ record.schedule.split(':')[1] + ':' + record.schedule.split(':')[0] }}</span>
-        </label>
-      </template>
-      <template #interval="{ text, record }" :name="text">
-        <span v-if="record.intervaltype==='WEEKLY'">
-          {{ `${$t('label.every')} ${$t(listDayOfWeek[record.schedule.split(':')[2] - 1])}` }}
-        </span>
-        <span v-else-if="record.intervaltype==='MONTHLY'">
-          {{ `${$t('label.day')} ${record.schedule.split(':')[2]} ${$t('label.of.month')}` }}
-        </span>
-      </template>
-      <template #timezone="{ text, record }" :name="text">
-        <label>{{ getTimeZone(record.timezone) }}</label>
-      </template>
-      <template #action="{ text, record }" class="account-button-action" :name="text">
-        <tooltip-button
-          tooltipPlacement="top"
-          :tooltip="$t('label.delete')"
-          type="primary"
-          :danger="true"
-          icon="close-outlined"
-          size="small"
-          :loading="actionLoading"
-          @onClick="handleClickDelete(record)"/>
+        </template>
+        <template v-if="column.key === 'timezone'" :name="text">
+          <label>{{ getTimeZone(record.timezone) }}</label>
+        </template>
+        <template v-if="column.key === 'actions'" class="account-button-action" :name="text">
+          <tooltip-button
+            tooltipPlacement="top"
+            :tooltip="$t('label.delete')"
+            type="primary"
+            :danger="true"
+            icon="close-outlined"
+            size="small"
+            :loading="actionLoading"
+            @onClick="handleClickDelete(record)"/>
+        </template>
       </template>
     </a-table>
   </div>
@@ -107,31 +109,31 @@
     columns () {
       return [
         {
+          key: 'icon',
           title: '',
           dataIndex: 'icon',
-          width: 30,
-          slots: { customRender: 'icon' }
+          width: 30
         },
         {
+          key: 'time',
           title: this.$t('label.time'),
-          dataIndex: 'schedule',
-          slots: { customRender: 'time' }
+          dataIndex: 'schedule'
         },
         {
+          key: 'interval',
           title: '',
-          dataIndex: 'interval',
-          slots: { customRender: 'interval' }
+          dataIndex: 'interval'
         },
         {
+          key: 'timezone',
           title: this.$t('label.timezone'),
-          dataIndex: 'timezone',
-          slots: { customRender: 'timezone' }
+          dataIndex: 'timezone'
         },
         {
-          title: this.$t('label.action'),
-          dataIndex: 'action',
-          width: 80,
-          slots: { customRender: 'action' }
+          key: 'actions',
+          title: this.$t('label.actions'),
+          dataIndex: 'actions',
+          width: 80
         }
       ]
     }
diff --git a/ui/src/views/compute/backup/FormSchedule.vue b/ui/src/views/compute/backup/FormSchedule.vue
index d1512623..3b8db9d 100644
--- a/ui/src/views/compute/backup/FormSchedule.vue
+++ b/ui/src/views/compute/backup/FormSchedule.vue
@@ -70,7 +70,8 @@
                 <a-time-picker
                   use12Hours
                   format="h:mm A"
-                  v-model:value="form.timeSelect" />
+                  v-model:value="form.timeSelect"
+                  style="width: 100%;" />
               </a-form-item>
             </a-col>
             <a-col :md="24" :lg="12" v-if="form.intervaltype==='weekly'">
@@ -80,9 +81,9 @@
                   showSearch
                   optionFilterProp="label"
                   :filterOption="(input, option) => {
-                    return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                   }" >
-                  <a-select-option v-for="(opt, optIndex) in dayOfWeek" :key="optIndex">
+                  <a-select-option v-for="(opt, optIndex) in dayOfWeek" :key="optIndex" :label="opt.name || opt.description">
                     {{ opt.name || opt.description }}
                   </a-select-option>
                 </a-select>
@@ -95,9 +96,9 @@
                   showSearch
                   optionFilterProp="label"
                   :filterOption="(input, option) => {
-                    return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                   }">
-                  <a-select-option v-for="opt in dayOfMonth" :key="opt.name">
+                  <a-select-option v-for="opt in dayOfMonth" :key="opt.name" :label="opt.name || opt.description">
                     {{ opt.name }}
                   </a-select-option>
                 </a-select>
@@ -110,10 +111,10 @@
                   v-model:value="form.timezone"
                   optionFilterProp="label"
                   :filterOption="(input, option) => {
-                    return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                   }"
                   :loading="fetching">
-                  <a-select-option v-for="opt in timeZoneMap" :key="opt.id">
+                  <a-select-option v-for="opt in timeZoneMap" :key="opt.id" :label="opt.name || opt.description">
                     {{ opt.name || opt.description }}
                   </a-select-option>
                 </a-select>
diff --git a/ui/src/views/compute/wizard/ComputeOfferingSelection.vue b/ui/src/views/compute/wizard/ComputeOfferingSelection.vue
index fb1ab66..aa97f36 100644
--- a/ui/src/views/compute/wizard/ComputeOfferingSelection.vue
+++ b/ui/src/views/compute/wizard/ComputeOfferingSelection.vue
@@ -32,8 +32,10 @@
       size="middle"
       :scroll="{ y: 225 }"
     >
-      <template #cpuTitle><appstore-outlined /> {{ $t('label.cpu') }}</template>
-      <template #ramTitle><bulb-outlined /> {{ $t('label.memory') }}</template>
+      <template #headerCell="{ column }">
+        <template v-if="column.key === 'cpu'"><appstore-outlined /> {{ $t('label.cpu') }}</template>
+        <template v-if="column.key === 'ram'"><bulb-outlined /> {{ $t('label.memory') }}</template>
+      </template>
     </a-table>
 
     <div style="display: block; text-align: right;">
@@ -109,18 +111,19 @@
       filter: '',
       columns: [
         {
+          key: 'name',
           dataIndex: 'name',
           title: this.$t('label.serviceofferingid'),
           width: '40%'
         },
         {
+          key: 'cpu',
           dataIndex: 'cpu',
-          slots: { title: 'cpuTitle' },
           width: '30%'
         },
         {
+          key: 'ram',
           dataIndex: 'ram',
-          slots: { title: 'ramTitle' },
           width: '30%'
         }
       ],
diff --git a/ui/src/views/compute/wizard/DiskOfferingSelection.vue b/ui/src/views/compute/wizard/DiskOfferingSelection.vue
index 6262795..ee103aa 100644
--- a/ui/src/views/compute/wizard/DiskOfferingSelection.vue
+++ b/ui/src/views/compute/wizard/DiskOfferingSelection.vue
@@ -32,18 +32,23 @@
       size="middle"
       :scroll="{ y: 225 }"
     >
-      <template #diskSizeTitle><hdd-outlined /> {{ $t('label.disksize') }}</template>
-      <template #iopsTitle><rocket-outlined /> {{ $t('label.minmaxiops') }}</template>
-      <template #diskSize="{ record }">
-        <div v-if="record.isCustomized">{{ $t('label.iscustomized') }}</div>
-        <div v-else-if="record.diskSize">{{ record.diskSize }} GB</div>
-        <div v-else>-</div>
+      <template #headerCell="{ column }">
+        <template v-if="column.key === 'diskSize'"><hdd-outlined /> {{ $t('label.disksize') }}</template>
+        <template v-if="column.key === 'iops'"><rocket-outlined /> {{ $t('label.minmaxiops') }}</template>
       </template>
-      <template #iops="{ record }">
-        <span v-if="record.miniops && record.maxiops">{{ record.miniops }} - {{ record.maxiops }}</span>
-        <span v-else-if="record.miniops && !record.maxiops">{{ record.miniops }}</span>
-        <span v-else-if="!record.miniops && record.maxiops">{{ record.maxiops }}</span>
-        <span v-else>-</span>
+
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'diskSize'">
+          <div v-if="record.isCustomized">{{ $t('label.iscustomized') }}</div>
+          <div v-else-if="record.diskSize">{{ record.diskSize }} GB</div>
+          <div v-else>-</div>
+        </template>
+        <template v-if="column.key === 'iops'">
+          <span v-if="record.miniops && record.maxiops">{{ record.miniops }} - {{ record.maxiops }}</span>
+          <span v-else-if="record.miniops && !record.maxiops">{{ record.miniops }}</span>
+          <span v-else-if="!record.miniops && record.maxiops">{{ record.maxiops }}</span>
+          <span v-else>-</span>
+        </template>
       </template>
     </a-table>
 
@@ -108,19 +113,20 @@
       filter: '',
       columns: [
         {
+          key: 'name',
           dataIndex: 'name',
           title: this.$t('label.diskoffering'),
           width: '40%'
         },
         {
+          key: 'diskSize',
           dataIndex: 'disksize',
-          width: '30%',
-          slots: { customRender: 'diskSize', title: 'diskSizeTitle' }
+          width: '30%'
         },
         {
+          key: 'iops',
           dataIndex: 'iops',
-          width: '30%',
-          slots: { customRender: 'iops', title: 'iopsTitle' }
+          width: '30%'
         }
       ],
       selectedRowKeys: ['0'],
diff --git a/ui/src/views/compute/wizard/LoadBalancerSelection.vue b/ui/src/views/compute/wizard/LoadBalancerSelection.vue
index f29b229..e2ffb99 100644
--- a/ui/src/views/compute/wizard/LoadBalancerSelection.vue
+++ b/ui/src/views/compute/wizard/LoadBalancerSelection.vue
@@ -32,9 +32,9 @@
       :rowSelection="rowSelection"
       size="middle"
       :scroll="{ y: 225 }">
-      <template #publicip><environment-outlined /> {{ $t('label.publicip') }}</template>
-      <template #publicport>{{ $t('label.publicport') }}</template>
-      <template #privateport>{{ $t('label.privateport') }}</template>
+      <template #headerCell="{ column }">
+        <template v-if="column.key === 'publicip'"><environment-outlined /> {{ $t('label.publicip') }}</template>
+      </template>
     </a-table>
 
     <div style="display: block; text-align: right;">
@@ -113,6 +113,7 @@
           width: '40%'
         },
         {
+          key: 'publicip',
           title: this.$t('label.publicip'),
           dataIndex: 'publicip'
         },
diff --git a/ui/src/views/compute/wizard/MultiDiskSelection.vue b/ui/src/views/compute/wizard/MultiDiskSelection.vue
index 55c30c3..5dd8466 100644
--- a/ui/src/views/compute/wizard/MultiDiskSelection.vue
+++ b/ui/src/views/compute/wizard/MultiDiskSelection.vue
@@ -26,44 +26,46 @@
       :rowSelection="rowSelection"
       :scroll="{ y: 225 }" >
 
-      <template #name="{ record }">
-        <span>{{ record.displaytext || record.name }}</span>
-        <div v-if="record.meta">
-          <div v-for="meta in record.meta" :key="meta.key">
-            <a-tag style="margin-top: 5px" :key="meta.key">{{ meta.key + ': ' + meta.value }}</a-tag>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'name'">
+          <span>{{ record.displaytext || record.name }}</span>
+          <div v-if="record.meta">
+            <div v-for="meta in record.meta" :key="meta.key">
+              <a-tag style="margin-top: 5px" :key="meta.key">{{ meta.key + ': ' + meta.value }}</a-tag>
+            </div>
           </div>
-        </div>
-      </template>
-      <template #offering="{ record }">
-        <span
-          style="width: 50%"
-          v-if="validOfferings[record.id] && validOfferings[record.id].length > 0">
-          <check-box-select-pair
-            v-if="selectedCustomDiskOffering!=null"
-            layout="vertical"
-            :resourceKey="record.id"
-            :selectOptions="validOfferings[record.id]"
-            :checkBoxLabel="autoSelectLabel"
-            :defaultCheckBoxValue="true"
-            :reversed="true"
-            @handle-checkselectpair-change="updateOfferingCheckPairSelect" />
-          <a-select
-            v-else
-            @change="updateOfferingSelect($event, record.id)"
-            :defaultValue="validOfferings[record.id][0].id"
-            showSearch
-            optionFilterProp="label"
-            :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-            }" >
-            <a-select-option v-for="offering in validOfferings[record.id]" :key="offering.id">
-              {{ offering.displaytext }}
-            </a-select-option>
-          </a-select>
-        </span>
-        <span v-else style="width: 50%">
-          {{ $t('label.no.matching.offering') }}
-        </span>
+        </template>
+        <template v-if="column.key === 'offering'">
+          <span
+            style="width: 50%"
+            v-if="validOfferings[record.id] && validOfferings[record.id].length > 0">
+            <check-box-select-pair
+              v-if="selectedCustomDiskOffering!=null"
+              layout="vertical"
+              :resourceKey="record.id"
+              :selectOptions="validOfferings[record.id]"
+              :checkBoxLabel="autoSelectLabel"
+              :defaultCheckBoxValue="true"
+              :reversed="true"
+              @handle-checkselectpair-change="updateOfferingCheckPairSelect" />
+            <a-select
+              v-else
+              @change="updateOfferingSelect($event, record.id)"
+              :defaultValue="validOfferings[record.id][0].id"
+              showSearch
+              optionFilterProp="label"
+              :filterOption="(input, option) => {
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              }" >
+              <a-select-option v-for="offering in validOfferings[record.id]" :key="offering.id" :label="offering.displaytext">
+                {{ offering.displaytext }}
+              </a-select-option>
+            </a-select>
+          </span>
+          <span v-else style="width: 50%">
+            {{ $t('label.no.matching.offering') }}
+          </span>
+        </template>
       </template>
     </a-table>
   </div>
@@ -108,14 +110,14 @@
     return {
       columns: [
         {
+          key: 'name',
           dataIndex: 'name',
-          title: this.$t('label.data.disk'),
-          slots: { customRender: 'name' }
+          title: this.$t('label.data.disk')
         },
         {
+          key: 'offering',
           dataIndex: 'offering',
-          title: this.$t('label.data.disk.offering'),
-          slots: { customRender: 'offering' }
+          title: this.$t('label.data.disk.offering')
         }
       ],
       loading: false,
diff --git a/ui/src/views/compute/wizard/MultiNetworkSelection.vue b/ui/src/views/compute/wizard/MultiNetworkSelection.vue
index bdbd23e..f2397d5 100644
--- a/ui/src/views/compute/wizard/MultiNetworkSelection.vue
+++ b/ui/src/views/compute/wizard/MultiNetworkSelection.vue
@@ -26,41 +26,46 @@
       :rowSelection="rowSelection"
       :scroll="{ y: 225 }" >
 
-      <template #name="{record}">
-        <span>{{ record.displaytext || record.name }}</span>
-        <div v-if="record.meta">
-          <div v-for="meta in record.meta" :key="meta.key">
-            <a-tag style="margin-top: 5px" :key="meta.key">{{ meta.key + ': ' + meta.value }}</a-tag>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'name'">
+          <span>{{ record.displaytext || record.name }}</span>
+          <div v-if="record.meta">
+            <div v-for="meta in record.meta" :key="meta.key">
+              <a-tag style="margin-top: 5px" :key="meta.key">{{ meta.key + ': ' + meta.value }}</a-tag>
+            </div>
           </div>
-        </div>
-      </template>
-      <template #network="{record}">
-        <a-select
-          v-if="validNetworks[record.id] && validNetworks[record.id].length > 0"
-          :defaultValue="validNetworks[record.id][0].id"
-          @change="val => handleNetworkChange(record, val)"
-          showSearch
-          optionFilterProp="label"
-          :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-          }" >
-          <a-select-option v-for="network in validNetworks[record.id]" :key="network.id">
-            {{ network.displaytext + (network.broadcasturi ? ' (' + network.broadcasturi + ')' : '') }}
-          </a-select-option>
-        </a-select>
-        <span v-else>
-          {{ $t('label.no.matching.network') }}
-        </span>
-      </template>
-      <template #ipaddress="{record}">
-        <check-box-input-pair
-          layout="vertical"
-          :resourceKey="record.id"
-          :checkBoxLabel="$t('label.auto.assign.random.ip')"
-          :defaultCheckBoxValue="true"
-          :reversed="true"
-          :visible="(indexNum > 0 && ipAddressesEnabled[record.id])"
-          @handle-checkinputpair-change="setIpAddress" />
+        </template>
+        <template v-if="column.key === 'network'">
+          <a-select
+            v-if="validNetworks[record.id] && validNetworks[record.id].length > 0"
+            :defaultValue="validNetworks[record.id][0].id"
+            @change="val => handleNetworkChange(record, val)"
+            showSearch
+            optionFilterProp="label"
+            :filterOption="(input, option) => {
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            }" >
+            <a-select-option
+              v-for="network in validNetworks[record.id]"
+              :key="network.id"
+              :label="network.displaytext + (network.broadcasturi ? ' (' + network.broadcasturi + ')' : '')">
+              {{ network.displaytext + (network.broadcasturi ? ' (' + network.broadcasturi + ')' : '') }}
+            </a-select-option>
+          </a-select>
+          <span v-else>
+            {{ $t('label.no.matching.network') }}
+          </span>
+        </template>
+        <template v-if="column.key === 'ipaddress'">
+          <check-box-input-pair
+            layout="vertical"
+            :resourceKey="record.id"
+            :checkBoxLabel="$t('label.auto.assign.random.ip')"
+            :defaultCheckBoxValue="true"
+            :reversed="true"
+            :visible="(indexNum > 0 && ipAddressesEnabled[record.id])"
+            @handle-checkinputpair-change="setIpAddress" />
+        </template>
       </template>
     </a-table>
   </div>
@@ -102,19 +107,19 @@
     return {
       columns: [
         {
+          key: 'name',
           dataIndex: 'name',
-          title: this.$t('label.nic'),
-          slots: { customRender: 'name' }
+          title: this.$t('label.nic')
         },
         {
+          key: 'network',
           dataIndex: 'network',
-          title: this.$t('label.network'),
-          slots: { customRender: 'network' }
+          title: this.$t('label.network')
         },
         {
+          key: 'ipaddress',
           dataIndex: 'ipaddress',
-          title: this.$t('label.ipaddress'),
-          slots: { customRender: 'ipaddress' }
+          title: this.$t('label.ipaddress')
         }
       ],
       loading: false,
diff --git a/ui/src/views/compute/wizard/NetworkConfiguration.vue b/ui/src/views/compute/wizard/NetworkConfiguration.vue
index a31f7f4..4165276 100644
--- a/ui/src/views/compute/wizard/NetworkConfiguration.vue
+++ b/ui/src/views/compute/wizard/NetworkConfiguration.vue
@@ -29,42 +29,46 @@
       :rowKey="record => record.id"
       size="middle"
       :scroll="{ y: 225 }">
-      <template #name="{ text, record }">
-        <div>{{ text }}</div>
-        <small v-if="record.type!=='L2'">{{ $t('label.cidr') + ': ' + record.cidr }}</small>
-      </template>
-      <template #ipAddress="{ record }" v-if="!this.autoscale">
-        <a-form-item
-          style="display: block"
-          v-if="record.type !== 'L2'"
-          :name="'ipAddress' + record.id">
-          <a-input
-            style="width: 150px;"
-            v-model:value="form['ipAddress' + record.id]"
-            :placeholder="record.cidr"
-            @change="($event) => updateNetworkData('ipAddress', record.id, $event.target.value)">
-            <template #suffix>
-              <a-tooltip :title="getIpRangeDescription(record)">
-                <info-circle-outlined style="color: rgba(0,0,0,.45)" />
-              </a-tooltip>
-            </template>
-          </a-input>
-        </a-form-item>
-      </template>
-      <template #macAddress="{ record }" v-if="!this.autoscale">
-        <a-form-item style="display: block" :name="'macAddress' + record.id">
-          <a-input
-            style="width: 150px;"
-            :placeholder="$t('label.macaddress')"
-            v-model:value="form[`macAddress` + record.id]"
-            @change="($event) => updateNetworkData('macAddress', record.id, $event.target.value)">
-            <template #suffix>
-              <a-tooltip :title="$t('label.macaddress.example')">
-                <info-circle-outlined style="color: rgba(0,0,0,.45)" />
-              </a-tooltip>
-            </template>
-          </a-input>
-        </a-form-item>
+      <template #bodyCell="{ column, text, record }">
+        <template v-if="column.key === 'name'">
+          <div>{{ text }}</div>
+          <small v-if="record.type!=='L2'">{{ $t('label.cidr') + ': ' + record.cidr }}</small>
+        </template>
+        <template  v-if="!this.autoscale">
+          <template v-if="column.key === 'ipAddress'">
+            <a-form-item
+              style="display: block"
+              v-if="record.type !== 'L2'"
+              :name="'ipAddress' + record.id">
+              <a-input
+                style="width: 150px;"
+                v-model:value="form['ipAddress' + record.id]"
+                :placeholder="record.cidr"
+                @change="($event) => updateNetworkData('ipAddress', record.id, $event.target.value)">
+                <template #suffix>
+                  <a-tooltip :title="getIpRangeDescription(record)">
+                    <info-circle-outlined style="color: rgba(0,0,0,.45)" />
+                  </a-tooltip>
+                </template>
+              </a-input>
+            </a-form-item>
+          </template>
+          <template v-if="column.key === 'macAddress'">
+            <a-form-item style="display: block" :name="'macAddress' + record.id">
+              <a-input
+                style="width: 150px;"
+                :placeholder="$t('label.macaddress')"
+                v-model:value="form[`macAddress` + record.id]"
+                @change="($event) => updateNetworkData('macAddress', record.id, $event.target.value)">
+                <template #suffix>
+                  <a-tooltip :title="$t('label.macaddress.example')">
+                    <info-circle-outlined style="color: rgba(0,0,0,.45)" />
+                  </a-tooltip>
+                </template>
+              </a-input>
+            </a-form-item>
+          </template>
+        </template>
       </template>
     </a-table>
   </a-form>
@@ -97,22 +101,22 @@
       networks: [],
       columns: [
         {
+          key: 'name',
           dataIndex: 'name',
           title: this.$t('label.defaultnetwork'),
-          width: '30%',
-          slots: { customRender: 'name' }
+          width: '30%'
         },
         {
+          key: 'ipAddress',
           dataIndex: 'ip',
           title: this.$t('label.ip'),
-          width: '30%',
-          slots: { customRender: 'ipAddress' }
+          width: '30%'
         },
         {
+          key: 'macAddress',
           dataIndex: 'mac',
           title: this.$t('label.macaddress'),
-          width: '30%',
-          slots: { customRender: 'macAddress' }
+          width: '30%'
         }
       ],
       selectedRowKeys: [],
diff --git a/ui/src/views/compute/wizard/NetworkSelection.vue b/ui/src/views/compute/wizard/NetworkSelection.vue
index 96a6d28..66a932c 100644
--- a/ui/src/views/compute/wizard/NetworkSelection.vue
+++ b/ui/src/views/compute/wizard/NetworkSelection.vue
@@ -34,14 +34,16 @@
       :rowSelection="rowSelection"
       :scroll="{ y: 225 }"
     >
-      <template #name="{record}">
-        <resource-icon
-          v-if="record.icon"
-          :image="record.icon.base64image"
-          size="1x"
-          style="margin-right: 5px"/>
-        <apartment-outlined v-else style="margin-right: 5px" />
-        {{ record.name }}
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'name'">
+          <resource-icon
+            v-if="record.icon"
+            :image="record.icon.base64image"
+            size="1x"
+            style="margin-right: 5px"/>
+          <apartment-outlined v-else style="margin-right: 5px" />
+          {{ record.name }}
+        </template>
       </template>
       <template #expandedRowRender="{ record }">
         <a-list
@@ -173,29 +175,35 @@
           }
         })
       }
+      const vpcCol = {
+        key: 'vpcName',
+        dataIndex: 'vpcName',
+        title: this.$t('label.vpc'),
+        width: '30%'
+      }
+      if (vpcFilter.length > 0) {
+        vpcCol.filters = vpcFilter
+        vpcCol.filteredValue = _.get(this.filteredInfo, 'id')
+        vpcCol.onFilter = (value, record) => {
+          return record.vpcid === value
+        }
+      }
       return [
         {
+          key: 'name',
           dataIndex: 'name',
           title: this.$t('label.networks'),
-          slots: { customRender: 'name' },
           width: '40%'
         },
         {
+          key: 'type',
           dataIndex: 'type',
           title: this.$t('label.guestiptype'),
           width: '15%'
         },
+        vpcCol,
         {
-          dataIndex: 'vpcName',
-          title: this.$t('label.vpc'),
-          width: '20%',
-          filters: vpcFilter,
-          filteredValue: _.get(this.filteredInfo, 'id'),
-          onFilter: (value, record) => {
-            return record.vpcid === value
-          }
-        },
-        {
+          key: 'supportsvmautoscaling',
           dataIndex: 'supportsvmautoscaling',
           title: this.$t('label.supportsvmautoscaling'),
           width: '25%'
diff --git a/ui/src/views/compute/wizard/SshKeyPairSelection.vue b/ui/src/views/compute/wizard/SshKeyPairSelection.vue
index 848c1a2..f6dda72 100644
--- a/ui/src/views/compute/wizard/SshKeyPairSelection.vue
+++ b/ui/src/views/compute/wizard/SshKeyPairSelection.vue
@@ -31,8 +31,10 @@
       :pagination="false"
       size="middle"
       :scroll="{ y: 225 }">
-      <template #account><user-outlined /> {{ $t('label.account') }}</template>
-      <template #domain><block-outlined /> {{ $t('label.domain') }}</template>
+      <template #headerCell="{ column }">
+        <template v-if="column.key === 'account'"><user-outlined /> {{ $t('label.account') }}</template>
+        <template v-if="column.key === 'domain'"><block-outlined /> {{ $t('label.domain') }}</template>
+      </template>
     </a-table>
     <div style="display: block; text-align: right;">
       <a-pagination
@@ -87,18 +89,19 @@
       filter: '',
       columns: [
         {
+          key: 'name',
           dataIndex: 'name',
           title: this.$t('label.sshkeypairs'),
           width: '40%'
         },
         {
+          key: 'account',
           dataIndex: 'account',
-          slots: { title: 'account' },
           width: '30%'
         },
         {
+          key: 'domain',
           dataIndex: 'domain',
-          slots: { title: 'domain' },
           width: '30%'
         }
       ],
diff --git a/ui/src/views/compute/wizard/UserDataSelection.vue b/ui/src/views/compute/wizard/UserDataSelection.vue
index 4dfc14e..87e0bb3 100644
--- a/ui/src/views/compute/wizard/UserDataSelection.vue
+++ b/ui/src/views/compute/wizard/UserDataSelection.vue
@@ -32,8 +32,10 @@
       size="middle"
       :scroll="{ y: 225 }"
     >
-      <template #account><user-outlined /> {{ $t('label.account') }}</template>
-      <template #domain><block-outlined /> {{ $t('label.domain') }}</template>
+      <template #headerCell="{ column }">
+        <template v-if="column.key === 'account'"><user-outlined /> {{ $t('label.account') }}</template>
+        <template v-if="column.key === 'domain'"><block-outlined /> {{ $t('label.domain') }}</template>
+      </template>
     </a-table>
   </div>
 </template>
@@ -81,13 +83,13 @@
           width: '40%'
         },
         {
+          key: 'account',
           dataIndex: 'account',
-          slots: { title: 'account' },
           width: '30%'
         },
         {
+          key: 'domain',
           dataIndex: 'domain',
-          slots: { title: 'domain' },
           width: '30%'
         }
       ],
diff --git a/ui/src/views/dashboard/CapacityDashboard.vue b/ui/src/views/dashboard/CapacityDashboard.vue
index 1dc67a7..c634500 100644
--- a/ui/src/views/dashboard/CapacityDashboard.vue
+++ b/ui/src/views/dashboard/CapacityDashboard.vue
@@ -280,7 +280,7 @@
       this.listCapacity(this.zoneSelected)
     },
     filterZone (input, option) {
-      return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
     }
   }
 }
diff --git a/ui/src/views/dashboard/SetupTwoFaAtLogin.vue b/ui/src/views/dashboard/SetupTwoFaAtLogin.vue
index a710afb..2300a7a 100644
--- a/ui/src/views/dashboard/SetupTwoFaAtLogin.vue
+++ b/ui/src/views/dashboard/SetupTwoFaAtLogin.vue
@@ -38,10 +38,6 @@
           <a-form-item v-ctrl-enter="submitPin" ref="selectedProvider" name="selectedProvider">
              <a-select
               v-model:value="form.selectedProvider"
-              optionFilterProp="label"
-              :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-              }"
               @change="val => { handleSelectChange(val) }">
               <a-select-option
                 v-for="(opt) in providers"
diff --git a/ui/src/views/dashboard/UsageDashboard.vue b/ui/src/views/dashboard/UsageDashboard.vue
index 4264a90..28a892a 100644
--- a/ui/src/views/dashboard/UsageDashboard.vue
+++ b/ui/src/views/dashboard/UsageDashboard.vue
@@ -169,7 +169,7 @@
   methods: {
     fetchData () {
       this.stats = [{}, {}, {}, {}, {}, {}]
-      api('listVirtualMachines', { state: 'Running', listall: true }).then(json => {
+      api('listVirtualMachines', { state: 'Running', listall: true, retrieveonlyresourcecount: true }).then(json => {
         var count = 0
         if (json && json.listvirtualmachinesresponse) {
           count = json.listvirtualmachinesresponse.count
@@ -177,7 +177,7 @@
         var tileColor = this.$config.theme['@dashboard-tile-runningvms-bg'] || '#dfe9cc'
         this.stats.splice(0, 1, { name: this.$t('label.running.vms'), count: count, icon: 'desktop-outlined', bgcolor: tileColor, path: '/vm', query: { state: 'running', filter: 'running' } })
       })
-      api('listVirtualMachines', { state: 'Stopped', listall: true }).then(json => {
+      api('listVirtualMachines', { state: 'Stopped', listall: true, retrieveonlyresourcecount: true }).then(json => {
         var count = 0
         if (json && json.listvirtualmachinesresponse) {
           count = json.listvirtualmachinesresponse.count
@@ -185,7 +185,7 @@
         var tileColor = this.$config.theme['@dashboard-tile-stoppedvms-bg'] || '#edcbce'
         this.stats.splice(1, 1, { name: this.$t('label.stopped.vms'), count: count, icon: 'poweroff-outlined', bgcolor: tileColor, path: '/vm', query: { state: 'stopped', filter: 'stopped' } })
       })
-      api('listVirtualMachines', { listall: true }).then(json => {
+      api('listVirtualMachines', { listall: true, retrieveonlyresourcecount: true }).then(json => {
         var count = 0
         if (json && json.listvirtualmachinesresponse) {
           count = json.listvirtualmachinesresponse.count
@@ -193,7 +193,7 @@
         var tileColor = this.$config.theme['@dashboard-tile-totalvms-bg'] || '#ffffff'
         this.stats.splice(2, 1, { name: this.$t('label.total.vms'), count: count, icon: 'number-outlined', bgcolor: tileColor, path: '/vm' })
       })
-      api('listVolumes', { listall: true }).then(json => {
+      api('listVolumes', { listall: true, retrieveonlyresourcecount: true }).then(json => {
         var count = 0
         if (json && json.listvolumesresponse) {
           count = json.listvolumesresponse.count
@@ -201,7 +201,7 @@
         var tileColor = this.$config.theme['@dashboard-tile-totalvolumes-bg'] || '#ffffff'
         this.stats.splice(3, 1, { name: this.$t('label.total.volume'), count: count, icon: 'database-outlined', bgcolor: tileColor, path: '/volume' })
       })
-      api('listNetworks', { listall: true }).then(json => {
+      api('listNetworks', { listall: true, retrieveonlyresourcecount: true }).then(json => {
         var count = 0
         if (json && json.listnetworksresponse) {
           count = json.listnetworksresponse.count
@@ -209,7 +209,7 @@
         var tileColor = this.$config.theme['@dashboard-tile-totalnetworks-bg'] || '#ffffff'
         this.stats.splice(4, 1, { name: this.$t('label.total.network'), count: count, icon: 'apartment-outlined', bgcolor: tileColor, path: '/guestnetwork' })
       })
-      api('listPublicIpAddresses', { listall: true }).then(json => {
+      api('listPublicIpAddresses', { listall: true, retrieveonlyresourcecount: true }).then(json => {
         var count = 0
         if (json && json.listpublicipaddressesresponse) {
           count = json.listpublicipaddressesresponse.count
diff --git a/ui/src/views/iam/AddAccount.vue b/ui/src/views/iam/AddAccount.vue
index 88bf848..467a4a2 100644
--- a/ui/src/views/iam/AddAccount.vue
+++ b/ui/src/views/iam/AddAccount.vue
@@ -37,9 +37,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }">
-            <a-select-option v-for="role in roles" :key="role.id">
+            <a-select-option v-for="role in roles" :key="role.id" :label="role.name + ' (' + role.type + ')'">
               {{ role.name + ' (' + role.type + ')' }}
             </a-select-option>
           </a-select>
@@ -143,9 +143,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }">
-            <a-select-option v-for="opt in timeZoneMap" :key="opt.id">
+            <a-select-option v-for="opt in timeZoneMap" :key="opt.id" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -173,9 +173,9 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }">
-              <a-select-option v-for="idp in idps" :key="idp.id">
+              <a-select-option v-for="idp in idps" :key="idp.id" :label="idp.orgName">
                 {{ idp.orgName }}
               </a-select-option>
             </a-select>
diff --git a/ui/src/views/iam/AddLdapAccount.vue b/ui/src/views/iam/AddLdapAccount.vue
index ecf8cb0..fadb538 100644
--- a/ui/src/views/iam/AddLdapAccount.vue
+++ b/ui/src/views/iam/AddLdapAccount.vue
@@ -59,9 +59,9 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }">
-                <a-select-option v-for="opt in filters" :key="opt.id" >
+                <a-select-option v-for="opt in filters" :key="opt.id" :label="opt.name">
                   {{ opt.name }}
                 </a-select-option>
               </a-select>
@@ -73,9 +73,9 @@
                 :loading="domainLoading"
                 @change="fetchListLdapUsers($event)"
                 showSearch
-                optionFilterProp="label"
+                optionFilterProp="value"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }" >
                 <a-select-option v-for="opt in listDomains" :key="opt.name">
                   {{ opt.name }}
@@ -94,9 +94,9 @@
                 :placeholder="apiParams.roleid.description"
                 :loading="roleLoading"
                 showSearch
-                optionFilterProp="label"
+                optionFilterProp="value"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }">
                 <a-select-option v-for="opt in listRoles" :key="opt.name">
                   {{ opt.name }}
@@ -111,9 +111,9 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }">
-                <a-select-option v-for="opt in timeZoneMap" :key="opt.id">
+                <a-select-option v-for="opt in timeZoneMap" :key="opt.id" :label="opt.name || opt.description">
                   {{ opt.name || opt.description }}
                 </a-select-option>
               </a-select>
@@ -142,9 +142,9 @@
                   showSearch
                   optionFilterProp="label"
                   :filterOption="(input, option) => {
-                    return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                   }">
-                  <a-select-option v-for="(idp, idx) in listIdps" :key="idx">
+                  <a-select-option v-for="(idp, idx) in listIdps" :key="idx" :label="idp.orgName">
                     {{ idp.orgName }}
                   </a-select-option>
                 </a-select>
@@ -212,26 +212,26 @@
     this.listIdps = []
     this.columns = [
       {
+        key: 'name',
         title: this.$t('label.name'),
         dataIndex: 'name',
-        width: 120,
-        slots: { customRender: 'name' }
+        width: 120
       },
       {
+        key: 'username',
         title: this.$t('label.username'),
         dataIndex: 'username',
-        width: 120,
-        slots: { customRender: 'username' }
+        width: 120
       },
       {
+        key: 'email',
         title: this.$t('label.email'),
-        dataIndex: 'email',
-        slots: { customRender: 'email' }
+        dataIndex: 'email'
       },
       {
+        key: 'conflictingusersource',
         title: this.$t('label.user.conflict'),
-        dataIndex: 'conflictingusersource',
-        slots: { customRender: 'conflictingusersource' }
+        dataIndex: 'conflictingusersource'
       }
     ]
     this.filters = [
@@ -487,9 +487,9 @@
     },
     handleEntityRule () {
       if (this.form.samlEnable) {
-        this.rules.push({
-          samlEntity: [{ required: true, message: `${this.$t('message.error.select')}` }]
-        })
+        this.rules.samlEntity = [{ required: true, message: `${this.$t('message.error.select')}` }]
+      } else {
+        delete this.rules.samlEntity
       }
     }
   }
diff --git a/ui/src/views/iam/AddUser.vue b/ui/src/views/iam/AddUser.vue
index c4b1a12..49bca32 100644
--- a/ui/src/views/iam/AddUser.vue
+++ b/ui/src/views/iam/AddUser.vue
@@ -140,9 +140,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option v-for="opt in timeZoneMap" :key="opt.id">
+            <a-select-option v-for="opt in timeZoneMap" :key="opt.id" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -161,9 +161,9 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
-              <a-select-option v-for="idp in idps" :key="idp.id">
+              <a-select-option v-for="idp in idps" :key="idp.id" :label="idp.orgName">
                 {{ idp.orgName }}
               </a-select-option>
             </a-select>
diff --git a/ui/src/views/iam/ConfigureSamlSsoAuth.vue b/ui/src/views/iam/ConfigureSamlSsoAuth.vue
index 4f2e540..15e2b78 100644
--- a/ui/src/views/iam/ConfigureSamlSsoAuth.vue
+++ b/ui/src/views/iam/ConfigureSamlSsoAuth.vue
@@ -36,9 +36,9 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
-          <a-select-option v-for="idp in idps" :key="idp.id">
+          <a-select-option v-for="idp in idps" :key="idp.id" :label="idp.orgName">
             {{ idp.orgName }}
           </a-select-option>
         </a-select>
diff --git a/ui/src/views/iam/CreateRole.vue b/ui/src/views/iam/CreateRole.vue
index ea3d380..d0ec8be 100644
--- a/ui/src/views/iam/CreateRole.vue
+++ b/ui/src/views/iam/CreateRole.vue
@@ -67,9 +67,9 @@
             v-model:value="form.type"
             :placeholder="apiParams.type.description"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option v-for="role in defaultRoles" :key="role">
               {{ role }}
@@ -87,12 +87,13 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option
               v-for="role in roles"
               :value="role.id"
-              :key="role.id">
+              :key="role.id"
+              :label="role.name">
               {{ role.name }}
             </a-select-option>
           </a-select>
diff --git a/ui/src/views/iam/DomainActionForm.vue b/ui/src/views/iam/DomainActionForm.vue
index fe55c51..4d7c727 100644
--- a/ui/src/views/iam/DomainActionForm.vue
+++ b/ui/src/views/iam/DomainActionForm.vue
@@ -65,9 +65,9 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }" >
-                <a-select-option v-for="(opt, optIndex) in action.mapping[field.name].options" :key="optIndex">
+                <a-select-option v-for="(opt, optIndex) in action.mapping[field.name].options" :key="optIndex" :label="opt">
                   {{ opt }}
                 </a-select-option>
               </a-select>
@@ -79,11 +79,14 @@
                 :loading="field.loading"
                 :placeholder="field.description"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }"
                 v-focus="fieldIndex === firstIndex"
               >
-                <a-select-option v-for="(opt, optIndex) in field.opts" :key="optIndex">
+                <a-select-option
+                  v-for="(opt, optIndex) in field.opts"
+                  :key="optIndex"
+                  :label="opt.name || opt.description || opt.traffictype || opt.publicip">
                   {{ opt.name || opt.description || opt.traffictype || opt.publicip }}
                 </a-select-option>
               </a-select>
@@ -97,9 +100,12 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }" >
-                <a-select-option v-for="(opt, optIndex) in field.opts" :key="optIndex">
+                <a-select-option
+                  v-for="(opt, optIndex) in field.opts"
+                  :key="optIndex"
+                  :label="opt.name && opt.type ? opt.name + ' (' + opt.type + ')' : opt.name || opt.description">
                   {{ opt.name && opt.type ? opt.name + ' (' + opt.type + ')' : opt.name || opt.description }}
                 </a-select-option>
               </a-select>
diff --git a/ui/src/views/iam/DomainView.vue b/ui/src/views/iam/DomainView.vue
index 2b15d8b..997f900 100644
--- a/ui/src/views/iam/DomainView.vue
+++ b/ui/src/views/iam/DomainView.vue
@@ -56,13 +56,13 @@
         :loading="loading"
         :tabs="$route.meta.tabs" />
       <tree-view
-        v-else
         :key="treeViewKey"
         :treeData="treeData"
         :treeSelected="treeSelected"
         :treeStore="domainStore"
         :loading="loading"
         :tabs="$route.meta.tabs"
+        :treeDeletedKey="treeDeletedKey"
         @change-resource="changeResource"
         @change-tree-store="changeDomainStore"/>
     </div>
@@ -109,7 +109,8 @@
       showAction: false,
       action: {},
       dataView: false,
-      domainStore: {}
+      domainStore: {},
+      treeDeletedKey: null
     }
   },
   computed: {
@@ -194,6 +195,7 @@
       })
     },
     execAction (action) {
+      this.treeDeletedKey = action.api === 'deleteDomain' ? this.resource.key : null
       this.actionData = []
       this.action = action
       this.action.params = store.getters.apis[this.action.api].params
@@ -286,9 +288,8 @@
 
       rootItem[0].title = rootItem[0].title ? rootItem[0].title : rootItem[0].name
       rootItem[0].key = rootItem[0].id ? rootItem[0].id : 0
-      rootItem[0].slots = {
-        icon: 'leaf'
-      }
+      rootItem[0].resourceIcon = rootItem[0].icon || {}
+      delete rootItem[0].icon
 
       if (!rootItem[0].haschild) {
         rootItem[0].isLeaf = true
diff --git a/ui/src/views/iam/EditUser.vue b/ui/src/views/iam/EditUser.vue
index 9940b20..e082fd1 100644
--- a/ui/src/views/iam/EditUser.vue
+++ b/ui/src/views/iam/EditUser.vue
@@ -74,9 +74,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option v-for="opt in timeZoneMap" :key="opt.id">
+            <a-select-option v-for="opt in timeZoneMap" :key="opt.id" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
diff --git a/ui/src/views/iam/ImportRole.vue b/ui/src/views/iam/ImportRole.vue
index a4811fa..9919127 100644
--- a/ui/src/views/iam/ImportRole.vue
+++ b/ui/src/views/iam/ImportRole.vue
@@ -31,7 +31,7 @@
           <a-upload-dragger
             :multiple="false"
             :fileList="fileList"
-            :remove="handleRemove"
+            @remove="handleRemove"
             :beforeUpload="beforeUpload"
             @change="handleChange"
             v-model:value="form.file">
@@ -70,9 +70,9 @@
             v-model:value="form.type"
             :placeholder="apiParams.type.description"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option v-for="role in defaultRoles" :key="role">
               {{ role }}
diff --git a/ui/src/views/iam/PermissionEditable.vue b/ui/src/views/iam/PermissionEditable.vue
index 10add51..22007d8 100644
--- a/ui/src/views/iam/PermissionEditable.vue
+++ b/ui/src/views/iam/PermissionEditable.vue
@@ -23,10 +23,10 @@
     showSearch
     optionFilterProp="label"
     :filterOption="(input, option) => {
-      return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+      return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
     }" >
-    <a-select-option value="allow">{{ $t('label.allow') }}</a-select-option>
-    <a-select-option value="deny">{{ $t('label.deny') }}</a-select-option>
+    <a-select-option value="allow" :label="$t('label.allow')">{{ $t('label.allow') }}</a-select-option>
+    <a-select-option value="deny" :label="$t('label.deny')">{{ $t('label.deny') }}</a-select-option>
   </a-select>
 </template>
 
diff --git a/ui/src/views/iam/RolePermissionTab.vue b/ui/src/views/iam/RolePermissionTab.vue
index 7a0a622..49a9e98 100644
--- a/ui/src/views/iam/RolePermissionTab.vue
+++ b/ui/src/views/iam/RolePermissionTab.vue
@@ -69,7 +69,6 @@
         handle=".drag-handle"
         animation="200"
         ghostClass="drag-ghost"
-        tag="transition-group"
         :component-data="{type: 'transition'}"
         item-key="id">
         <template #item="{element}">
diff --git a/ui/src/views/iam/SSLCertificateTab.vue b/ui/src/views/iam/SSLCertificateTab.vue
index 6a3e161..4015e20 100644
--- a/ui/src/views/iam/SSLCertificateTab.vue
+++ b/ui/src/views/iam/SSLCertificateTab.vue
@@ -28,23 +28,25 @@
           :pagination="false"
           v-if="!quickview"
         >
-          <template #action="{ record }" class="cert-button-action">
-            <tooltip-button
-              tooltipPlacement="top"
-              :tooltip="$t('label.quickview')"
-              type="primary"
-              icon="eye-outlined"
-              size="small"
-              @onClick="onQuickView(record.id)" />
-            <tooltip-button
-              tooltipPlacement="top"
-              :tooltip="$t('label.delete.sslcertificate')"
-              :disabled="!('deleteSslCert' in $store.getters.apis)"
-              type="primary"
-              :danger="true"
-              icon="delete-outlined"
-              size="small"
-              @onClick="onShowConfirm(record)" />
+          <template #bodyCell="{ column, record }">
+            <template v-if="column.key === 'actions'" class="cert-button-action">
+              <tooltip-button
+                tooltipPlacement="top"
+                :tooltip="$t('label.quickview')"
+                type="primary"
+                icon="eye-outlined"
+                size="small"
+                @onClick="onQuickView(record.id)" />
+              <tooltip-button
+                tooltipPlacement="top"
+                :tooltip="$t('label.delete.sslcertificate')"
+                :disabled="!('deleteSslCert' in $store.getters.apis)"
+                type="primary"
+                :danger="true"
+                icon="delete-outlined"
+                size="small"
+                @onClick="onShowConfirm(record)" />
+            </template>
           </template>
         </a-table>
 
@@ -128,22 +130,22 @@
   created () {
     this.columns = [
       {
+        key: 'name',
         title: this.$t('label.name'),
-        dataIndex: 'name',
-        slots: { customRender: 'name' }
+        dataIndex: 'name'
       },
       {
+        key: 'id',
         title: this.$t('label.certificateid'),
         dataIndex: 'id',
-        width: 450,
-        slots: { customRender: 'id' }
+        width: 450
       },
       {
-        title: this.$t('label.action'),
-        dataIndex: 'action',
+        key: 'actions',
+        title: this.$t('label.actions'),
+        dataIndex: 'actions',
         fixed: 'right',
-        width: 80,
-        slots: { customRender: 'action' }
+        width: 80
       }
     ]
     this.detailColumn = ['name', 'certificate', 'certchain']
diff --git a/ui/src/views/iam/SetupTwoFaAtUserProfile.vue b/ui/src/views/iam/SetupTwoFaAtUserProfile.vue
index 6f4f729..df6466a 100644
--- a/ui/src/views/iam/SetupTwoFaAtUserProfile.vue
+++ b/ui/src/views/iam/SetupTwoFaAtUserProfile.vue
@@ -29,10 +29,6 @@
           <a-form-item v-ctrl-enter="submitPin" ref="selectedProvider" name="selectedProvider">
              <a-select
               v-model:value="form.selectedProvider"
-              optionFilterProp="label"
-              :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-              }"
               @change="val => { handleSelectChange(val) }">
               <a-select-option
                 v-for="(opt) in providers"
diff --git a/ui/src/views/image/IsoZones.vue b/ui/src/views/image/IsoZones.vue
index 7718b1c..326f102 100644
--- a/ui/src/views/image/IsoZones.vue
+++ b/ui/src/views/image/IsoZones.vue
@@ -35,43 +35,45 @@
       :pagination="false"
       :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
       :rowKey="record => record.zoneid">
-      <template #zonename="{record}">
-        <span v-if="fetchZoneIcon(record.zoneid)">
-          <resource-icon :image="zoneIcon" size="1x" style="margin-right: 5px"/>
-        </span>
-        <global-outlined v-else style="margin-right: 5px" />
-        <span> {{ record.zonename }} </span>
-      </template>
-      <template #isready="{ record }">
-        <span v-if="record.isready">{{ $t('label.yes') }}</span>
-        <span v-else>{{ $t('label.no') }}</span>
-      </template>
-      <template #action="{ record }">
-        <span style="margin-right: 5px">
-          <tooltip-button
-            :tooltip="$t('label.action.copy.iso')"
-            :disabled="!('copyIso' in $store.getters.apis && record.isready)"
-            icon="copy-outlined"
-            :loading="copyLoading"
-            @click="showCopyIso(record)" />
-        </span>
-        <span style="margin-right: 5px">
-          <a-popconfirm
-            v-if="'deleteIso' in $store.getters.apis"
-            placement="topRight"
-            :title="$t('message.action.delete.iso')"
-            :ok-text="$t('label.yes')"
-            :cancel-text="$t('label.no')"
-            :loading="deleteLoading"
-            @confirm="deleteIso(record)"
-          >
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'zonename'">
+          <span v-if="fetchZoneIcon(record.zoneid)">
+            <resource-icon :image="zoneIcon" size="1x" style="margin-right: 5px"/>
+          </span>
+          <global-outlined v-else style="margin-right: 5px" />
+          <span> {{ record.zonename }} </span>
+        </template>
+        <template v-if="column.key === 'isready'">
+          <span v-if="record.isready">{{ $t('label.yes') }}</span>
+          <span v-else>{{ $t('label.no') }}</span>
+        </template>
+        <template v-if="column.key === 'actions'">
+          <span style="margin-right: 5px">
             <tooltip-button
-              :tooltip="$t('label.action.delete.iso')"
-              type="primary"
-              :danger="true"
-              icon="delete-outlined" />
-          </a-popconfirm>
-        </span>
+              :tooltip="$t('label.action.copy.iso')"
+              :disabled="!('copyIso' in $store.getters.apis && record.isready)"
+              icon="copy-outlined"
+              :loading="copyLoading"
+              @click="showCopyIso(record)" />
+          </span>
+          <span style="margin-right: 5px">
+            <a-popconfirm
+              v-if="'deleteIso' in $store.getters.apis"
+              placement="topRight"
+              :title="$t('message.action.delete.iso')"
+              :ok-text="$t('label.yes')"
+              :cancel-text="$t('label.no')"
+              :loading="deleteLoading"
+              @confirm="deleteIso(record)"
+            >
+              <tooltip-button
+                :tooltip="$t('label.action.delete.iso')"
+                type="primary"
+                :danger="true"
+                icon="delete-outlined" />
+            </a-popconfirm>
+          </span>
+        </template>
       </template>
     </a-table>
     <a-pagination
@@ -221,27 +223,27 @@
     this.initForm()
     this.columns = [
       {
+        key: 'zonename',
         title: this.$t('label.zonename'),
-        dataIndex: 'zonename',
-        slots: { customRender: 'zonename' }
+        dataIndex: 'zonename'
       },
       {
         title: this.$t('label.status'),
         dataIndex: 'status'
       },
       {
+        key: 'isready',
         title: this.$t('label.isready'),
-        dataIndex: 'isready',
-        slots: { customRender: 'isready' }
+        dataIndex: 'isready'
       }
     ]
     if (this.isActionPermitted()) {
       this.columns.push({
+        key: 'actions',
         title: '',
-        dataIndex: 'action',
+        dataIndex: 'actions',
         fixed: 'right',
-        width: 100,
-        slots: { customRender: 'action' }
+        width: 100
       })
     }
 
@@ -355,9 +357,9 @@
     deleteIsos (e) {
       this.showConfirmationAction = false
       this.selectedColumns.splice(0, 0, {
+        key: 'status',
         dataIndex: 'status',
         title: this.$t('label.operation.status'),
-        slots: { customRender: 'status' },
         filters: [
           { text: 'In Progress', value: 'InProgress' },
           { text: 'Success', value: 'success' },
diff --git a/ui/src/views/image/RegisterOrUploadIso.vue b/ui/src/views/image/RegisterOrUploadIso.vue
index cf1435a..c56dcd8 100644
--- a/ui/src/views/image/RegisterOrUploadIso.vue
+++ b/ui/src/views/image/RegisterOrUploadIso.vue
@@ -50,7 +50,7 @@
           <a-upload-dragger
             :multiple="false"
             :fileList="fileList"
-            :remove="handleRemove"
+            @remove="handleRemove"
             :beforeUpload="beforeUpload"
             v-model:value="form.file">
             <p class="ant-upload-drag-icon">
@@ -111,11 +111,11 @@
             }"
             :loading="osTypeLoading"
             :placeholder="apiParams.ostypeid.description">
-            <a-select-option :value="opt.id" v-for="(opt, optIndex) in osTypes" :key="optIndex" :label="opt.name || opt.description">
+            <a-select-option :value="opt.id" v-for="(opt, optIndex) in osTypes" :key="optIndex" :label="opt.name">
               <span>
                 <resource-icon v-if="opt.icon" :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/>
                 <global-outlined v-else style="margin-right: 5px" />
-                {{ opt.name || opt.description }}
+                {{ opt.name }}
               </span>
             </a-select-option>
           </a-select>
@@ -131,12 +131,12 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children?.[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }"
                 v-model:value="userdataid"
                 :placeholder="linkUserDataParams.userdataid.description"
                 :loading="userdata.loading">
-                <a-select-option v-for="opt in userdata.opts" :key="opt.id">
+                <a-select-option v-for="opt in userdata.opts" :key="opt.id" :label="opt.name || opt.description">
                   {{ opt.name || opt.description }}
                 </a-select-option>
               </a-select>
@@ -148,13 +148,14 @@
                 <tooltip-label :title="$t('label.userdatapolicy')" :tooltip="$t('label.userdatapolicy.tooltip')"/>
               </template>
               <a-select
+                showSearch
                 v-model:value="userdatapolicy"
                 :placeholder="linkUserDataParams.userdatapolicy.description"
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }" >
-                <a-select-option v-for="opt in userdatapolicylist.opts" :key="opt.id">
+                <a-select-option v-for="opt in userdatapolicylist.opts" :key="opt.id" :label="opt.id || opt.description">
                   {{ opt.id || opt.description }}
                 </a-select-option>
               </a-select>
@@ -260,7 +261,6 @@
         url: [{ required: true, message: this.$t('label.upload.iso.from.local') }],
         file: [{ required: true, message: this.$t('message.error.required.input') }],
         name: [{ required: true, message: this.$t('message.error.required.input') }],
-        displaytext: [{ required: true, message: this.$t('message.error.required.input') }],
         zoneid: [{ required: true, message: this.$t('message.error.select') }],
         ostypeid: [{ required: true, message: this.$t('message.error.select') }]
       })
diff --git a/ui/src/views/image/RegisterOrUploadTemplate.vue b/ui/src/views/image/RegisterOrUploadTemplate.vue
index e4d4687..4ed33af 100644
--- a/ui/src/views/image/RegisterOrUploadTemplate.vue
+++ b/ui/src/views/image/RegisterOrUploadTemplate.vue
@@ -44,7 +44,7 @@
             <a-upload-dragger
               :multiple="false"
               :fileList="fileList"
-              :remove="handleRemove"
+              @remove="handleRemove"
               :beforeUpload="beforeUpload"
               v-model:value="form.file">
               <p class="ant-upload-drag-icon">
@@ -128,9 +128,9 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }" >
-                <a-select-option v-for="(opt, optIndex) in hyperVisor.opts" :key="optIndex">
+                <a-select-option v-for="(opt, optIndex) in hyperVisor.opts" :key="optIndex" :label="opt.name || opt.description">
                   {{ opt.name || opt.description }}
                 </a-select-option>
               </a-select>
@@ -145,9 +145,9 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }" >
-                <a-select-option v-for="opt in format.opts" :key="opt.id">
+                <a-select-option v-for="opt in format.opts" :key="opt.id" :label="opt.name || opt.description">
                   {{ opt.name || opt.description }}
                 </a-select-option>
               </a-select>
@@ -191,9 +191,9 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }" >
-                <a-select-option v-for="opt in rootDisk.opts" :key="opt.id">
+                <a-select-option v-for="opt in rootDisk.opts" :key="opt.id" :label="opt.name || opt.description">
                   {{ opt.name || opt.description }}
                 </a-select-option>
               </a-select>
@@ -206,10 +206,10 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }"
                 :placeholder="$t('label.nicadaptertype')">
-                <a-select-option v-for="opt in nicAdapterType.opts" :key="opt.id">
+                <a-select-option v-for="opt in nicAdapterType.opts" :key="opt.id" :label="opt.name || opt.description">
                   {{ opt.name || opt.description }}
                 </a-select-option>
               </a-select>
@@ -226,10 +226,10 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :placeholder="$t('label.keyboard')">
-            <a-select-option v-for="opt in keyboardType.opts" :key="opt.id">
+            <a-select-option v-for="opt in keyboardType.opts" :key="opt.id" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -243,12 +243,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             v-model:value="form.ostypeid"
             :loading="osTypes.loading"
             :placeholder="apiParams.ostypeid.description">
-            <a-select-option v-for="opt in osTypes.opts" :key="opt.id">
+            <a-select-option v-for="opt in osTypes.opts" :key="opt.id" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -263,12 +263,12 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children?.[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }"
                 v-model:value="userdataid"
                 :placeholder="linkUserDataParams.userdataid.description"
                 :loading="userdata.loading">
-                <a-select-option v-for="opt in userdata.opts" :key="opt.id">
+                <a-select-option v-for="opt in userdata.opts" :key="opt.id" :label="opt.name || opt.description">
                   {{ opt.name || opt.description }}
                 </a-select-option>
               </a-select>
@@ -280,13 +280,14 @@
                 <tooltip-label :title="$t('label.userdatapolicy')" :tooltip="$t('label.userdatapolicy.tooltip')"/>
               </template>
               <a-select
+                showSearch
                 v-model:value="userdatapolicy"
                 :placeholder="linkUserDataParams.userdatapolicy.description"
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }" >
-                <a-select-option v-for="opt in userdatapolicylist.opts" :key="opt.id">
+                <a-select-option v-for="opt in userdatapolicylist.opts" :key="opt.id" :label="opt.id || opt.description">
                   {{ opt.id || opt.description }}
                 </a-select-option>
               </a-select>
@@ -441,7 +442,6 @@
         url: [{ required: true, message: this.$t('message.error.required.input') }],
         file: [{ required: true, message: this.$t('message.error.required.input') }],
         name: [{ required: true, message: this.$t('message.error.required.input') }],
-        displaytext: [{ required: true, message: this.$t('message.error.required.input') }],
         zoneids: [
           { type: 'array', required: true, message: this.$t('message.error.select') },
           {
@@ -454,7 +454,6 @@
         ostypeid: [{ required: true, message: this.$t('message.error.select') }],
         groupenabled: [{ type: 'array' }]
       })
-      console.log(this.form)
     },
     fetchData () {
       this.fetchZone()
@@ -576,7 +575,7 @@
         const listOsTypes = json.listostypesresponse.ostype
         this.osTypes.opts = listOsTypes
         this.defaultOsType = this.osTypes.opts[1].description
-        this.defaultOsId = this.osTypes.opts[1].id
+        this.defaultOsId = this.osTypes.opts[1].name
       }).finally(() => {
         this.osTypes.loading = false
       })
diff --git a/ui/src/views/image/TemplateZones.vue b/ui/src/views/image/TemplateZones.vue
index d4811c0..8d7a3e2 100644
--- a/ui/src/views/image/TemplateZones.vue
+++ b/ui/src/views/image/TemplateZones.vue
@@ -35,20 +35,39 @@
       :pagination="false"
       :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
       :rowKey="record => record.zoneid">
-      <template #zonename="{record}">
-        <span v-if="fetchZoneIcon(record.zoneid)">
-          <resource-icon :image="zoneIcon" size="1x" style="margin-right: 5px"/>
-        </span>
-        <global-outlined v-else style="margin-right: 5px" />
-        <span> {{ record.zonename }} </span>
-      </template>
-      <template #isready="{ record }">
-        <span v-if="record.isready">{{ $t('label.yes') }}</span>
-        <span v-else>{{ $t('label.no') }}</span>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'zonename'">
+          <span v-if="fetchZoneIcon(record.zoneid)">
+            <resource-icon :image="zoneIcon" size="1x" style="margin-right: 5px"/>
+          </span>
+          <global-outlined v-else style="margin-right: 5px" />
+          <span> {{ record.zonename }} </span>
+        </template>
+        <template v-if="column.key === 'isready'">
+          <span v-if="record.isready">{{ $t('label.yes') }}</span>
+          <span v-else>{{ $t('label.no') }}</span>
+        </template>
+        <template v-if="column.key === 'actions'">
+          <tooltip-button
+            style="margin-right: 5px"
+            :disabled="!('copyTemplate' in $store.getters.apis && record.isready)"
+            :title="$t('label.action.copy.template')"
+            icon="copy-outlined"
+            :loading="copyLoading"
+            @onClick="showCopyTemplate(record)" />
+          <tooltip-button
+            style="margin-right: 5px"
+            :disabled="!('deleteTemplate' in $store.getters.apis)"
+            :title="$t('label.action.delete.template')"
+            type="primary"
+            :danger="true"
+            icon="delete-outlined"
+            @onClick="onShowDeleteModal(record)"/>
+        </template>
       </template>
       <template #expandedRowRender="{ record }">
         <a-table
-          style="marginLeft: -50px; marginTop: 10px; marginBottom: 10px"
+          style="margin: 10px 0;"
           :columns="innerColumns"
           :data-source="record.downloaddetails"
           :pagination="false"
@@ -56,23 +75,6 @@
           :rowKey="record => record.zoneid">
         </a-table>
       </template>
-      <template #action="{ record }">
-        <tooltip-button
-          style="margin-right: 5px"
-          :disabled="!('copyTemplate' in $store.getters.apis && record.isready)"
-          :title="$t('label.action.copy.template')"
-          icon="copy-outlined"
-          :loading="copyLoading"
-          @onClick="showCopyTemplate(record)" />
-        <tooltip-button
-          style="margin-right: 5px"
-          :disabled="!('deleteTemplate' in $store.getters.apis)"
-          :title="$t('label.action.delete.template')"
-          type="primary"
-          :danger="true"
-          icon="delete-outlined"
-          @onClick="onShowDeleteModal(record)"/>
-      </template>
     </a-table>
     <a-pagination
       class="row-element"
@@ -171,12 +173,12 @@
           size="middle"
           :columns="selectedColumns"
           :dataSource="selectedItems"
-          :rowKey="(record, idx) => record.zoneid || record.name"
+          :rowKey="record => record.zoneid || record.name"
           :pagination="true"
           style="overflow-y: auto">
         </a-table>
         <a-spin :spinning="deleteLoading">
-          <a-form-item :label="$t('label.isforced')" style="margin-bottom: 0;">
+          <a-form-item ref="forcedDelete" name="forcedDelete" :label="$t('label.isforced')" style="margin-bottom: 0;">
             <a-switch v-model:checked="forcedDelete" v-focus="true"></a-switch>
           </a-form-item>
           <div :span="24" class="action-button">
@@ -260,18 +262,18 @@
   created () {
     this.columns = [
       {
+        key: 'zonename',
         title: this.$t('label.zonename'),
-        dataIndex: 'zonename',
-        slots: { customRender: 'zonename' }
+        dataIndex: 'zonename'
       },
       {
         title: this.$t('label.status'),
         dataIndex: 'status'
       },
       {
+        key: 'isready',
         title: this.$t('label.isready'),
-        dataIndex: 'isready',
-        slots: { customRender: 'isready' }
+        dataIndex: 'isready'
       }
     ]
     this.innerColumns = [
@@ -290,10 +292,10 @@
     ]
     if (this.isActionPermitted()) {
       this.columns.push({
+        key: 'actions',
         title: '',
-        dataIndex: 'action',
-        width: 100,
-        slots: { customRender: 'action' }
+        dataIndex: 'actions',
+        width: 100
       })
     }
 
@@ -422,9 +424,9 @@
     deleteTemplates (e) {
       this.showConfirmationAction = false
       this.selectedColumns.splice(0, 0, {
+        key: 'status',
         dataIndex: 'status',
         title: this.$t('label.operation.status'),
-        slots: { customRender: 'status' },
         filters: [
           { text: 'In Progress', value: 'InProgress' },
           { text: 'Success', value: 'success' },
diff --git a/ui/src/views/image/UpdateISO.vue b/ui/src/views/image/UpdateISO.vue
index 2fa7979..4d7140d 100644
--- a/ui/src/views/image/UpdateISO.vue
+++ b/ui/src/views/image/UpdateISO.vue
@@ -48,12 +48,15 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             v-model:value="form.ostypeid"
             :loading="osTypes.loading"
             :placeholder="apiParams.ostypeid.description">
-            <a-select-option v-for="opt in osTypes.opts" :key="opt.id">
+            <a-select-option
+              v-for="opt in osTypes.opts"
+              :key="opt.id"
+              :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -69,12 +72,12 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children?.[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }"
                 v-model:value="userdataid"
                 :placeholder="linkUserDataParams.userdataid.description"
                 :loading="userdata.loading">
-                <a-select-option v-for="opt in userdata.opts" :key="opt.id">
+                <a-select-option v-for="opt in userdata.opts" :key="opt.id" :label="opt.name || opt.description">
                   {{ opt.name || opt.description }}
                 </a-select-option>
               </a-select>
@@ -86,13 +89,17 @@
                 <tooltip-label :title="$t('label.userdatapolicy')" :tooltip="$t('label.userdatapolicy.tooltip')"/>
               </template>
               <a-select
+                showSearch
                 v-model:value="userdatapolicy"
                 :placeholder="linkUserDataParams.userdatapolicy.description"
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }" >
-                <a-select-option v-for="opt in userdatapolicylist.opts" :key="opt.id">
+                <a-select-option
+                  v-for="opt in userdatapolicylist.opts"
+                  :key="opt.id"
+                  :label="opt.name || opt.description">
                   {{ opt.id || opt.description }}
                 </a-select-option>
               </a-select>
diff --git a/ui/src/views/image/UpdateKubernetesSupportedVersion.vue b/ui/src/views/image/UpdateKubernetesSupportedVersion.vue
index 9081eb0..8d2b4e4 100644
--- a/ui/src/views/image/UpdateKubernetesSupportedVersion.vue
+++ b/ui/src/views/image/UpdateKubernetesSupportedVersion.vue
@@ -30,12 +30,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="stateLoading"
             :placeholder="apiParams.state.description"
             v-focus="true" >
-            <a-select-option v-for="(opt, optIndex) in states" :key="optIndex">
+            <a-select-option v-for="(opt, optIndex) in states" :key="optIndex" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
diff --git a/ui/src/views/image/UpdateTemplate.vue b/ui/src/views/image/UpdateTemplate.vue
index 441c685..9b6f754 100644
--- a/ui/src/views/image/UpdateTemplate.vue
+++ b/ui/src/views/image/UpdateTemplate.vue
@@ -92,12 +92,12 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }"
                 v-model:value="form.ostypeid"
                 :loading="osTypes.loading"
                 :placeholder="apiParams.ostypeid.description">
-                <a-select-option v-for="opt in osTypes.opts" :key="opt.id">
+                <a-select-option v-for="opt in osTypes.opts" :key="opt.id" :label="opt.name || opt.description">
                   {{ opt.name || opt.description }}
                 </a-select-option>
               </a-select>
@@ -114,12 +114,12 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children?.[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }"
                 v-model:value="userdataid"
                 :placeholder="linkUserDataParams.userdataid.description"
                 :loading="userdata.loading">
-                <a-select-option v-for="opt in userdata.opts" :key="opt.id">
+                <a-select-option v-for="opt in userdata.opts" :key="opt.id" :label="opt.name || opt.description">
                   {{ opt.name || opt.description }}
                 </a-select-option>
               </a-select>
@@ -131,13 +131,14 @@
                 <tooltip-label :title="$t('label.userdatapolicy')" :tooltip="$t('label.userdatapolicy.tooltip')"/>
               </template>
               <a-select
+                showSearch
                 v-model:value="userdatapolicy"
                 :placeholder="linkUserDataParams.userdatapolicy.description"
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }" >
-                <a-select-option v-for="opt in userdatapolicylist.opts" :key="opt.id">
+                <a-select-option v-for="opt in userdatapolicylist.opts" :key="opt.id" :label="opt.id || opt.description">
                   {{ opt.id || opt.description }}
                 </a-select-option>
               </a-select>
@@ -164,9 +165,9 @@
           </span>
           <a-select
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             v-model:value="form.templatetype"
             :placeholder="apiParams.templatetype.description"
diff --git a/ui/src/views/image/UpdateTemplateIsoPermissions.vue b/ui/src/views/image/UpdateTemplateIsoPermissions.vue
index 05840c6..c7b0f9e 100644
--- a/ui/src/views/image/UpdateTemplateIsoPermissions.vue
+++ b/ui/src/views/image/UpdateTemplateIsoPermissions.vue
@@ -29,9 +29,9 @@
         @change="fetchData"
         v-focus="true"
         showSearch
-        optionFilterProp="label"
+        optionFilterProp="value"
         :filterOption="(input, option) => {
-          return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+          return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
         }" >
         <a-select-option :value="$t('label.add')">{{ $t('label.add') }}</a-select-option>
         <a-select-option :value="$t('label.remove')">{{ $t('label.remove') }}</a-select-option>
@@ -50,9 +50,9 @@
           :defaultValue="$t('label.account')"
           @change="fetchData"
           showSearch
-          optionFilterProp="label"
+          optionFilterProp="value"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }">
           <a-select-option :value="$t('label.account')">{{ $t('label.account') }}</a-select-option>
           <a-select-option :value="$t('label.project')">{{ $t('label.project') }}</a-select-option>
diff --git a/ui/src/views/infra/AddPrimaryStorage.vue b/ui/src/views/infra/AddPrimaryStorage.vue
index c1c733d..b30b034 100644
--- a/ui/src/views/infra/AddPrimaryStorage.vue
+++ b/ui/src/views/infra/AddPrimaryStorage.vue
@@ -35,11 +35,11 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :placeholder="apiParams.scope.description" >
-            <a-select-option :value="'cluster'"> {{ $t('label.clusterid') }} </a-select-option>
-            <a-select-option :value="'zone'"> {{ $t('label.zoneid') }} </a-select-option>
+            <a-select-option :value="'cluster'" :label="$t('label.clusterid')"> {{ $t('label.clusterid') }} </a-select-option>
+            <a-select-option :value="'zone'" :label="$t('label.zoneid')"> {{ $t('label.zoneid') }} </a-select-option>
           </a-select>
         </a-form-item>
         <div v-if="form.scope === 'zone'">
@@ -50,9 +50,9 @@
             <a-select
               v-model:value="form.hypervisor"
               showSearch
-              optionFilterProp="label"
+              optionFilterProp="value"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :placeholder="apiParams.hypervisor.description" >
               <a-select-option :value="hypervisor" v-for="(hypervisor, idx) in hypervisors" :key="idx">
@@ -93,10 +93,10 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :placeholder="apiParams.podid.description">
-              <a-select-option :value="pod.id" v-for="(pod) in pods" :key="pod.id">
+              <a-select-option :value="pod.id" v-for="(pod) in pods" :key="pod.id" :label="pod.name">
                 {{ pod.name }}
               </a-select-option>
             </a-select>
@@ -111,10 +111,10 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :placeholder="apiParams.clusterid.description">
-              <a-select-option :value="cluster.id" v-for="cluster in clusters" :key="cluster.id">
+              <a-select-option :value="cluster.id" v-for="cluster in clusters" :key="cluster.id" :label="cluster.name">
                 {{ cluster.name }}
               </a-select-option>
             </a-select>
@@ -127,9 +127,9 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
-              <a-select-option :value="host.id" v-for="host in hosts" :key="host.id">
+              <a-select-option :value="host.id" v-for="host in hosts" :key="host.id" :label="host.name">
                 {{ host.name }}
               </a-select-option>
             </a-select>
@@ -148,9 +148,9 @@
           <a-select
             v-model:value="form.protocol"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :placeholder="apiParams.clusterid.description">
             <a-select-option :value="protocol" v-for="(protocol,idx) in protocols" :key="idx">
@@ -218,9 +218,9 @@
               v-model:value="form.provider"
               @change="updateProviderAndProtocol"
               showSearch
-              optionFilterProp="label"
+              optionFilterProp="value"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :placeholder="apiParams.provider.description">
               <a-select-option :value="provider" v-for="(provider,idx) in providers" :key="idx">
diff --git a/ui/src/views/infra/AddSecondaryStorage.vue b/ui/src/views/infra/AddSecondaryStorage.vue
index 3dbf8cc..4adc4e9 100644
--- a/ui/src/views/infra/AddSecondaryStorage.vue
+++ b/ui/src/views/infra/AddSecondaryStorage.vue
@@ -33,9 +33,9 @@
             v-model:value="form.provider"
             @change="val => { form.provider = val }"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option
               :value="prov"
diff --git a/ui/src/views/infra/AsyncJobsTab.vue b/ui/src/views/infra/AsyncJobsTab.vue
new file mode 100644
index 0000000..7b514a4
--- /dev/null
+++ b/ui/src/views/infra/AsyncJobsTab.vue
@@ -0,0 +1,104 @@
+// 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.
+
+<template>
+  <a-table
+    class="table"
+    size="small"
+    :columns="columns"
+    :dataSource="jobs"
+    :rowKey="item => item.id"
+    :pagination="false" >
+    <template #cmd="{ text }">
+      {{ text.split('.').pop() }}
+    </template>
+    <template #account="{ text, record }">
+      <router-link :to="{ path: '/account/' + record.accountid }">{{ text }}</router-link>
+    </template>
+    <template #domainpath="{ text, record }">
+      <router-link :to="{ path: '/domain/' + record.domainid, query: { tab: 'details' } }">{{ text }}</router-link>
+    </template>
+  </a-table>
+</template>
+
+<script>
+import { api } from '@/api'
+import Status from '@/components/widgets/Status'
+
+export default {
+  name: 'AsyncJobsTab',
+  components: {
+    Status
+  },
+  props: {
+    resource: {
+      type: Object,
+      required: true
+    }
+  },
+  data () {
+    return {
+      jobs: [],
+      columns: [
+        {
+          title: this.$t('label.command'),
+          dataIndex: 'cmd',
+          slots: { customRender: 'cmd' }
+        },
+        {
+          title: this.$t('label.resourcetype'),
+          dataIndex: 'jobinstancetype'
+        },
+        {
+          title: this.$t('label.account'),
+          dataIndex: 'account',
+          slots: { customRender: 'account' }
+        },
+        {
+          title: this.$t('label.domain'),
+          dataIndex: 'domainpath',
+          slots: { customRender: 'domainpath' }
+        },
+        {
+          title: this.$t('label.created'),
+          dataIndex: 'created'
+        }
+      ]
+    }
+  },
+  created () {
+    this.fetchData()
+  },
+  watch: {
+    resource: function (newItem) {
+      this.fetchData()
+    }
+  },
+  methods: {
+    fetchData () {
+      this.jobs = []
+      api('listAsyncJobs', {
+        listall: true,
+        isrecursive: true,
+        managementserverid: this.resource.id
+      }).then(json => {
+        this.jobs = json.listasyncjobsresponse.asyncjobs || []
+      })
+    }
+  }
+}
+</script>
diff --git a/ui/src/views/infra/ClusterAdd.vue b/ui/src/views/infra/ClusterAdd.vue
index 5450db9..862b458 100644
--- a/ui/src/views/infra/ClusterAdd.vue
+++ b/ui/src/views/infra/ClusterAdd.vue
@@ -49,9 +49,9 @@
           v-model:value="hypervisor"
           @change="resetAllFields"
           showSearch
-          optionFilterProp="label"
+          optionFilterProp="value"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
           <a-select-option
             v-for="hv in hypervisorsList"
@@ -69,12 +69,13 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
           <a-select-option
             v-for="pod in podsList"
             :value="pod.id"
-            :key="pod.id">
+            :key="pod.id"
+            :label="pod.name">
             {{ pod.name }}
           </a-select-option>
         </a-select>
diff --git a/ui/src/views/infra/Confirmation.vue b/ui/src/views/infra/Confirmation.vue
new file mode 100644
index 0000000..96b7f6f
--- /dev/null
+++ b/ui/src/views/infra/Confirmation.vue
@@ -0,0 +1,129 @@
+// 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.
+
+<template>
+  <a-spin :spinning="loading">
+    <div class="form-layout" v-ctrl-enter="handleSubmit">
+      <a-form
+        :ref="formRef"
+        :model="form"
+        :rules="rules"
+        @finish="handleSubmit"
+      >
+        <a-alert type="error">
+          <template #message>
+            <span v-html="$t(action.currentAction.message)" />
+          </template>
+        </a-alert>
+        <a-alert type="warning" style="margin-top: 10px">
+          <template #message>
+            <span>{{ $t('message.confirm.type') }} "{{ action.currentAction.confirmationText }}"</span>
+          </template>
+        </a-alert>
+        <a-form-item ref="confirmation" name="confirmation" style="margin-top: 10px">
+            <a-input v-model:value="form.confirmation" />
+        </a-form-item>
+      </a-form>
+
+      <div :span="24" class="action-button">
+        <a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
+        <a-button type="primary" ref="submit" @click="handleSubmit">{{ $t('label.ok') }}</a-button>
+      </div>
+
+    </div>
+  </a-spin>
+</template>
+
+<script>
+
+import { api } from '@/api'
+import { ref, reactive } from 'vue'
+
+export default {
+  name: 'Confirmation',
+  props: {
+    resource: {
+      type: Object,
+      required: true
+    },
+    action: {
+      type: Object,
+      default: () => {}
+    }
+  },
+  inject: ['parentFetchData'],
+  data () {
+    return {
+      loading: false
+    }
+  },
+  created () {
+    this.initForm()
+  },
+  methods: {
+    initForm () {
+      this.formRef = ref()
+      this.form = reactive({})
+      this.rules = reactive({
+        confirmation: [{
+          validator: this.checkConfirmation,
+          message: this.$t('message.error.confirm.text')
+        }]
+      })
+    },
+    async checkConfirmation (rule, value) {
+      if (value && value === 'SHUTDOWN') {
+        return Promise.resolve()
+      }
+      return Promise.reject(rule.message)
+    },
+    handleSubmit (e) {
+      e.preventDefault()
+      if (this.loading) return
+      this.formRef.value.validate().then(() => {
+        this.loading = true
+        const params = { managementserverid: this.resource.id }
+        api(this.action.currentAction.api, params).then(() => {
+          this.$message.success(this.$t(this.action.currentAction.label) + ' : ' + this.resource.name)
+          this.closeAction()
+          this.parentFetchData()
+        }).catch(error => {
+          this.$notifyError(error)
+        }).finally(() => {
+          this.loading = false
+        })
+      })
+    },
+    closeAction () {
+      this.$emit('close-action')
+    }
+  }
+}
+
+</script>
+<style lang="scss" scoped>
+.form-layout {
+  width: 80vw;
+  @media (min-width: 700px) {
+    width: 600px;
+  }
+}
+
+.form {
+  margin: 10px 0;
+}
+</style>
diff --git a/ui/src/views/infra/HostAdd.vue b/ui/src/views/infra/HostAdd.vue
index 063e8dd..def050a 100644
--- a/ui/src/views/infra/HostAdd.vue
+++ b/ui/src/views/infra/HostAdd.vue
@@ -62,13 +62,14 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               @change="fetchClusters">
               <a-select-option
                 v-for="pod in podsList"
                 :value="pod.id"
-                :key="pod.id">
+                :key="pod.id"
+                :label="pod.name">
                 {{ pod.name }}
               </a-select-option>
             </a-select>
@@ -83,13 +84,14 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               @change="handleChangeCluster">
               <a-select-option
                 v-for="cluster in clustersList"
                 :value="cluster.id"
-                :key="cluster.id">
+                :key="cluster.id"
+                :label="cluster.name">
                 {{ cluster.name }}
               </a-select-option>
             </a-select>
@@ -206,9 +208,9 @@
             <a-select
               mode="tags"
               showSearch
-              optionFilterProp="label"
+              optionFilterProp="value"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               v-model:value="form.hosttags"
               :placeholder="placeholder.hosttags">
diff --git a/ui/src/views/infra/HostEnableDisable.vue b/ui/src/views/infra/HostEnableDisable.vue
new file mode 100644
index 0000000..bc71aa2
--- /dev/null
+++ b/ui/src/views/infra/HostEnableDisable.vue
@@ -0,0 +1,133 @@
+// 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.
+
+<template>
+  <div class="form-layout">
+    <a-form
+      :ref="formRef"
+      :model="form"
+      :rules="rules"
+      @finish="handleSubmit"
+      v-ctrl-enter="handleSubmit"
+      class="form"
+      layout="vertical"
+    >
+      <a-alert type="warning">
+        <template #message>
+          <span v-html="$t('message.confirm.enable.host')" />
+        </template>
+      </a-alert>
+      <div v-show="enableKVMAutoEnableDisableSetting" class="reason">
+        <a-form-item
+          class="form__item"
+          name="reason"
+          ref="reason"
+          :label="'The setting \'enable.kvm.host.auto.enable.disable\' is enabled, ' +
+            ' can specify a reason for ' + (resourcestate === 'Enabled' ? 'disabling' : 'enabling') + ' this host'">
+          <a-textarea
+            v-model:value="form.reason"
+            :placeholder="'(Optional) Reason to ' + (resourcestate === 'Enabled' ? 'disable' : 'enable') + ' this host'"
+            rows="3"
+          />
+        </a-form-item>
+      </div>
+      <div :span="24" class="action-button">
+        <a-button @click="$emit('close-action')">{{ $t('label.cancel') }}</a-button>
+        <a-button type="primary" @click="handleSubmit" ref="submit">{{ $t('label.ok') }}</a-button>
+      </div>
+    </a-form>
+  </div>
+</template>
+
+<script>
+import { ref, reactive, toRaw } from 'vue'
+import { api } from '@/api'
+
+export default {
+  name: 'HostEnableDisable',
+  props: {
+    resource: {
+      type: Object,
+      required: true
+    }
+  },
+  data () {
+    return {
+      resourcestate: '',
+      allocationstate: '',
+      enableKVMAutoEnableDisableSetting: false
+    }
+  },
+  created () {
+    this.initForm()
+    this.fetchAutoEnableDisableKVMSetting()
+    this.resourcestate = this.resource.resourcestate
+    this.allocationstate = this.resourcestate === 'Enabled' ? 'Disable' : 'Enable'
+  },
+  beforeCreate () {
+  },
+  methods: {
+    initForm () {
+      this.formRef = ref()
+      this.form = reactive({})
+      this.rules = reactive({})
+    },
+    fetchAutoEnableDisableKVMSetting () {
+      if (this.resource.hypervisor !== 'KVM') {
+        return
+      }
+      api('listConfigurations', { name: 'enable.kvm.host.auto.enable.disable', clusterid: this.resource.clusterid }).then(json => {
+        if (json.listconfigurationsresponse.configuration[0]) {
+          this.enableKVMAutoEnableDisableSetting = json.listconfigurationsresponse.configuration[0].value
+        }
+      })
+    },
+    handleSubmit (e) {
+      e.preventDefault()
+      this.formRef.value.validate().then(() => {
+        const values = toRaw(this.form)
+
+        var data = {
+          allocationstate: this.allocationstate,
+          id: this.resource.id
+        }
+        if (values.reason) {
+          data.annotation = values.reason
+        }
+        api('updateHost', data).then(_ => {
+          this.$emit('close-action')
+        })
+      })
+    }
+  }
+}
+
+</script>
+
+<style scoped>
+.reason {
+  padding-top: 20px
+}
+
+.form-layout {
+    width: 30vw;
+
+    @media (min-width: 500px) {
+      width: 450px;
+    }
+  }
+</style>
diff --git a/ui/src/views/infra/InfraSummary.vue b/ui/src/views/infra/InfraSummary.vue
index 941d15b..8411dca 100644
--- a/ui/src/views/infra/InfraSummary.vue
+++ b/ui/src/views/infra/InfraSummary.vue
@@ -149,8 +149,10 @@
     </a-col>
     <template v-for="(section, index) in sections" :key="index">
       <a-col
+        :xs="12"
+        :sm="8"
         :md="6"
-        style="margin-bottom: 12px"
+        :style="{ marginBottom: '12px' }"
         v-if="routes[section]">
         <chart-card :loading="loading">
           <div class="chart-card-inner">
diff --git a/ui/src/views/infra/MigrateData.vue b/ui/src/views/infra/MigrateData.vue
index fa42579..f6c9f1f 100644
--- a/ui/src/views/infra/MigrateData.vue
+++ b/ui/src/views/infra/MigrateData.vue
@@ -37,11 +37,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option
               v-for="store in imageStores"
-              :key="store.id"> {{ store.name || opt.url }}
+              :key="store.id"
+              :label="store.name || opt.url"> {{ store.name || opt.url }}
             </a-select-option>
           </a-select>
         </a-form-item>
@@ -56,11 +57,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option
               v-for="store in destStores"
-              :key="store.id"> {{ store.name || opt.url }}
+              :key="store.id"
+              :label="store.name || opt.url"> {{ store.name || opt.url }}
             </a-select-option>
           </a-select>
         </a-form-item>
@@ -71,10 +73,10 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="Complete">{{ $t('label.complete') }}</a-select-option>
-            <a-select-option value="Balance">{{ $t('label.balance') }}</a-select-option>
+            <a-select-option value="Complete" :label="$t('label.complete')">{{ $t('label.complete') }}</a-select-option>
+            <a-select-option value="Balance" :label="$t('label.balance')">{{ $t('label.balance') }}</a-select-option>
           </a-select>
         </a-form-item>
         <div :span="24" class="action-button">
diff --git a/ui/src/views/infra/network/DedicatedVLANTab.vue b/ui/src/views/infra/network/DedicatedVLANTab.vue
index 7e59c55..7343b30 100644
--- a/ui/src/views/infra/network/DedicatedVLANTab.vue
+++ b/ui/src/views/infra/network/DedicatedVLANTab.vue
@@ -33,21 +33,23 @@
       :dataSource="items"
       :pagination="false"
       :rowKey="record => record.id">
-      <template #actions="{record}">
-        <a-popconfirm
-          :title="`${$t('label.delete')}?`"
-          @confirm="handleDelete(record)"
-          :okText="$t('label.yes')"
-          :cancelText="$t('label.no')"
-          placement="top"
-        >
-          <tooltip-button
-            :tooltip="$t('label.delete')"
-            :disabled="!('releaseDedicatedGuestVlanRange' in $store.getters.apis)"
-            icon="delete-outlined"
-            type="primary"
-            :danger="true" />
-        </a-popconfirm>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'actions'">
+          <a-popconfirm
+            :title="`${$t('label.delete')}?`"
+            @confirm="handleDelete(record)"
+            :okText="$t('label.yes')"
+            :cancelText="$t('label.no')"
+            placement="top"
+          >
+            <tooltip-button
+              :tooltip="$t('label.delete')"
+              :disabled="!('releaseDedicatedGuestVlanRange' in $store.getters.apis)"
+              icon="delete-outlined"
+              type="primary"
+              :danger="true" />
+          </a-popconfirm>
+        </template>
       </template>
     </a-table>
     <a-pagination
@@ -91,10 +93,10 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
-              <a-select-option value="account">{{ $t('label.account') }}</a-select-option>
-              <a-select-option value="project">{{ $t('label.project') }}</a-select-option>
+              <a-select-option value="account" :label="$t('label.account')">{{ $t('label.account') }}</a-select-option>
+              <a-select-option value="project" :label="$t('label.project')">{{ $t('label.project') }}</a-select-option>
             </a-select>
           </a-form-item>
 
@@ -121,7 +123,7 @@
             <a-select
               v-model:value="form.account"
               showSearch
-              optionFilterProp="label"
+              optionFilterProp="value"
               :filterOption="(input, option) => {
                 return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
@@ -219,8 +221,8 @@
           dataIndex: 'account'
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          key: 'actions',
+          title: this.$t('label.actions')
         }
       ]
     }
diff --git a/ui/src/views/infra/network/EditTrafficLabel.vue b/ui/src/views/infra/network/EditTrafficLabel.vue
index f147bab..f8f44d9 100644
--- a/ui/src/views/infra/network/EditTrafficLabel.vue
+++ b/ui/src/views/infra/network/EditTrafficLabel.vue
@@ -39,9 +39,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option v-for="type in trafficTypes" :key="type.id">
+            <a-select-option v-for="type in trafficTypes" :key="type.id" :label="type.traffictype">
               {{ type.traffictype }}
             </a-select-option>
           </a-select>
diff --git a/ui/src/views/infra/network/IpRangesTabGuest.vue b/ui/src/views/infra/network/IpRangesTabGuest.vue
index 4de5fd2..2c575d7 100644
--- a/ui/src/views/infra/network/IpRangesTabGuest.vue
+++ b/ui/src/views/infra/network/IpRangesTabGuest.vue
@@ -33,20 +33,22 @@
       :rowKey="record => record.id + record.prefix"
       :pagination="false"
     >
-      <template #allocated="{ record }">
-        {{ record.usedsubnets + '/' + record.totalsubnets }}
-      </template>
-      <template #actions="{ record }">
-        <div class="actions">
-          <tooltip-button
-            tooltipPlacement="bottom"
-            :tooltip="$t('label.delete.ip.v6.prefix')"
-            type="primary"
-            icon="delete-outlined"
-            :danger="true"
-            @click="handleDeleteIpv6Prefix(record)"
-            :disabled="!('deleteGuestNetworkIpv6Prefix' in $store.getters.apis)" />
-        </div>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'allocated'">
+          {{ record.usedsubnets + '/' + record.totalsubnets }}
+        </template>
+        <template v-if="column.key === 'actions'">
+          <div class="actions">
+            <tooltip-button
+              tooltipPlacement="bottom"
+              :tooltip="$t('label.delete.ip.v6.prefix')"
+              type="primary"
+              icon="delete-outlined"
+              :danger="true"
+              @click="handleDeleteIpv6Prefix(record)"
+              :disabled="!('deleteGuestNetworkIpv6Prefix' in $store.getters.apis)" />
+          </div>
+        </template>
       </template>
     </a-table>
     <br>
@@ -69,12 +71,14 @@
       :rowKey="record => record.id"
       :pagination="false"
     >
-      <template #name="{ text, record }">
-        <resource-icon v-if="record.icon" :image="record.icon.base64image" size="1x" style="margin-right: 5px"/>
-        <apartment-outlined v-else style="margin-right: 5px"/>
-        <router-link :to="{ path: '/guestnetwork/' + record.id }">
-          {{ text }}
-        </router-link>
+      <template #bodyCell="{ column, text, record }">
+        <template v-if="column.key === 'name'">
+          <resource-icon v-if="record.icon" :image="record.icon.base64image" size="1x" style="margin-right: 5px"/>
+          <apartment-outlined v-else style="margin-right: 5px"/>
+          <router-link :to="{ path: '/guestnetwork/' + record.id }">
+            {{ text }}
+          </router-link>
+        </template>
       </template>
     </a-table>
     <a-pagination
@@ -170,9 +174,9 @@
       pageSize: 10,
       columns: [
         {
+          key: 'name',
           title: this.$t('label.name'),
-          dataIndex: 'name',
-          slots: { customRender: 'name' }
+          dataIndex: 'name'
         },
         {
           title: this.$t('label.type'),
@@ -202,12 +206,12 @@
           dataIndex: 'prefix'
         },
         {
-          title: this.$t('label.allocated'),
-          slots: { customRender: 'allocated' }
+          key: 'allocated',
+          title: this.$t('label.allocated')
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          key: 'actions',
+          title: this.$t('label.actions')
         }
       ],
       addIpv6PrefixModal: false
diff --git a/ui/src/views/infra/network/IpRangesTabManagement.vue b/ui/src/views/infra/network/IpRangesTabManagement.vue
index e7abfa8..f6d0029 100644
--- a/ui/src/views/infra/network/IpRangesTabManagement.vue
+++ b/ui/src/views/infra/network/IpRangesTabManagement.vue
@@ -34,20 +34,22 @@
       :rowKey="record => record.id + record.startip"
       :pagination="false"
     >
-      <template #forsystemvms="{ record }">
-        <a-checkbox v-model:checked="record.forsystemvms" />
-      </template>
-      <template #actions="{ record }">
-        <div class="actions">
-          <tooltip-button
-            tooltipPlacement="bottom"
-            :tooltip="$t('label.remove.ip.range')"
-            :disabled="!('deleteManagementNetworkIpRange' in $store.getters.apis)"
-            icon="delete-outlined"
-            type="primary"
-            :danger="true"
-            @onClick="handleDeleteIpRange(record)" />
-        </div>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'forsystemvms'">
+          <a-checkbox v-model:checked="record.forsystemvms" />
+        </template>
+        <template v-if="column.key === 'actions'">
+          <div class="actions">
+            <tooltip-button
+              tooltipPlacement="bottom"
+              :tooltip="$t('label.remove.ip.range')"
+              :disabled="!('deleteManagementNetworkIpRange' in $store.getters.apis)"
+              icon="delete-outlined"
+              type="primary"
+              :danger="true"
+              @onClick="handleDeleteIpRange(record)" />
+          </div>
+        </template>
       </template>
     </a-table>
     <a-pagination
@@ -90,9 +92,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option v-for="item in pods" :key="item.id" :value="item.id">{{ item.name }}</a-select-option>
+            <a-select-option v-for="item in pods" :key="item.id" :value="item.id" :label="item.name">{{ item.name }}</a-select-option>
           </a-select>
         </a-form-item>
         <a-form-item name="gateway" ref="gateway" :label="$t('label.gateway')" class="form__item">
@@ -170,28 +172,28 @@
           dataIndex: 'netmask'
         },
         {
+          key: 'vlan',
           title: this.$t('label.vlan'),
-          dataIndex: 'vlanid',
-          slots: { customRender: 'vlan' }
+          dataIndex: 'vlanid'
         },
         {
+          key: 'startip',
           title: this.$t('label.startip'),
-          dataIndex: 'startip',
-          slots: { customRender: 'startip' }
+          dataIndex: 'startip'
         },
         {
+          key: 'endip',
           title: this.$t('label.endip'),
-          dataIndex: 'endip',
-          slots: { customRender: 'endip' }
+          dataIndex: 'endip'
         },
         {
+          key: 'forsystemvms',
           title: this.$t('label.system.vms'),
-          dataIndex: 'forsystemvms',
-          slots: { customRender: 'forsystemvms' }
+          dataIndex: 'forsystemvms'
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          key: 'actions',
+          title: this.$t('label.actions')
         }
       ]
     }
diff --git a/ui/src/views/infra/network/IpRangesTabPublic.vue b/ui/src/views/infra/network/IpRangesTabPublic.vue
index 247a8fa..c5505da 100644
--- a/ui/src/views/infra/network/IpRangesTabPublic.vue
+++ b/ui/src/views/infra/network/IpRangesTabPublic.vue
@@ -34,58 +34,60 @@
       :rowKey="record => record.id"
       :pagination="false"
     >
-      <template #gateway="{record}">
-        {{ record.gateway || record.ip6gateway }}
-      </template>
-      <template #cidr="{record}">
-        {{ record.cidr || record.ip6cidr }}
-      </template>
-      <template #startip="{record}">
-        {{ record.startip || record.startipv6 }}
-      </template>
-      <template #endip="{record}">
-        {{ record.endip || record.endipv6 }}
-      </template>
-      <template #account="{record}" v-if="!basicGuestNetwork">
-        <a-button @click="() => handleOpenAccountModal(record)">{{ `[${record.domain}] ${record.account === undefined ? '' : record.account}` }}</a-button>
-      </template>
-      <template #actions="{record}">
-        <div
-          class="actions"
-          style="text-align: right" >
-          <tooltip-button
-            v-if="record.account === 'system' && !basicGuestNetwork && record.gateway && !record.ip6gateway"
-            tooltipPlacement="bottom"
-            :tooltip="$t('label.add.account')"
-            icon="user-add-outlined"
-            @onClick="() => handleOpenAddAccountModal(record)"
-            :disabled="!('dedicatePublicIpRange' in $store.getters.apis)" />
-          <tooltip-button
-            v-if="record.account !== 'system' && !basicGuestNetwork"
-            tooltipPlacement="bottom"
-            :tooltip="$t('label.release.account')"
-            icon="user-delete-outlined"
-            type="primary"
-            :danger="true"
-            @onClick="() => handleRemoveAccount(record.id)"
-            :disabled="!('releasePublicIpRange' in $store.getters.apis)" />
-          <tooltip-button
-            tooltipPlacement="bottom"
-            :tooltip="$t('label.update.ip.range')"
-            icon="edit-outlined"
-            type="primary"
-            :danger="true"
-            @onClick="() => handleUpdateIpRangeModal(record)"
-            :disabled="!('updateVlanIpRange' in $store.getters.apis)" />
-          <tooltip-button
-            tooltipPlacement="bottom"
-            :tooltip="$t('label.remove.ip.range')"
-            icon="delete-outlined"
-            type="primary"
-            :danger="true"
-            @onClick="handleDeleteIpRange(record.id)"
-            :disabled="!('deleteVlanIpRange' in $store.getters.apis)" />
-        </div>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'gateway'">
+          {{ record.gateway || record.ip6gateway }}
+        </template>
+        <template v-if="column.key === 'cidr'">
+          {{ record.cidr || record.ip6cidr }}
+        </template>
+        <template v-if="column.key === 'startip'">
+          {{ record.startip || record.startipv6 }}
+        </template>
+        <template v-if="column.key === 'endip'">
+          {{ record.endip || record.endipv6 }}
+        </template>
+        <template v-if="column.key === 'account' && !basicGuestNetwork">
+          <a-button @click="() => handleOpenAccountModal(record)">{{ `[${record.domain}] ${record.account === undefined ? '' : record.account}` }}</a-button>
+        </template>
+        <template v-if="column.key === 'actions'">
+          <div
+            class="actions"
+            style="text-align: right" >
+            <tooltip-button
+              v-if="record.account === 'system' && !basicGuestNetwork && record.gateway && !record.ip6gateway"
+              tooltipPlacement="bottom"
+              :tooltip="$t('label.add.account')"
+              icon="user-add-outlined"
+              @onClick="() => handleOpenAddAccountModal(record)"
+              :disabled="!('dedicatePublicIpRange' in $store.getters.apis)" />
+            <tooltip-button
+              v-if="record.account !== 'system' && !basicGuestNetwork"
+              tooltipPlacement="bottom"
+              :tooltip="$t('label.release.account')"
+              icon="user-delete-outlined"
+              type="primary"
+              :danger="true"
+              @onClick="() => handleRemoveAccount(record.id)"
+              :disabled="!('releasePublicIpRange' in $store.getters.apis)" />
+            <tooltip-button
+              tooltipPlacement="bottom"
+              :tooltip="$t('label.update.ip.range')"
+              icon="edit-outlined"
+              type="primary"
+              :danger="true"
+              @onClick="() => handleUpdateIpRangeModal(record)"
+              :disabled="!('updateVlanIpRange' in $store.getters.apis)" />
+            <tooltip-button
+              tooltipPlacement="bottom"
+              :tooltip="$t('label.remove.ip.range')"
+              icon="delete-outlined"
+              type="primary"
+              :danger="true"
+              @onClick="handleDeleteIpRange(record.id)"
+              :disabled="!('deleteVlanIpRange' in $store.getters.apis)" />
+          </div>
+        </template>
       </template>
     </a-table>
     <a-pagination
@@ -152,12 +154,13 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option
               v-for="domain in domains"
               :key="domain.id"
-              :value="domain.id">{{ domain.path || domain.name || domain.description }}
+              :value="domain.id"
+              :label="domain.path || domain.name || domain.description">{{ domain.path || domain.name || domain.description }}
             </a-select-option>
           </a-select>
         </div>
@@ -205,10 +208,10 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             v-focus="true">
-            <a-select-option v-for="pod in pods" :key="pod.id" :value="pod.id">{{ pod.name }}</a-select-option>
+            <a-select-option v-for="pod in pods" :key="pod.id" :value="pod.id" :label="pod.name">{{ pod.name }}</a-select-option>
           </a-select>
         </a-form-item>
         <a-form-item name="vlan" ref="vlan" :label="$t('label.vlan')" class="form__item" v-if="!basicGuestNetwork">
@@ -255,12 +258,13 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }" >
                 <a-select-option
                   v-for="domain in domains"
                   :key="domain.id"
-                  :value="domain.id">{{ domain.path || domain.name || domain.description }}
+                  :value="domain.id"
+                  :label="domain.path || domain.name || domain.description">{{ domain.path || domain.name || domain.description }}
                 </a-select-option>
               </a-select>
             </a-form-item>
@@ -377,28 +381,28 @@
       pageSize: 10,
       columns: [
         {
-          title: this.$t('label.gateway'),
-          slots: { customRender: 'gateway' }
+          key: 'gateway',
+          title: this.$t('label.gateway')
         },
         {
-          title: this.$t('label.cidr'),
-          slots: { customRender: 'cidr' }
+          key: 'cidr',
+          title: this.$t('label.cidr')
         },
         {
           title: this.$t('label.vlan'),
           dataIndex: 'vlan'
         },
         {
-          title: this.$t('label.startip'),
-          slots: { customRender: 'startip' }
+          key: 'startip',
+          title: this.$t('label.startip')
         },
         {
-          title: this.$t('label.endip'),
-          slots: { customRender: 'endip' }
+          key: 'endip',
+          title: this.$t('label.endip')
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          key: 'actions',
+          title: this.$t('label.actions')
         }
       ]
     }
@@ -409,8 +413,8 @@
     if (!this.basicGuestNetwork) {
       this.columns.splice(6, 0,
         {
-          title: this.$t('label.account'),
-          slots: { customRender: 'account' }
+          key: 'account',
+          title: this.$t('label.account')
         }
       )
     } else {
diff --git a/ui/src/views/infra/network/IpRangesTabStorage.vue b/ui/src/views/infra/network/IpRangesTabStorage.vue
index 29e146d..c8665d6 100644
--- a/ui/src/views/infra/network/IpRangesTabStorage.vue
+++ b/ui/src/views/infra/network/IpRangesTabStorage.vue
@@ -34,17 +34,19 @@
       :rowKey="record => record.id"
       :pagination="false"
     >
-      <template #name="{record}">
-        <div>{{ returnPodName(record.podid) }}</div>
-      </template>
-      <template #actions="{record}">
-        <tooltip-button
-          :tooltip="$t('label.remove.ip.range')"
-          :disabled="!('deleteStorageNetworkIpRange' in $store.getters.apis)"
-          icon="delete-outlined"
-          type="primary"
-          :danger="true"
-          @onClick="handleDeleteIpRange(record.id)" />
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'name'">
+          <div>{{ returnPodName(record.podid) }}</div>
+        </template>
+        <template v-if="column.key === 'actions'">
+          <tooltip-button
+            :tooltip="$t('label.remove.ip.range')"
+            :disabled="!('deleteStorageNetworkIpRange' in $store.getters.apis)"
+            icon="delete-outlined"
+            type="primary"
+            :danger="true"
+            @onClick="handleDeleteIpRange(record.id)" />
+        </template>
       </template>
     </a-table>
     <a-pagination
@@ -88,9 +90,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option v-for="pod in pods" :key="pod.id" :value="pod.id">{{ pod.name }}</a-select-option>
+            <a-select-option v-for="pod in pods" :key="pod.id" :value="pod.id" :label="pod.name">{{ pod.name }}</a-select-option>
           </a-select>
         </a-form-item>
         <a-form-item name="gateway" ref="gateway" :label="$t('label.gateway')" class="form__item">
@@ -151,8 +153,8 @@
       defaultSelectedPod: null,
       columns: [
         {
-          title: this.$t('label.podid'),
-          slots: { customRender: 'name' }
+          key: 'name',
+          title: this.$t('label.podid')
         },
         {
           title: this.$t('label.gateway'),
@@ -175,8 +177,8 @@
           dataIndex: 'endip'
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          key: 'actions',
+          title: this.$t('label.actions')
         }
       ],
       page: 1,
diff --git a/ui/src/views/infra/network/ServiceProvidersTab.vue b/ui/src/views/infra/network/ServiceProvidersTab.vue
index 184804e..4985389 100644
--- a/ui/src/views/infra/network/ServiceProvidersTab.vue
+++ b/ui/src/views/infra/network/ServiceProvidersTab.vue
@@ -27,8 +27,10 @@
           v-for="item in hardcodedNsps"
           :key="item.title">
           <template #tab>
-            {{ $t(item.title) }}
-            <status :text="item.title in nsps ? nsps[item.title].state : $t('label.disabled')" style="margin-bottom: 6px; margin-left: 6px" />
+            <span>
+              {{ $t(item.title) }}
+              <status :text="item.title in nsps ? nsps[item.title].state : $t('label.disabled')" style="margin-bottom: 6px; margin-left: 6px" />
+            </span>
           </template>
           <provider-item
             v-if="tabKey===item.title"
@@ -109,11 +111,12 @@
                 showSearch
                 optionFilterProp="label"
                 :filterOption="(input, option) => {
-                  return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                 }" >
                 <a-select-option
                   v-for="(opt, idx) in field.opts"
-                  :key="idx">{{ opt.name || opt.description }}</a-select-option>
+                  :key="idx"
+                  :label="opt.name || opt.description">{{ opt.name || opt.description }}</a-select-option>
               </a-select>
             </span>
             <span v-else>
@@ -356,7 +359,7 @@
                   value: (record) => { return record.physicalnetworkid }
                 }
               },
-              columns: ['hostname', 'action']
+              columns: ['hostname', 'actions']
             }
           ]
         },
@@ -415,7 +418,7 @@
                   value: (record) => { return record.physicalnetworkid }
                 }
               },
-              columns: ['hostname', 'action']
+              columns: ['hostname', 'actions']
             }
           ]
         },
@@ -496,7 +499,7 @@
                   value: (record) => { return record.physicalnetworkid }
                 }
               },
-              columns: ['hostname', 'insideportprofile', 'action']
+              columns: ['hostname', 'insideportprofile', 'actions']
             }
           ]
         },
@@ -587,7 +590,7 @@
                   value: (record) => { return record.physicalnetworkid }
                 }
               },
-              columns: ['ipaddress', 'lbdevicestate', 'action']
+              columns: ['ipaddress', 'lbdevicestate', 'actions']
             }
           ]
         },
@@ -737,7 +740,7 @@
                   value: (record) => { return record.physicalnetworkid }
                 }
               },
-              columns: ['ipaddress', 'lbdevicestate', 'action']
+              columns: ['ipaddress', 'lbdevicestate', 'actions']
             }
           ]
         },
@@ -796,7 +799,7 @@
                   value: (record) => { return record.physicalnetworkid }
                 }
               },
-              columns: ['hostname', 'transportzoneuuid', 'l3gatewayserviceuuid', 'l2gatewayserviceuuid', 'action']
+              columns: ['hostname', 'transportzoneuuid', 'l3gatewayserviceuuid', 'l2gatewayserviceuuid', 'actions']
             }
           ]
         },
@@ -855,7 +858,7 @@
                   value: (record) => { return record.physicalnetworkid }
                 }
               },
-              columns: ['name', 'url', 'username', 'action']
+              columns: ['name', 'url', 'username', 'actions']
             }
           ]
         },
@@ -871,7 +874,7 @@
                   value: (record) => { return record.id }
                 }
               },
-              columns: ['account', 'domain', 'enabled', 'project', 'action']
+              columns: ['account', 'domain', 'enabled', 'project', 'actions']
             }
           ]
         },
@@ -930,7 +933,7 @@
                   value: (record) => { return record.physicalnetworkid }
                 }
               },
-              columns: ['ipaddress', 'fwdevicestate', 'type', 'action']
+              columns: ['ipaddress', 'fwdevicestate', 'type', 'actions']
             }
           ]
         },
@@ -1364,5 +1367,15 @@
       }
     }
   }
+
+  &-tab {
+    justify-content: end;
+  }
+
+  &-tab-btn {
+    span {
+      display: flex;
+    }
+  }
 }
 </style>
diff --git a/ui/src/views/infra/network/providers/AddF5LoadBalancer.vue b/ui/src/views/infra/network/providers/AddF5LoadBalancer.vue
index fa1173a..7fd7f03 100644
--- a/ui/src/views/infra/network/providers/AddF5LoadBalancer.vue
+++ b/ui/src/views/infra/network/providers/AddF5LoadBalancer.vue
@@ -61,11 +61,12 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
               <a-select-option
                 v-for="opt in networkDeviceType"
-                :key="opt.id">{{ $t(opt.description) }}</a-select-option>
+                :key="opt.id"
+                :label="$t(opt.description)">{{ $t(opt.description) }}</a-select-option>
             </a-select>
           </a-form-item>
         </a-col>
diff --git a/ui/src/views/infra/network/providers/AddNetscalerLoadBalancer.vue b/ui/src/views/infra/network/providers/AddNetscalerLoadBalancer.vue
index a89990c..e3a051d 100644
--- a/ui/src/views/infra/network/providers/AddNetscalerLoadBalancer.vue
+++ b/ui/src/views/infra/network/providers/AddNetscalerLoadBalancer.vue
@@ -61,11 +61,12 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
               <a-select-option
                 v-for="opt in networkDeviceType"
-                :key="opt.id">{{ $t(opt.description) }}</a-select-option>
+                :key="opt.id"
+                :label="$t(opt.description)">{{ $t(opt.description) }}</a-select-option>
             </a-select>
           </a-form-item>
         </a-col>
diff --git a/ui/src/views/infra/network/providers/AddPaloAltoFirewall.vue b/ui/src/views/infra/network/providers/AddPaloAltoFirewall.vue
index 545c32c..1dd9150 100644
--- a/ui/src/views/infra/network/providers/AddPaloAltoFirewall.vue
+++ b/ui/src/views/infra/network/providers/AddPaloAltoFirewall.vue
@@ -61,11 +61,12 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
               <a-select-option
                 v-for="opt in networkDeviceType"
-                :key="opt.id">{{ $t(opt.description) }}</a-select-option>
+                :key="opt.id"
+                :label="$t(opt.description)">{{ $t(opt.description) }}</a-select-option>
             </a-select>
           </a-form-item>
         </a-col>
diff --git a/ui/src/views/infra/network/providers/ProviderItem.vue b/ui/src/views/infra/network/providers/ProviderItem.vue
index 69d0d1b..125455b 100644
--- a/ui/src/views/infra/network/providers/ProviderItem.vue
+++ b/ui/src/views/infra/network/providers/ProviderItem.vue
@@ -154,25 +154,25 @@
       params.pageSize = this.pageSize
 
       let length = args.columns.length
-      if (args.columns.includes('action')) {
+      if (args.columns.includes('actions')) {
         length--
       }
       const columns = args.columns.map(col => {
-        if (col === 'action') {
+        if (col === 'actions') {
           return {
+            key: col,
             title: this.$t('label.' + col),
             dataIndex: col,
             width: 80,
-            fixed: 'right',
-            slots: { customRender: col }
+            fixed: 'right'
           }
         }
         const width = 100 / (length) + '%'
         return {
+          key: col,
           title: this.$t('label.' + col),
           width: width,
-          dataIndex: col,
-          slots: { customRender: col }
+          dataIndex: col
         }
       })
 
diff --git a/ui/src/views/infra/network/providers/ProviderListView.vue b/ui/src/views/infra/network/providers/ProviderListView.vue
index baa6517..6c107e6 100644
--- a/ui/src/views/infra/network/providers/ProviderListView.vue
+++ b/ui/src/views/infra/network/providers/ProviderListView.vue
@@ -28,69 +28,73 @@
       :rowKey="record => record.id || record.name || record.nvpdeviceid || record.resourceid"
       :pagination="false"
       :scroll="scrollable">
-      <template #name="{text, record}">
-        <span v-if="record.role==='VIRTUAL_ROUTER'">
-          <router-link :to="{ path: '/router' + '/' + record.id }" v-if="record.id">{{ text }}</router-link>
-          <label v-else>{{ text }}</label>
-        </span>
-        <span v-else>{{ text }}</span>
-      </template>
-      <template #hostname="{text, record}">
-        <span v-if="record.role==='VIRTUAL_ROUTER'">
-          <router-link :to="{ path: '/host' + '/' + record.hostid }" v-if="record.hostid">{{ text }}</router-link>
-          <label v-else>{{ text }}</label>
-        </span>
-        <span v-else>{{ text }}</span>
-      </template>
-      <template #zonename="{text, record}">
-        <span v-if="record.role==='VIRTUAL_ROUTER'">
-          <router-link :to="{ path: '/zone' + '/' + record.zoneid }" v-if="record.zoneid">{{ text }}</router-link>
-          <label v-else>{{ text }}</label>
-        </span>
-        <span v-else>{{ text }}</span>
-      </template>
-      <template #action="{record}">
-        <a-tooltip placement="top">
-          <template #title>
-            <span v-if="resource.name==='BigSwitchBcf'">{{ $t('label.delete.bigswitchbcf') }}</span>
-            <span v-else-if="resource.name==='BrocadeVcs'">{{ $t('label.delete.brocadevcs') }}</span>
-            <span v-else-if="resource.name==='NiciraNvp'">{{ $t('label.delete.niciranvp') }}</span>
-            <span v-else-if="resource.name==='Netscaler'">{{ $t('label.delete.netscaler') }}</span>
-            <span v-else-if="resource.name==='Opendaylight'">{{ $t('label.delete.opendaylight.device') }}</span>
-            <span v-else-if="resource.name==='PaloAlto'">{{ $t('label.delete.pa') }}</span>
-            <span v-else-if="resource.name==='CiscoVnmc' && title==='listCiscoVnmcResources'">
-              {{ $t('label.delete.ciscovnmc.resource') }}
-            </span>
-            <span v-else-if="resource.name==='CiscoVnmc' && title==='listCiscoAsa1000vResources'">
-              {{ $t('label.delete.ciscoasa1000v') }}
-            </span>
-          </template>
-          <tooltip-button
-            v-if="resource.name==='Ovs'"
-            :tooltip="$t('label.configure')"
-            icon="setting-outlined"
-            size="small"
-            :loading="actionLoading"
-            @onClick="onConfigureOvs(record)"/>
-          <tooltip-button
-            v-else
-            :tooltip="$t('label.delete')"
-            type="primary"
-            :danger="true"
-            icon="close-outlined"
-            size="small"
-            :loading="actionLoading"
-            @onClick="onDelete(record)"/>
-        </a-tooltip>
-      </template>
-      <template #lbdevicestate="{text}">
-        <status :text="text ? text : ''" displayText />
-      </template>
-      <template #status="{text}">
-        <status :text="text ? text : ''" displayText />
-      </template>
-      <template #state="{text}">
-        <status :text="text ? text : ''" displayText />
+      <template #bodyCell="{ column, text, record }">
+        <template v-if="column.key === 'name'">
+          <span v-if="record.role==='VIRTUAL_ROUTER'">
+            <router-link :to="{ path: '/router' + '/' + record.id }" v-if="record.id">{{ text }}</router-link>
+            <label v-else>{{ text }}</label>
+          </span>
+          <span v-else>{{ text }}</span>
+        </template>
+        <template v-if="column.key === 'hostname'">
+          <span v-if="record.role==='VIRTUAL_ROUTER'">
+            <router-link :to="{ path: '/host' + '/' + record.hostid }" v-if="record.hostid">{{ text }}</router-link>
+            <label v-else>{{ text }}</label>
+          </span>
+          <span v-else>{{ text }}</span>
+        </template>
+        <template v-if="column.key === 'zonename'">
+          <span v-if="record.role==='VIRTUAL_ROUTER'">
+            <router-link :to="{ path: '/zone' + '/' + record.zoneid }" v-if="record.zoneid">{{ text }}</router-link>
+            <label v-else>{{ text }}</label>
+          </span>
+          <span v-else>{{ text }}</span>
+        </template>
+        <template v-if="column.key === 'actions'">
+          <a-tooltip placement="top">
+            <template #title>
+              <span v-if="resource.name==='BigSwitchBcf'">{{ $t('label.delete.bigswitchbcf') }}</span>
+              <span v-else-if="resource.name==='BrocadeVcs'">{{ $t('label.delete.brocadevcs') }}</span>
+              <span v-else-if="resource.name==='NiciraNvp'">{{ $t('label.delete.niciranvp') }}</span>
+              <span v-else-if="resource.name==='F5BigIp'">{{ $t('label.delete.f5') }}</span>
+              <span v-else-if="resource.name==='JuniperSRX'">{{ $t('label.delete.srx') }}</span>
+              <span v-else-if="resource.name==='Netscaler'">{{ $t('label.delete.netscaler') }}</span>
+              <span v-else-if="resource.name==='Opendaylight'">{{ $t('label.delete.opendaylight.device') }}</span>
+              <span v-else-if="resource.name==='PaloAlto'">{{ $t('label.delete.pa') }}</span>
+              <span v-else-if="resource.name==='CiscoVnmc' && title==='listCiscoVnmcResources'">
+                {{ $t('label.delete.ciscovnmc.resource') }}
+              </span>
+              <span v-else-if="resource.name==='CiscoVnmc' && title==='listCiscoAsa1000vResources'">
+                {{ $t('label.delete.ciscoasa1000v') }}
+              </span>
+            </template>
+            <tooltip-button
+              v-if="resource.name==='Ovs'"
+              :tooltip="$t('label.configure')"
+              icon="setting-outlined"
+              size="small"
+              :loading="actionLoading"
+              @onClick="onConfigureOvs(record)"/>
+            <tooltip-button
+              v-else
+              :tooltip="$t('label.delete')"
+              type="primary"
+              :danger="true"
+              icon="close-outlined"
+              size="small"
+              :loading="actionLoading"
+              @onClick="onDelete(record)"/>
+          </a-tooltip>
+        </template>
+        <template v-if="column.key === 'lbdevicestate'">
+          <status :text="text ? text : ''" displayText />
+        </template>
+        <template v-if="column.key === 'status'">
+          <status :text="text ? text : ''" displayText />
+        </template>
+        <template v-if="column.key === 'state'">
+          <status :text="text ? text : ''" displayText />
+        </template>
       </template>
     </a-table>
     <a-pagination
diff --git a/ui/src/views/infra/routers/RouterHealthCheck.vue b/ui/src/views/infra/routers/RouterHealthCheck.vue
index abadc12..a6f54f7 100644
--- a/ui/src/views/infra/routers/RouterHealthCheck.vue
+++ b/ui/src/views/infra/routers/RouterHealthCheck.vue
@@ -33,8 +33,10 @@
         :pagination="false"
         :rowKey="record => record.checkname"
         size="large">
-        <template #status="{record}">
-          <status class="status" :text="record.success === true ? 'True' : 'False'" displayText />
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.key === 'status'">
+            <status class="status" :text="record.success === true ? 'True' : 'False'" displayText />
+          </template>
         </template>
       </a-table>
 
@@ -110,8 +112,8 @@
           dataIndex: 'checktype'
         },
         {
-          title: this.$t('label.router.health.check.success'),
-          slots: { customRender: 'status' }
+          key: 'status',
+          title: this.$t('label.router.health.check.success')
         },
         {
           title: this.$t('label.router.health.check.last.updated'),
diff --git a/ui/src/views/infra/zone/IpAddressRangeForm.vue b/ui/src/views/infra/zone/IpAddressRangeForm.vue
index b851ad9..2233295 100644
--- a/ui/src/views/infra/zone/IpAddressRangeForm.vue
+++ b/ui/src/views/infra/zone/IpAddressRangeForm.vue
@@ -30,13 +30,15 @@
         :columns="columns"
         :pagination="false"
         style="margin-bottom: 24px; width: 100%" >
-        <template #actions="{ record }">
-          <tooltip-button
-            :tooltip="$t('label.delete')"
-            type="primary"
-            :danger="true"
-            icon="delete-outlined"
-            @onClick="onDelete(record.key)" />
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.key === 'actions'">
+            <tooltip-button
+              :tooltip="$t('label.delete')"
+              type="primary"
+              :danger="true"
+              icon="delete-outlined"
+              @onClick="onDelete(record.key)" />
+          </template>
         </template>
         <template #footer>
           <a-form
@@ -193,9 +195,9 @@
           width: 140
         },
         {
+          key: 'actions',
           title: '',
           dataIndex: 'actions',
-          slots: { customRender: 'actions' },
           width: 70
         }
       ],
diff --git a/ui/src/views/infra/zone/StaticInputsForm.vue b/ui/src/views/infra/zone/StaticInputsForm.vue
index e917ad9..77f509a 100644
--- a/ui/src/views/infra/zone/StaticInputsForm.vue
+++ b/ui/src/views/infra/zone/StaticInputsForm.vue
@@ -46,12 +46,13 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option
               v-for="option in field.options"
               :key="option.id"
               :value="option.id"
+              :label="option.name || option.description"
             >
               {{ option.name || option.description }}
             </a-select-option>
diff --git a/ui/src/views/infra/zone/ZoneWizardPhysicalNetworkSetupStep.vue b/ui/src/views/infra/zone/ZoneWizardPhysicalNetworkSetupStep.vue
index 97871d3..e424ddc 100644
--- a/ui/src/views/infra/zone/ZoneWizardPhysicalNetworkSetupStep.vue
+++ b/ui/src/views/infra/zone/ZoneWizardPhysicalNetworkSetupStep.vue
@@ -29,118 +29,120 @@
       :columns="columns"
       :pagination="false"
       style="margin-bottom: 24px; width: 100%">
-      <template #name="{ text, record, index }">
-        <a-input
-          :disabled="tungstenNetworkIndex > -1 && tungstenNetworkIndex !== index"
-          :value="text"
-          @change="e => onCellChange(record.key, 'name', e.target.value)"
-          v-focus="true">
-          <template #suffix>
-            <a-tooltip
-              v-if="tungstenNetworkIndex > -1 && tungstenNetworkIndex !== index"
-              :title="$t('message.no.support.tungsten.fabric')">
-              <warning-outlined style="color: #f5222d" />
-            </a-tooltip>
-          </template>
-        </a-input>
-      </template>
-      <template #isolationMethod="{ text, record, index }">
-        <a-select
-          :disabled="tungstenNetworkIndex > -1 && tungstenNetworkIndex !== index"
-          style="width: 100%"
-          :defaultValue="text"
-          @change="value => onCellChange(record.key, 'isolationMethod', value)"
-          showSearch
-          optionFilterProp="label"
-          :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-          }" >
-          <a-select-option value="VLAN"> VLAN </a-select-option>
-          <a-select-option value="VXLAN"> VXLAN </a-select-option>
-          <a-select-option value="GRE"> GRE </a-select-option>
-          <a-select-option value="STT"> STT </a-select-option>
-          <a-select-option value="BCF_SEGMENT"> BCF_SEGMENT </a-select-option>
-          <a-select-option value="ODL"> ODL </a-select-option>
-          <a-select-option value="L3VPN"> L3VPN </a-select-option>
-          <a-select-option value="VSP"> VSP </a-select-option>
-          <a-select-option value="VCS"> VCS </a-select-option>
-          <a-select-option value="TF"> TF </a-select-option>
+      <template #bodyCell="{ column, text, record, index }">
+        <template v-if="column.key === 'name'">
+          <a-input
+            :disabled="tungstenNetworkIndex > -1 && tungstenNetworkIndex !== index"
+            :value="text"
+            @change="e => onCellChange(record.key, 'name', e.target.value)"
+            v-focus="true">
+            <template #suffix>
+              <a-tooltip
+                v-if="tungstenNetworkIndex > -1 && tungstenNetworkIndex !== index"
+                :title="$t('message.no.support.tungsten.fabric')">
+                <warning-outlined style="color: #f5222d" />
+              </a-tooltip>
+            </template>
+          </a-input>
+        </template>
+        <template v-if="column.key === 'isolationMethod'">
+          <a-select
+            :disabled="tungstenNetworkIndex > -1 && tungstenNetworkIndex !== index"
+            style="width: 100%"
+            :defaultValue="text"
+            @change="value => onCellChange(record.key, 'isolationMethod', value)"
+            showSearch
+            optionFilterProp="value"
+            :filterOption="(input, option) => {
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            }" >
+            <a-select-option value="VLAN"> VLAN </a-select-option>
+            <a-select-option value="VXLAN"> VXLAN </a-select-option>
+            <a-select-option value="GRE"> GRE </a-select-option>
+            <a-select-option value="STT"> STT </a-select-option>
+            <a-select-option value="BCF_SEGMENT"> BCF_SEGMENT </a-select-option>
+            <a-select-option value="ODL"> ODL </a-select-option>
+            <a-select-option value="L3VPN"> L3VPN </a-select-option>
+            <a-select-option value="VSP"> VSP </a-select-option>
+            <a-select-option value="VCS"> VCS </a-select-option>
+            <a-select-option value="TF"> TF </a-select-option>
 
-          <template #suffixIcon>
-            <a-tooltip
-              v-if="tungstenNetworkIndex > -1 && tungstenNetworkIndex !== index"
-              :title="$t('message.no.support.tungsten.fabric')">
-              <warning-outlined style="color: #f5222d" />
-            </a-tooltip>
-          </template>
-        </a-select>
-      </template>
-      <template #traffics="{ record, index }">
-        <div v-for="traffic in record.traffics" :key="traffic.type">
-          <a-tag
-            :color="trafficColors[traffic.type]"
-            style="margin:2px"
-          >
-            {{ traffic.type.toUpperCase() }}
-            <edit-outlined class="traffic-type-action" @click="editTraffic(record.key, traffic, $event)"/>
-            <delete-outlined class="traffic-type-action" @click="deleteTraffic(record.key, traffic, $event)"/>
-          </a-tag>
-        </div>
-        <div v-if="isShowAddTraffic(record.traffics, index)">
-          <div class="traffic-select-item" v-if="addingTrafficForKey === record.key">
-            <a-select
-              :defaultValue="trafficLabelSelected"
-              @change="val => { trafficLabelSelected = val }"
-              style="min-width: 120px;"
-              showSearch
-              optionFilterProp="label"
-              :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-              }" >
-              <a-select-option
-                v-for="(traffic, idx) in availableTrafficToAdd"
-                :value="traffic"
-                :key="idx"
-                :disabled="isDisabledTraffic(record.traffics, traffic)"
-              >
-                {{ traffic.toUpperCase() }}
-              </a-select-option>
-            </a-select>
-            <tooltip-button
-              :tooltip="$t('label.add')"
-              buttonClass="icon-button"
-              icon="plus-outlined"
-              size="small"
-              @onClick="trafficAdded" />
-            <tooltip-button
-              :tooltip="$t('label.cancel')"
-              buttonClass="icon-button"
-              type="primary"
-              :danger="true"
-              icon="close-outlined"
-              size="small"
-              @onClick="() => { addingTrafficForKey = null }" />
+            <template #suffixIcon>
+              <a-tooltip
+                v-if="tungstenNetworkIndex > -1 && tungstenNetworkIndex !== index"
+                :title="$t('message.no.support.tungsten.fabric')">
+                <warning-outlined style="color: #f5222d" />
+              </a-tooltip>
+            </template>
+          </a-select>
+        </template>
+        <template v-if="column.key === 'traffics'">
+          <div v-for="traffic in record.traffics" :key="traffic.type">
+            <a-tag
+              :color="trafficColors[traffic.type]"
+              style="margin:2px"
+            >
+              {{ traffic.type.toUpperCase() }}
+              <edit-outlined class="traffic-type-action" @click="editTraffic(record.key, traffic, $event)"/>
+              <delete-outlined class="traffic-type-action" @click="deleteTraffic(record.key, traffic, $event)"/>
+            </a-tag>
           </div>
-          <a-tag
-            key="addingTraffic"
-            style="margin:2px;"
-            v-else
-          >
-            <a @click="addingTraffic(record.key, record.traffics)">
-              <plus-outlined />
-              {{ $t('label.add.traffic') }}
-            </a>
-          </a-tag>
-        </div>
-      </template>
-      <template #actions="{ record, index }">
-        <tooltip-button
-          :tooltip="$t('label.delete')"
-          v-if="tungstenNetworkIndex === -1 ? index > 0 : tungstenNetworkIndex !== index"
-          type="primary"
-          :danger="true"
-          icon="delete-outlined"
-          @onClick="onDelete(record)" />
+          <div v-if="isShowAddTraffic(record.traffics, index)">
+            <div class="traffic-select-item" v-if="addingTrafficForKey === record.key">
+              <a-select
+                :defaultValue="trafficLabelSelected"
+                @change="val => { trafficLabelSelected = val }"
+                style="min-width: 120px;"
+                showSearch
+                optionFilterProp="value"
+                :filterOption="(input, option) => {
+                  return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                }" >
+                <a-select-option
+                  v-for="(traffic, index) in availableTrafficToAdd"
+                  :value="traffic"
+                  :key="index"
+                  :disabled="isDisabledTraffic(record.traffics, traffic)"
+                >
+                  {{ traffic.toUpperCase() }}
+                </a-select-option>
+              </a-select>
+              <tooltip-button
+                :tooltip="$t('label.add')"
+                buttonClass="icon-button"
+                icon="plus-outlined"
+                size="small"
+                @onClick="trafficAdded" />
+              <tooltip-button
+                :tooltip="$t('label.cancel')"
+                buttonClass="icon-button"
+                type="primary"
+                :danger="true"
+                icon="close-outlined"
+                size="small"
+                @onClick="() => { addingTrafficForKey = null }" />
+            </div>
+            <a-tag
+              key="addingTraffic"
+              style="margin:2px;"
+              v-else
+            >
+              <a @click="addingTraffic(record.key, record.traffics)">
+                <plus-outlined />
+                {{ $t('label.add.traffic') }}
+              </a>
+            </a-tag>
+          </div>
+        </template>
+        <template v-if="column.key === 'actions'">
+          <tooltip-button
+            :tooltip="$t('label.delete')"
+            v-if="tungstenNetworkIndex === -1 ? index > 0 : tungstenNetworkIndex !== index"
+            type="primary"
+            :danger="true"
+            icon="delete-outlined"
+            @onClick="onDelete(record)" />
+        </template>
       </template>
       <template #footer v-if="isAdvancedZone">
         <a-button
@@ -219,11 +221,17 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
-              <a-select-option value="nexusdvs">{{ $t('label.vswitch.type.nexusdvs') }}</a-select-option>
-              <a-select-option value="vmwaresvs">{{ $t('label.vswitch.type.vmwaresvs') }}</a-select-option>
-              <a-select-option value="vmwaredvs">{{ $t('label.vswitch.type.vmwaredvs') }}</a-select-option>
+              <a-select-option
+                value="nexusdvs"
+                :label="$t('label.vswitch.type.nexusdvs')">{{ $t('label.vswitch.type.nexusdvs') }}</a-select-option>
+              <a-select-option
+                value="vmwaresvs"
+                :label="$t('label.vswitch.type.vmwaresvs')">{{ $t('label.vswitch.type.vmwaresvs') }}</a-select-option>
+              <a-select-option
+                value="vmwaredvs"
+                :label="$t('label.vswitch.type.vmwaredvs')">{{ $t('label.vswitch.type.vmwaredvs') }}</a-select-option>
             </a-select>
           </a-form-item>
         </span>
@@ -290,29 +298,28 @@
     columns () {
       const columns = []
       columns.push({
+        key: 'name',
         title: this.$t('label.network.name'),
         dataIndex: 'name',
-        width: 175,
-        slots: { customRender: 'name' }
+        width: 175
       })
       columns.push({
+        key: 'isolationMethod',
         title: this.$t('label.isolation.method'),
         dataIndex: 'isolationMethod',
-        width: 150,
-        slots: { customRender: 'isolationMethod' }
+        width: 150
       })
       columns.push({
-        title: this.$t('label.traffic.types'),
         key: 'traffics',
+        title: this.$t('label.traffic.types'),
         dataIndex: 'traffics',
-        width: 250,
-        slots: { customRender: 'traffics' }
+        width: 250
       })
       if (this.isAdvancedZone) {
         columns.push({
+          key: 'actions',
           title: '',
           dataIndex: 'actions',
-          slots: { customRender: 'actions' },
           width: 70
         })
       }
diff --git a/ui/src/views/infra/zone/ZoneWizardZoneDetailsStep.vue b/ui/src/views/infra/zone/ZoneWizardZoneDetailsStep.vue
index 42e30a7..8aea3ff 100644
--- a/ui/src/views/infra/zone/ZoneWizardZoneDetailsStep.vue
+++ b/ui/src/views/infra/zone/ZoneWizardZoneDetailsStep.vue
@@ -121,9 +121,9 @@
           :loading="hypervisors === null"
           :disabled="this.isEdgeZone"
           showSearch
-          optionFilterProp="label"
+          optionFilterProp="value"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
           <a-select-option v-for="hypervisor in hypervisors" :key="hypervisor.name">
             {{ hypervisor.name }}
@@ -145,11 +145,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option
               v-for="networkOffering in availableNetworkOfferings"
-              :key="networkOffering.id">
+              :key="networkOffering.id"
+              :label="networkOffering.displaytext || networkOffering.name || networkOffering.description">
               {{ networkOffering.displaytext || networkOffering.name || networkOffering.description }}
             </a-select-option>
           </a-select>
@@ -193,9 +194,9 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
-          <a-select-option v-for="dom in domains" :key="dom.id">
+          <a-select-option v-for="dom in domains" :key="dom.id" :label="dom.path">
             {{ dom.path }}
           </a-select-option>
         </a-select>
diff --git a/ui/src/views/network/AclListRulesTab.vue b/ui/src/views/network/AclListRulesTab.vue
index 36f10e9..6675500 100644
--- a/ui/src/views/network/AclListRulesTab.vue
+++ b/ui/src/views/network/AclListRulesTab.vue
@@ -40,7 +40,6 @@
         handle=".drag-handle"
         animation="200"
         ghostClass="drag-ghost"
-        tag="transition-group"
         :component-data="{type: 'transition'}"
         item-key="id">
         <template #item="{element}">
@@ -182,10 +181,10 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="allow">{{ $t('label.allow') }}</a-select-option>
-            <a-select-option value="deny">{{ $t('label.deny') }}</a-select-option>
+            <a-select-option value="allow" :label="$t('label.allow')">{{ $t('label.allow') }}</a-select-option>
+            <a-select-option value="deny" :label="$t('label.deny')">{{ $t('label.deny') }}</a-select-option>
           </a-select>
         </a-form-item>
         <a-form-item :label="$t('label.protocol')" ref="protocol" name="protocol">
@@ -194,13 +193,13 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="tcp">{{ capitalise($t('label.tcp')) }}</a-select-option>
-            <a-select-option value="udp">{{ capitalise($t('label.udp')) }}</a-select-option>
-            <a-select-option value="icmp">{{ capitalise($t('label.icmp')) }}</a-select-option>
-            <a-select-option value="all">{{ $t('label.all') }}</a-select-option>
-            <a-select-option value="protocolnumber">{{ $t('label.protocol.number') }}</a-select-option>
+            <a-select-option value="tcp" :label="$t('label.tcp')">{{ capitalise($t('label.tcp')) }}</a-select-option>
+            <a-select-option value="udp" :label="$t('label.udp')">{{ capitalise($t('label.udp')) }}</a-select-option>
+            <a-select-option value="icmp" :label="$t('label.icmp')">{{ capitalise($t('label.icmp')) }}</a-select-option>
+            <a-select-option value="all" :label="$t('label.all')">{{ $t('label.all') }}</a-select-option>
+            <a-select-option value="protocolnumber" :label="$t('label.protocol.number')">{{ $t('label.protocol.number') }}</a-select-option>
           </a-select>
         </a-form-item>
 
@@ -236,10 +235,10 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="ingress">{{ $t('label.ingress') }}</a-select-option>
-            <a-select-option value="egress">{{ $t('label.egress') }}</a-select-option>
+            <a-select-option value="ingress" :label="$t('label.ingress')">{{ $t('label.ingress') }}</a-select-option>
+            <a-select-option value="egress" :label="$t('label.egress')">{{ $t('label.egress') }}</a-select-option>
           </a-select>
         </a-form-item>
         <a-form-item :label="$t('label.description')" ref="reason" name="reason">
diff --git a/ui/src/views/network/CreateIsolatedNetworkForm.vue b/ui/src/views/network/CreateIsolatedNetworkForm.vue
index 21ab5e3..046510d 100644
--- a/ui/src/views/network/CreateIsolatedNetworkForm.vue
+++ b/ui/src/views/network/CreateIsolatedNetworkForm.vue
@@ -75,12 +75,12 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="domainLoading"
               :placeholder="apiParams.domainid.description"
               @change="val => { handleDomainChange(domains[val]) }">
-              <a-select-option v-for="(opt, optIndex) in domains" :key="optIndex">
+              <a-select-option v-for="(opt, optIndex) in domains" :key="optIndex" :label="opt.path || opt.name || opt.description">
                 {{ opt.path || opt.name || opt.description }}
               </a-select-option>
             </a-select>
@@ -124,12 +124,12 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="networkOfferingLoading"
               :placeholder="apiParams.networkofferingid.description"
               @change="val => { handleNetworkOfferingChange(networkOfferings[val]) }">
-              <a-select-option v-for="(opt, optIndex) in networkOfferings" :key="optIndex">
+              <a-select-option v-for="(opt, optIndex) in networkOfferings" :key="optIndex" :label="opt.displaytext || opt.name || opt.description">
                 {{ opt.displaytext || opt.name || opt.description }}
               </a-select-option>
             </a-select>
@@ -189,12 +189,12 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="vpcLoading"
               :placeholder="apiParams.vpcid.description"
               @change="val => { selectedVpc = vpcs[val] }">
-              <a-select-option v-for="(opt, optIndex) in vpcs" :key="optIndex">
+              <a-select-option v-for="(opt, optIndex) in vpcs" :key="optIndex" :label="opt.name || opt.description">
                 {{ opt.name || opt.description }}
               </a-select-option>
             </a-select>
@@ -291,6 +291,36 @@
               </a-col>
             </a-row>
           </div>
+          <a-form-item v-if="selectedNetworkOfferingSupportsSourceNat" name="sourcenatipaddress" ref="sourcenatipaddress">
+            <template #label>
+              <tooltip-label :title="$t('label.routerip')" :tooltip="apiParams.sourcenatipaddress.description"/>
+            </template>
+            <a-input
+              v-model:value="form.sourcenatipaddress"
+              :placeholder="apiParams.sourcenatipaddress.description"/>
+          </a-form-item>
+          <a-form-item
+            ref="networkdomain"
+            name="networkdomain"
+            v-if="!isObjectEmpty(selectedNetworkOffering) && !selectedNetworkOffering.forvpc">
+            <template #label>
+              <tooltip-label :title="$t('label.networkdomain')" :tooltip="apiParams.networkdomain.description"/>
+            </template>
+            <a-input
+             v-model:value="form.networkdomain"
+              :placeholder="apiParams.networkdomain.description"/>
+          </a-form-item>
+          <a-form-item
+            ref="account"
+            name="account"
+            v-if="accountVisible">
+            <template #label>
+              <tooltip-label :title="$t('label.account')" :tooltip="apiParams.account.description"/>
+            </template>
+            <a-input
+             v-model:value="form.account"
+              :placeholder="apiParams.account.description"/>
+          </a-form-item>
           <div :span="24" class="action-button">
             <a-button
               :loading="actionLoading"
@@ -397,6 +427,14 @@
         return dnsServices && dnsServices.length === 1
       }
       return false
+    },
+    selectedNetworkOfferingSupportsSourceNat () {
+      if (this.selectedNetworkOffering) {
+        const services = this.selectedNetworkOffering?.service || []
+        const sourcenatService = services.filter(service => service.name === 'SourceNat')
+        return sourcenatService && sourcenatService.length === 1
+      }
+      return false
     }
   },
   methods: {
@@ -596,7 +634,7 @@
           displayText: values.displaytext,
           networkOfferingId: this.selectedNetworkOffering.id
         }
-        var usefulFields = ['gateway', 'netmask', 'startip', 'endip', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'externalid', 'vlan', 'networkdomain']
+        var usefulFields = ['gateway', 'netmask', 'startip', 'startipv4', 'endip', 'endipv4', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'sourcenatipaddress', 'externalid', 'vpcid', 'vlan', 'networkdomain']
         for (var field of usefulFields) {
           if (this.isValidTextValueForKey(values, field)) {
             params[field] = values[field]
diff --git a/ui/src/views/network/CreateL2NetworkForm.vue b/ui/src/views/network/CreateL2NetworkForm.vue
index b5f5763..76695eb 100644
--- a/ui/src/views/network/CreateL2NetworkForm.vue
+++ b/ui/src/views/network/CreateL2NetworkForm.vue
@@ -117,12 +117,12 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="networkOfferingLoading"
               :placeholder="apiParams.networkofferingid.description"
               @change="val => { handleNetworkOfferingChange(networkOfferings[val]) }">
-              <a-select-option v-for="(opt, optIndex) in networkOfferings" :key="optIndex">
+              <a-select-option v-for="(opt, optIndex) in networkOfferings" :key="optIndex" :label="opt.displaytext || opt.name || opt.description">
                 {{ opt.displaytext || opt.name || opt.description }}
               </a-select-option>
             </a-select>
diff --git a/ui/src/views/network/CreateNetworkPermission.vue b/ui/src/views/network/CreateNetworkPermission.vue
index 8872346..037e91e 100644
--- a/ui/src/views/network/CreateNetworkPermission.vue
+++ b/ui/src/views/network/CreateNetworkPermission.vue
@@ -35,9 +35,9 @@
               :loading="accountLoading"
               :placeholder="apiParams.accountids.description"
               showSearch
-              optionFilterProp="children"
+              optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
               <a-select-option v-for="(opt, optIndex) in accounts" :key="optIndex" :label="opt.name || opt.description">
                 <span>
@@ -58,9 +58,9 @@
               :loading="projectLoading"
               :placeholder="apiParams.projectids.description"
               showSearch
-              optionFilterProp="children"
+              optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
               <a-select-option v-for="(opt, optIndex) in projects" :key="optIndex" :label="opt.name || opt.description">
                 <span>
@@ -131,6 +131,7 @@
   created () {
     this.formRef = ref()
     this.form = reactive({})
+    this.rules = reactive({})
     this.apiParams = this.$getApiParams('createNetworkPermissions')
     this.fetchData()
   },
diff --git a/ui/src/views/network/CreateSharedNetworkForm.vue b/ui/src/views/network/CreateSharedNetworkForm.vue
index 380ced7..93bf693 100644
--- a/ui/src/views/network/CreateSharedNetworkForm.vue
+++ b/ui/src/views/network/CreateSharedNetworkForm.vue
@@ -80,7 +80,7 @@
               :loading="formPhysicalNetworkLoading"
               :placeholder="apiParams.physicalnetworkid.description"
               @change="val => { handlePhysicalNetworkChange(formPhysicalNetworks[val]) }">
-              <a-select-option v-for="(opt, optIndex) in formPhysicalNetworks" :key="optIndex">
+              <a-select-option v-for="(opt, optIndex) in formPhysicalNetworks" :key="optIndex" :label="opt.name || opt.description">
                 {{ opt.name || opt.description }}
               </a-select-option>
             </a-select>
@@ -164,7 +164,7 @@
               :loading="domainLoading"
               :placeholder="apiParams.domainid.description"
               @change="val => { handleDomainChange(domains[val]) }">
-              <a-select-option v-for="(opt, optIndex) in domains" :key="optIndex">
+              <a-select-option v-for="(opt, optIndex) in domains" :key="optIndex" :label="opt.path || opt.name || opt.description">
                 <span>
                   <resource-icon v-if="opt && opt.icon" :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/>
                   <block-outlined v-else style="margin-right: 5px" />
@@ -193,7 +193,7 @@
               :loading="accountLoading"
               :placeholder="apiParams.account.description"
               @change="val => { handleAccountChange(accounts[val]) }">
-              <a-select-option v-for="(opt, optIndex) in accounts" :key="optIndex">
+              <a-select-option v-for="(opt, optIndex) in accounts" :key="optIndex" :label="opt.name || opt.description">
                 <span>
                   <resource-icon v-if="opt && opt.icon" :image="opt.icon.base64image" size="1x" style="margin-right: 5px"/>
                   <user-outlined v-else style="margin-right: 5px" />
@@ -216,7 +216,7 @@
               :loading="projectLoading"
               :placeholder="apiParams.projectid.description"
               @change="val => { handleProjectChange(projects[val]) }">
-              <a-select-option v-for="(opt, optIndex) in projects" :key="optIndex">
+              <a-select-option v-for="(opt, optIndex) in projects" :key="optIndex" :label="opt.name || opt.description">
                 {{ opt.name || opt.description }}
               </a-select-option>
             </a-select>
@@ -235,7 +235,7 @@
               :loading="networkOfferingLoading"
               :placeholder="apiParams.networkofferingid.description"
               @change="val => { handleNetworkOfferingChange(networkOfferings[val]) }">
-              <a-select-option v-for="(opt, optIndex) in networkOfferings" :key="optIndex">
+              <a-select-option v-for="(opt, optIndex) in networkOfferings" :key="optIndex" :label="opt.displaytext || opt.name || opt.description">
                 {{ opt.displaytext || opt.name || opt.description }}
               </a-select-option>
             </a-select>
diff --git a/ui/src/views/network/CreateVlanIpRange.vue b/ui/src/views/network/CreateVlanIpRange.vue
index 96bbc9c..f819c2e 100644
--- a/ui/src/views/network/CreateVlanIpRange.vue
+++ b/ui/src/views/network/CreateVlanIpRange.vue
@@ -35,9 +35,9 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
-              <a-select-option v-for="pod in pods" :key="pod.id" :value="pod.id">{{ pod.name }}</a-select-option>
+              <a-select-option v-for="pod in pods" :key="pod.id" :value="pod.id" :label="pod.name">{{ pod.name }}</a-select-option>
             </a-select>
           </a-form-item>
           <a-form-item name="gateway" ref="gateway">
diff --git a/ui/src/views/network/CreateVpc.vue b/ui/src/views/network/CreateVpc.vue
index fb2d110..363dd44 100644
--- a/ui/src/views/network/CreateVpc.vue
+++ b/ui/src/views/network/CreateVpc.vue
@@ -88,10 +88,10 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             @change="handleVpcOfferingChange" >
-            <a-select-option :value="offering.id" v-for="offering in vpcOfferings" :key="offering.id">
+            <a-select-option :value="offering.id" v-for="offering in vpcOfferings" :key="offering.id" :label="offering.name">
               {{ offering.name }}
             </a-select-option>
           </a-select>
@@ -155,6 +155,14 @@
             </a-form-item>
           </a-col>
         </a-row>
+        <a-form-item v-if="selectedNetworkOfferingSupportsSourceNat" name="sourcenatipaddress" ref="sourcenatipaddress">
+          <template #label>
+            <tooltip-label :title="$t('label.routerip')" :tooltip="apiParams.sourcenatipaddress.description"/>
+          </template>
+          <a-input
+            v-model:value="form.sourcenatipaddress"
+            :placeholder="apiParams.sourcenatipaddress.description"/>
+        </a-form-item>
         <a-form-item name="start" ref="start">
           <template #label>
             <tooltip-label :title="$t('label.start')" :tooltip="apiParams.start.description"/>
@@ -212,6 +220,14 @@
         return dnsServices && dnsServices.length === 1
       }
       return false
+    },
+    selectedNetworkOfferingSupportsSourceNat () {
+      if (this.selectedVpcOffering) {
+        const services = this.selectedVpcOffering?.service || []
+        const sourcenatService = services.filter(service => service.name === 'SourceNat')
+        return sourcenatService && sourcenatService.length === 1
+      }
+      return false
     }
   },
   methods: {
@@ -222,7 +238,6 @@
       })
       this.rules = reactive({
         name: [{ required: true, message: this.$t('message.error.required.input') }],
-        displaytext: [{ required: true, message: this.$t('message.error.required.input') }],
         zoneid: [{ required: true, message: this.$t('label.required') }],
         cidr: [{ required: true, message: this.$t('message.error.required.input') }],
         vpcofferingid: [{ required: true, message: this.$t('label.required') }]
@@ -275,6 +290,10 @@
         this.selectedVpcOffering = this.vpcOfferings[0] || {}
       }).finally(() => {
         this.loadingOffering = false
+        if (this.vpcOfferings.length > 0) {
+          this.form.vpcofferingid = 0
+          this.handleVpcOfferingChange(this.vpcOfferings[0].id)
+        }
       })
     },
     handleVpcOfferingChange (value) {
@@ -285,6 +304,7 @@
       for (var offering of this.vpcOfferings) {
         if (offering.id === value) {
           this.selectedVpcOffering = offering
+          this.form.vpcofferingid = offering.id
           return
         }
       }
diff --git a/ui/src/views/network/CreateVpnCustomerGateway.vue b/ui/src/views/network/CreateVpnCustomerGateway.vue
index b890e29..00b9f3b 100644
--- a/ui/src/views/network/CreateVpnCustomerGateway.vue
+++ b/ui/src/views/network/CreateVpnCustomerGateway.vue
@@ -62,9 +62,9 @@
         <a-select
           v-model:value="form.ikeEncryption"
           showSearch
-          optionFilterProp="label"
+          optionFilterProp="value"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
           <a-select-option :value="algo" v-for="(algo, idx) in encryptionAlgo" :key="idx">
             {{ algo }}
@@ -75,9 +75,9 @@
         <a-select
           v-model:value="form.ikeHash"
           showSearch
-          optionFilterProp="label"
+          optionFilterProp="value"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
           <a-select-option :value="h" v-for="(h, idx) in hash" :key="idx">
             {{ h }}
@@ -91,9 +91,9 @@
         <a-select
           v-model:value="form.ikeversion"
           showSearch
-          optionFilterProp="label"
+          optionFilterProp="value"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
           <a-select-option :value="vers" v-for="(vers, idx) in ikeVersions" :key="idx">
             {{ vers }}
@@ -106,9 +106,13 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
-          <a-select-option :value="DHGroups[group]" v-for="(group, idx) in Object.keys(DHGroups)" :key="idx">
+          <a-select-option
+            :value="DHGroups[group]"
+            v-for="(group, idx) in Object.keys(DHGroups)"
+            :key="idx"
+            :label="group + '(' + DHGroups[group] + ')'">
             <div v-if="group !== ''">
               {{ group+"("+DHGroups[group]+")" }}
             </div>
@@ -119,9 +123,9 @@
         <a-select
           v-model:value="form.espEncryption"
           showSearch
-          optionFilterProp="label"
+          optionFilterProp="value"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
           <a-select-option :value="algo" v-for="(algo, idx) in encryptionAlgo" :key="idx">
             {{ algo }}
@@ -132,9 +136,9 @@
         <a-select
           v-model:value="form.espHash"
           showSearch
-          optionFilterProp="label"
+          optionFilterProp="value"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
           <a-select-option :value="h" v-for="(h, idx) in hash" :key="idx">
             {{ h }}
@@ -147,9 +151,13 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
-          <a-select-option :value="DHGroups[group]" v-for="(group, idx) in Object.keys(DHGroups)" :key="idx">
+          <a-select-option
+            :value="DHGroups[group]"
+            v-for="(group, idx) in Object.keys(DHGroups)"
+            :key="idx"
+            :label="group === '' ? DHGroups[group] : group + '(' + DHGroups[group] + ')'">
             <div v-if="group === ''">
               {{ DHGroups[group] }}
             </div>
diff --git a/ui/src/views/network/EgressRulesTab.vue b/ui/src/views/network/EgressRulesTab.vue
index dcd8054..a0fb708 100644
--- a/ui/src/views/network/EgressRulesTab.vue
+++ b/ui/src/views/network/EgressRulesTab.vue
@@ -45,12 +45,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="tcp">{{ capitalise($t('label.tcp'))  }}</a-select-option>
-            <a-select-option value="udp">{{ capitalise($t('label.udp')) }}</a-select-option>
-            <a-select-option value="icmp">{{ capitalise($t('label.icmp')) }}</a-select-option>
-            <a-select-option value="all">{{ $t('label.all') }}</a-select-option>
+            <a-select-option value="tcp" :label="$t('label.tcp')">{{ capitalise($t('label.tcp'))  }}</a-select-option>
+            <a-select-option value="udp" :label="$t('label.udp')">{{ capitalise($t('label.udp')) }}</a-select-option>
+            <a-select-option value="icmp" :label="$t('label.icmp')">{{ capitalise($t('label.icmp')) }}</a-select-option>
+            <a-select-option value="all" :label="$t('label.all')">{{ $t('label.all') }}</a-select-option>
           </a-select>
         </div>
         <div v-show="newRule.protocol === 'tcp' || newRule.protocol === 'udp'" class="form__item">
@@ -97,23 +97,25 @@
       :pagination="false"
       :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
       :rowKey="record => record.id">
-      <template #protocol="{ record }">
-        {{ getCapitalise(record.protocol) }}
-      </template>
-      <template #startport="{ record }">
-        {{ record.icmptype || record.startport >= 0 ? record.icmptype || record.startport : 'All' }}
-      </template>
-      <template #endport="{ record }">
-        {{ record.icmpcode || record.endport >= 0 ? record.icmpcode || record.endport : 'All' }}
-      </template>
-      <template #actions="{ record }">
-        <tooltip-button
-          :tooltip="$t('label.delete')"
-          :disabled="!('deleteEgressFirewallRule' in $store.getters.apis)"
-          type="primary"
-          :danger="true"
-          icon="delete-outlined"
-          @onClick="deleteRule(record)" />
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'protocol'">
+          {{ getCapitalise(record.protocol) }}
+        </template>
+        <template v-if="column.key === 'startport'">
+          {{ record.icmptype || record.startport >= 0 ? record.icmptype || record.startport : 'All' }}
+        </template>
+        <template v-if="column.key === 'endport'">
+          {{ record.icmpcode || record.endport >= 0 ? record.icmpcode || record.endport : 'All' }}
+        </template>
+        <template v-if="column.key === 'actions'">
+          <tooltip-button
+            :tooltip="$t('label.delete')"
+            :disabled="!('deleteEgressFirewallRule' in $store.getters.apis)"
+            type="primary"
+            :danger="true"
+            icon="delete-outlined"
+            @onClick="deleteRule(record)" />
+        </template>
       </template>
     </a-table>
     <a-pagination
@@ -176,7 +178,7 @@
       showGroupActionModal: false,
       selectedItems: [],
       selectedColumns: [],
-      filterColumns: ['Action'],
+      filterColumns: ['Actions'],
       showConfirmationAction: false,
       message: {
         title: this.$t('label.action.bulk.delete.egress.firewall.rules'),
@@ -207,20 +209,20 @@
           dataIndex: 'destcidrlist'
         },
         {
-          title: this.$t('label.protocol'),
-          slots: { customRender: 'protocol' }
+          key: 'protocol',
+          title: this.$t('label.protocol')
         },
         {
-          title: this.$t('label.icmptype.start.port'),
-          slots: { customRender: 'startport' }
+          key: 'startport',
+          title: this.$t('label.icmptype.start.port')
         },
         {
-          title: this.$t('label.icmpcode.end.port'),
-          slots: { customRender: 'endport' }
+          key: 'endport',
+          title: this.$t('label.icmpcode.end.port')
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          key: 'actions',
+          title: this.$t('label.actions')
         }
       ]
     }
@@ -291,9 +293,9 @@
     deleteRules (e) {
       this.showConfirmationAction = false
       this.selectedColumns.splice(0, 0, {
+        key: 'status',
         dataIndex: 'status',
         title: this.$t('label.operation.status'),
-        slots: { customRender: 'status' },
         filters: [
           { text: 'In Progress', value: 'InProgress' },
           { text: 'Success', value: 'success' },
diff --git a/ui/src/views/network/EnableStaticNat.vue b/ui/src/views/network/EnableStaticNat.vue
index 8def80f..51d3e8f 100644
--- a/ui/src/views/network/EnableStaticNat.vue
+++ b/ui/src/views/network/EnableStaticNat.vue
@@ -27,9 +27,9 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
-          <a-select-option v-for="network in networksList" :key="network.id" :value="network.id">
+          <a-select-option v-for="network in networksList" :key="network.id" :value="network.id" :label="network.name">
             {{ network.name }}
           </a-select-option>
         </a-select>
@@ -52,36 +52,39 @@
       :dataSource="vmsList"
       :pagination="false"
       :rowKey="record => record.id || record.account">
-      <template #name="{ record }">
-        <div>
-          {{ record.name }}
-        </div>
-        <a-select
-          v-if="nicsList.length && selectedVm && selectedVm === record.id"
-          class="nic-select"
-          :defaultValue="selectedNic.ipaddress"
-          showSearch
-          optionFilterProp="label"
-          :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-          }">
-          <a-select-option
-            @click="selectedNic = item"
-            v-for="item in nicsList"
-            :key="item.id">
-            {{ item.ipaddress }}
-          </a-select-option>
-        </a-select>
-      </template>
-      <template #state="{ text }">
-        <status :text="text ? text : ''" displayText />
-      </template>
-      <template #radio="{ text }">
-        <a-radio
-          class="list__radio"
-          :value="text"
-          :checked="selectedVm && selectedVm === text"
-          @change="fetchNics"></a-radio>
+      <template #bodyCell="{ column, text, record }">
+        <template v-if="column.key === 'name'">
+          <div>
+            {{ record.name }}
+          </div>
+          <a-select
+            v-if="nicsList.length && selectedVm && selectedVm === record.id"
+            class="nic-select"
+            :defaultValue="selectedNic.ipaddress"
+            showSearch
+            optionFilterProp="label"
+            :filterOption="(input, option) => {
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            }">
+            <a-select-option
+              @click="selectedNic = item"
+              v-for="item in nicsList"
+              :key="item.id"
+              :label="item.ipaddress">
+              {{ item.ipaddress }}
+            </a-select-option>
+          </a-select>
+        </template>
+        <template v-if="column.key === 'state'">
+          <status :text="text ? text : ''" displayText />
+        </template>
+        <template v-if="column.key === 'radio'">
+          <a-radio
+            class="list__radio"
+            :value="text"
+            :checked="selectedVm && selectedVm === text"
+            @change="fetchNics"></a-radio>
+        </template>
       </template>
     </a-table>
 
@@ -134,14 +137,14 @@
       selectedNic: null,
       columns: [
         {
+          key: 'name',
           title: this.$t('label.name'),
-          slots: { customRender: 'name' },
           width: 200
         },
         {
+          key: 'state',
           title: this.$t('label.state'),
-          dataIndex: 'state',
-          slots: { customRender: 'state' }
+          dataIndex: 'state'
         },
         {
           title: this.$t('label.displayname'),
@@ -156,9 +159,9 @@
           dataIndex: 'zonename'
         },
         {
+          key: 'radio',
           title: this.$t('label.select'),
           dataIndex: 'id',
-          slots: { customRender: 'radio' },
           width: 70
         }
       ],
@@ -188,8 +191,6 @@
         pageSize: this.pageSize,
         listAll: true,
         networkid: this.resource.associatednetworkid,
-        account: this.resource.account,
-        domainid: this.resource.domainid,
         keyword: this.searchQuery
       }).then(response => {
         this.vmCount = response.listvirtualmachinesresponse.count
@@ -207,8 +208,6 @@
         pageSize: this.pageSize,
         listAll: true,
         networkid: e,
-        account: this.resource.account,
-        domainid: this.resource.domainid,
         vpcid: this.resource.vpcid,
         keyword: this.searchQuery
       }).then(response => {
@@ -247,8 +246,7 @@
       this.loading = true
       api('listNetworks', {
         vpcid: this.resource.vpcid,
-        domainid: this.resource.domainid,
-        account: this.resource.account,
+        isrecursive: true,
         supportedservices: 'StaticNat'
       }).then(response => {
         this.networksList = response.listnetworksresponse.network
diff --git a/ui/src/views/network/FirewallRules.vue b/ui/src/views/network/FirewallRules.vue
index 523a632..787f5c2 100644
--- a/ui/src/views/network/FirewallRules.vue
+++ b/ui/src/views/network/FirewallRules.vue
@@ -32,11 +32,11 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="tcp">{{ $t('label.tcp') }}</a-select-option>
-            <a-select-option value="udp">{{ $t('label.udp') }}</a-select-option>
-            <a-select-option value="icmp">{{ $t('label.icmp') }}</a-select-option>
+            <a-select-option value="tcp" :label="$t('label.tcp')">{{ $t('label.tcp') }}</a-select-option>
+            <a-select-option value="udp" :label="$t('label.udp')">{{ $t('label.udp') }}</a-select-option>
+            <a-select-option value="icmp" :label="$t('label.icmp')">{{ $t('label.icmp') }}</a-select-option>
           </a-select>
         </div>
         <div v-show="newRule.protocol === 'tcp' || newRule.protocol === 'udp'" class="form__item">
@@ -80,27 +80,29 @@
       :pagination="false"
       :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
       :rowKey="record => record.id">
-      <template #protocol="{ record }">
-        {{ getCapitalise(record.protocol) }}
-      </template>
-      <template #startport="{ record }">
-        {{ record.icmptype || record.startport >= 0 ? record.icmptype || record.startport : $t('label.all') }}
-      </template>
-      <template #endport="{ record }">
-        {{ record.icmpcode || record.endport >= 0 ? record.icmpcode || record.endport : $t('label.all') }}
-      </template>
-      <template #actions="{ record }">
-        <div class="actions">
-          <tooltip-button :tooltip="$t('label.edit.tags')" icon="tag-outlined" buttonClass="rule-action" @onClick="() => openTagsModal(record.id)" />
-          <tooltip-button
-            :tooltip="$t('label.delete')"
-            type="primary"
-            :danger="true"
-            icon="delete-outlined"
-            buttonClass="rule-action"
-            :disabled="!('deleteFirewallRule' in $store.getters.apis)"
-            @onClick="deleteRule(record)" />
-        </div>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'protocol'">
+          {{ getCapitalise(record.protocol) }}
+        </template>
+        <template v-if="column.key === 'startport'">
+          {{ record.icmptype || record.startport >= 0 ? record.icmptype || record.startport : $t('label.all') }}
+        </template>
+        <template v-if="column.key === 'endport'">
+          {{ record.icmpcode || record.endport >= 0 ? record.icmpcode || record.endport : $t('label.all') }}
+        </template>
+        <template v-if="column.key === 'actions'">
+          <div class="actions">
+            <tooltip-button :tooltip="$t('label.edit.tags')" icon="tag-outlined" buttonClass="rule-action" @onClick="() => openTagsModal(record.id)" />
+            <tooltip-button
+              :tooltip="$t('label.delete')"
+              type="primary"
+              :danger="true"
+              icon="delete-outlined"
+              buttonClass="rule-action"
+              :disabled="!('deleteFirewallRule' in $store.getters.apis)"
+              @onClick="deleteRule(record)" />
+          </div>
+        </template>
       </template>
     </a-table>
     <a-pagination
@@ -218,7 +220,7 @@
       showGroupActionModal: false,
       selectedItems: [],
       selectedColumns: [],
-      filterColumns: ['State', 'Action'],
+      filterColumns: ['State', 'Actions'],
       showConfirmationAction: false,
       message: {
         title: this.$t('label.action.bulk.delete.firewall.rules'),
@@ -248,24 +250,24 @@
           dataIndex: 'cidrlist'
         },
         {
-          title: this.$t('label.protocol'),
-          slots: { customRender: 'protocol' }
+          key: 'protocol',
+          title: this.$t('label.protocol')
         },
         {
-          title: `${this.$t('label.startport')}/${this.$t('label.icmptype')}`,
-          slots: { customRender: 'startport' }
+          key: 'startport',
+          title: `${this.$t('label.startport')}/${this.$t('label.icmptype')}`
         },
         {
-          title: `${this.$t('label.endport')}/${this.$t('label.icmpcode')}`,
-          slots: { customRender: 'endport' }
+          key: 'endport',
+          title: `${this.$t('label.endport')}/${this.$t('label.icmpcode')}`
         },
         {
           title: this.$t('label.state'),
           dataIndex: 'state'
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          key: 'actions',
+          title: this.$t('label.actions')
         }
       ]
     }
@@ -346,9 +348,9 @@
     deleteRules (e) {
       this.showConfirmationAction = false
       this.selectedColumns.splice(0, 0, {
+        key: 'status',
         dataIndex: 'status',
         title: this.$t('label.operation.status'),
-        slots: { customRender: 'status' },
         filters: [
           { text: 'In Progress', value: 'InProgress' },
           { text: 'Success', value: 'success' },
diff --git a/ui/src/views/network/GuestIpRanges.vue b/ui/src/views/network/GuestIpRanges.vue
index 14cd8a1..4c05162 100644
--- a/ui/src/views/network/GuestIpRanges.vue
+++ b/ui/src/views/network/GuestIpRanges.vue
@@ -36,19 +36,21 @@
         :rowKey="item => item.id"
         :pagination="false" >
 
-        <template #action="{ record }">
-          <a-popconfirm
-            :title="$t('message.confirm.remove.ip.range')"
-            @confirm="removeIpRange(record.id)"
-            :okText="$t('label.yes')"
-            :cancelText="$t('label.no')" >
-            <tooltip-button
-              tooltipPlacement="bottom"
-              :tooltip="$t('label.action.delete.ip.range')"
-              type="primary"
-              :danger="true"
-              icon="delete-outlined" />
-          </a-popconfirm>
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.key === 'actions'">
+            <a-popconfirm
+              :title="$t('message.confirm.remove.ip.range')"
+              @confirm="removeIpRange(record.id)"
+              :okText="$t('label.yes')"
+              :cancelText="$t('label.no')" >
+              <tooltip-button
+                tooltipPlacement="bottom"
+                :tooltip="$t('label.action.delete.ip.range')"
+                type="primary"
+                :danger="true"
+                icon="delete-outlined" />
+            </a-popconfirm>
+          </template>
         </template>
 
       </a-table>
@@ -140,8 +142,8 @@
           dataIndex: 'netmask'
         },
         {
-          title: '',
-          slots: { customRender: 'action' }
+          key: 'actions',
+          title: ''
         }
       ]
     }
diff --git a/ui/src/views/network/GuestVlanNetworksTab.vue b/ui/src/views/network/GuestVlanNetworksTab.vue
index 2258eed..657880b 100644
--- a/ui/src/views/network/GuestVlanNetworksTab.vue
+++ b/ui/src/views/network/GuestVlanNetworksTab.vue
@@ -25,13 +25,15 @@
     :pagination="false"
     :loading="fetchLoading"
   >
-    <template #name="{ text, record }">
-      <router-link v-if="record.issystem === false && !record.projectid" :to="{ path: '/guestnetwork/' + record.id }" >{{ text }}</router-link>
-      <router-link v-else-if="record.issystem === false && record.projectid" :to="{ path: '/guestnetwork/' + record.id, query: { projectid: record.projectid}}" >{{ text }}</router-link>
-      <span v-else>{{ text }}</span>
-    </template>
-    <template #state="{ record }">
-      <status :text="record.state" displayText></status>
+    <template #bodyCell="{ column, text, record }">
+      <template v-if="column.key === 'name'">
+        <router-link v-if="record.issystem === false && !record.projectid" :to="{ path: '/guestnetwork/' + record.id }" >{{ text }}</router-link>
+        <router-link v-else-if="record.issystem === false && record.projectid" :to="{ path: '/guestnetwork/' + record.id, query: { projectid: record.projectid}}" >{{ text }}</router-link>
+        <span v-else>{{ text }}</span>
+      </template>
+      <template v-if="column.key === 'state'">
+        <status :text="record.state" displayText></status>
+      </template>
     </template>
   </a-table>
 </template>
@@ -61,17 +63,17 @@
       networks: [],
       columns: [
         {
+          key: 'name',
           title: this.$t('label.name'),
-          dataIndex: 'name',
-          slots: { customRender: 'name' }
+          dataIndex: 'name'
         },
         {
           title: this.$t('label.type'),
           dataIndex: 'type'
         },
         {
-          title: this.$t('label.state'),
-          slots: { customRender: 'state' }
+          key: 'state',
+          title: this.$t('label.state')
         },
         {
           title: this.$t('label.broadcasturi'),
diff --git a/ui/src/views/network/IngressEgressRuleConfigure.vue b/ui/src/views/network/IngressEgressRuleConfigure.vue
index c1e82a8..adf013c 100644
--- a/ui/src/views/network/IngressEgressRuleConfigure.vue
+++ b/ui/src/views/network/IngressEgressRuleConfigure.vue
@@ -38,13 +38,13 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="tcp">{{ capitalise($t('label.tcp')) }}</a-select-option>
-            <a-select-option value="udp">{{ capitalise($t('label.udp')) }}</a-select-option>
-            <a-select-option value="icmp">{{ capitalise($t('label.icmp')) }}</a-select-option>
-            <a-select-option value="all">{{ capitalise($t('label.all')) }}</a-select-option>
-            <a-select-option value="protocolnumber">{{ capitalise($t('label.protocol.number')) }}</a-select-option>
+            <a-select-option value="tcp" :label="$t('label.tcp')">{{ capitalise($t('label.tcp')) }}</a-select-option>
+            <a-select-option value="udp" :label="$t('label.udp')">{{ capitalise($t('label.udp')) }}</a-select-option>
+            <a-select-option value="icmp" :label="$t('label.icmp')">{{ capitalise($t('label.icmp')) }}</a-select-option>
+            <a-select-option value="all" :label="$t('label.all')">{{ capitalise($t('label.all')) }}</a-select-option>
+            <a-select-option value="protocolnumber" :label="$t('label.protocol.number')">{{ capitalise($t('label.protocol.number')) }}</a-select-option>
           </a-select>
         </div>
         <div v-show="newRule.protocol === 'tcp' || newRule.protocol === 'udp'" class="form__item">
@@ -94,38 +94,40 @@
       :dataSource="rules"
       :pagination="{ pageSizeOptions: ['10', '20', '40', '80', '100', '200'], showSizeChanger: true}"
       :rowKey="record => record.ruleid">
-      <template #protocol="{ record }">
-        {{ getCapitalise(record.protocol) }}
-      </template>
-      <template #account="{ record }">
-        <div v-if="record.account && record.securitygroupname">
-          {{ record.account }} - {{ record.securitygroupname }}
-        </div>
-      </template>
-      <template #startport="{text, record}">
-        <div v-if="!['tcp', 'udp', 'icmp'].includes(record.protocol)">{{ $t('label.all') }}</div>
-        <div v-else>{{ text }}</div>
-      </template>
-      <template #endport="{text, record}">
-        <div v-if="!['tcp', 'udp', 'icmp'].includes(record.protocol)">{{ $t('label.all') }}</div>
-        <div v-else>{{ text }}</div>
-      </template>
-      <template #actions="{ record }">
-        <tooltip-button :tooltip="$t('label.edit.tags')" icon="tag-outlined" buttonClass="rule-action" @onClick="() => openTagsModal(record)" />
-        <a-popconfirm
-          :title="$t('label.delete') + '?'"
-          @confirm="handleDeleteRule(record)"
-          :okText="$t('label.yes')"
-          :cancelText="$t('label.no')"
-        >
-          <tooltip-button
-            :disabled="!('revokeSecurityGroupIngress' in $store.getters.apis) && !('revokeSecurityGroupEgress' in $store.getters.apis)"
-            :tooltip="$t('label.delete')"
-            type="primary"
-            :danger="true"
-            icon="delete-outlined"
-            buttonClass="rule-action" />
-        </a-popconfirm>
+      <template #bodyCell="{ column, text, record }">
+        <template v-if="column.key === 'protocol'">
+          {{ getCapitalise(record.protocol) }}
+        </template>
+        <template v-if="column.key === 'account'">
+          <div v-if="record.account && record.securitygroupname">
+            {{ record.account }} - {{ record.securitygroupname }}
+          </div>
+        </template>
+        <template v-if="column.key === 'startport'">
+          <div v-if="!['tcp', 'udp', 'icmp'].includes(record.protocol)">{{ $t('label.all') }}</div>
+          <div v-else>{{ text }}</div>
+        </template>
+        <template v-if="column.key === 'endport'">
+          <div v-if="!['tcp', 'udp', 'icmp'].includes(record.protocol)">{{ $t('label.all') }}</div>
+          <div v-else>{{ text }}</div>
+        </template>
+        <template v-if="column.key === 'actions'">
+          <tooltip-button :tooltip="$t('label.edit.tags')" icon="tag-outlined" buttonClass="rule-action" @onClick="() => openTagsModal(record)" />
+          <a-popconfirm
+            :title="$t('label.delete') + '?'"
+            @confirm="handleDeleteRule(record)"
+            :okText="$t('label.yes')"
+            :cancelText="$t('label.no')"
+          >
+            <tooltip-button
+              :disabled="!('revokeSecurityGroupIngress' in $store.getters.apis) && !('revokeSecurityGroupEgress' in $store.getters.apis)"
+              :tooltip="$t('label.delete')"
+              type="primary"
+              :danger="true"
+              icon="delete-outlined"
+              buttonClass="rule-action" />
+          </a-popconfirm>
+        </template>
       </template>
     </a-table>
 
@@ -223,18 +225,18 @@
       pagesize: 10,
       columns: [
         {
-          title: this.$t('label.protocol'),
-          slots: { customRender: 'protocol' }
+          key: 'protocol',
+          title: this.$t('label.protocol')
         },
         {
+          key: 'startport',
           title: this.$t('label.startport'),
-          dataIndex: 'startport',
-          slots: { customRender: 'startport' }
+          dataIndex: 'startport'
         },
         {
+          key: 'endport',
           title: this.$t('label.endport'),
-          dataIndex: 'endport',
-          slots: { customRender: 'endport' }
+          dataIndex: 'endport'
         },
         {
           title: this.$t('label.icmptype'),
@@ -249,12 +251,12 @@
           dataIndex: 'cidr'
         },
         {
-          title: this.$t('label.account.and.security.group'),
-          slots: { customRender: 'account' }
+          key: 'account',
+          title: this.$t('label.account.and.security.group')
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          key: 'actions',
+          title: this.$t('label.actions')
         }
       ],
       isSubmitted: false
@@ -464,7 +466,6 @@
     },
     openTagsModal (rule) {
       this.selectedRule = rule
-      this.initForm()
       this.fetchTags(this.selectedRule)
       this.tagsModalVisible = true
     },
diff --git a/ui/src/views/network/InternalLBAssignVmForm.vue b/ui/src/views/network/InternalLBAssignVmForm.vue
index 2e48689..8eb030c 100644
--- a/ui/src/views/network/InternalLBAssignVmForm.vue
+++ b/ui/src/views/network/InternalLBAssignVmForm.vue
@@ -40,14 +40,19 @@
               v-focus="!addVmModalNicLoading && iLb.virtualmachineid[index] === vm.id && index === 0"
               v-else-if="!addVmModalNicLoading && iLb.virtualmachineid[index] === vm.id"
               mode="multiple"
+              style="min-width: 200px;"
               v-model:value="iLb.vmguestip[index]"
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
-              <a-select-option v-for="(nic, nicIndex) in nics[index]" :key="nic" :value="nic">
-                {{ nic }}{{ nicIndex === 0 ? ` (${this.$t('label.primary')})` : null }}
+              <a-select-option
+                v-for="(nic, nicIndex) in nics[index]"
+                :key="nic"
+                :value="nic"
+                :label="nic">
+                {{ nic }}{{ nicIndex === 0 ? ` (${this.$t('label.primary')})` : '' }}
               </a-select-option>
             </a-select>
           </span>
diff --git a/ui/src/views/network/InternalLBAssignedVmTab.vue b/ui/src/views/network/InternalLBAssignedVmTab.vue
index 67211f0..035af0e 100644
--- a/ui/src/views/network/InternalLBAssignedVmTab.vue
+++ b/ui/src/views/network/InternalLBAssignedVmTab.vue
@@ -25,23 +25,25 @@
       :rowKey="item => item.id"
       :pagination="false"
     >
-      <template #displayname="{ record }">
-        <router-link :to="{ path: '/vm/' + record.id }">{{ record.displayname || record.name }}</router-link>
-      </template>
-      <template #ipaddress="{ record }">
-        <span v-for="nic in record.nic" :key="nic.id">
-          <span v-if="nic.networkid === resource.networkid">
-            {{ nic.ipaddress }} <br/>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'displayname'">
+          <router-link :to="{ path: '/vm/' + record.id }">{{ record.displayname || record.name }}</router-link>
+        </template>
+        <template v-if="column.key === 'ipaddress'">
+          <span v-for="nic in record.nic" :key="nic.id">
+            <span v-if="nic.networkid === resource.networkid">
+              {{ nic.ipaddress }} <br/>
+            </span>
           </span>
-        </span>
-      </template>
-      <template #remove="{ record }">
-        <tooltip-button
-          :tooltip="$t('label.remove.vm.from.lb')"
-          type="primary"
-          :danger="true"
-          icon="delete-outlined"
-          @onClick="removeVmFromLB(record)" />
+        </template>
+        <template v-if="column.key === 'remove'">
+          <tooltip-button
+            :tooltip="$t('label.remove.vm.from.lb')"
+            type="primary"
+            :danger="true"
+            icon="delete-outlined"
+            @onClick="removeVmFromLB(record)" />
+        </template>
       </template>
       <a-divider />
     </a-table>
@@ -86,18 +88,18 @@
       totalInstances: 0,
       columns: [
         {
+          key: 'displayname',
           title: this.$t('label.name'),
-          dataIndex: 'displayname',
-          slots: { customRender: 'displayname' }
+          dataIndex: 'displayname'
         },
         {
+          key: 'ipaddress',
           title: this.$t('label.ipaddress'),
-          dataIndex: 'ipaddress',
-          slots: { customRender: 'ipaddress' }
+          dataIndex: 'ipaddress'
         },
         {
-          title: '',
-          slots: { customRender: 'remove' }
+          key: 'remove',
+          title: ''
         }
       ]
     }
diff --git a/ui/src/views/network/IpAddressesTab.vue b/ui/src/views/network/IpAddressesTab.vue
index bc61d65..8b22ec6 100644
--- a/ui/src/views/network/IpAddressesTab.vue
+++ b/ui/src/views/network/IpAddressesTab.vue
@@ -47,12 +47,12 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
           <a-select-option key="all" value="">
             {{ $t('label.view.all') }}
           </a-select-option>
-          <a-select-option v-for="network in networksList" :key="network.id" :value="network.id">
+          <a-select-option v-for="network in networksList" :key="network.id" :value="network.id" :label="network.name">
             {{ network.name }}
           </a-select-option>
         </a-select>
@@ -65,35 +65,57 @@
         :rowKey="item => item.id"
         :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
         :pagination="false" >
-        <template #ipaddress="{ text, record }">
-          <router-link v-if="record.forvirtualnetwork === true" :to="{ path: '/publicip/' + record.id }" >{{ text }} </router-link>
-          <div v-else>{{ text }}</div>
-          <a-tag v-if="record.issourcenat === true">source-nat</a-tag>
-        </template>
+        <template #bodyCell="{ column, text, record }">
+          <template v-if="column.key === 'ipaddress'">
+            <router-link v-if="record.forvirtualnetwork === true" :to="{ path: '/publicip/' + record.id }" >{{ text }}&nbsp;</router-link>
+            <div v-else>{{ text }}</div>
+            <template v-if="record.issourcenat === true">
+              <a-tag>{{ $t('label.sourcenat') }}</a-tag>
+            </template>
+            <template v-else-if="record.isstaticnat === true">
+              <a-tag>{{ $t('label.staticnat') }}</a-tag>
+            </template>
+            <template v-else-if="record.hasrules === false">
+              <tooltip-button
+                v-if="record.forvirtualnetwork === true"
+                :tooltip="$t('label.action.set.as.source.nat.ip')"
+                type="primary"
+                :danger="false"
+                icon="aim-outlined"
+                :disabled="!('updateNetwork' in $store.getters.apis)"
+                @onClick="showChangeSourceNat(record)"></tooltip-button>
+            </template>
+            <template v-else><!-- -if="record.hasrules === true" -->
+              <Tooltip placement="topLeft" :title="$t('message.sourcenatip.change.inhibited')" >
+                <a-tag>{{ $t('label.hasrules') }}</a-tag>
+              </Tooltip>
+            </template>
+          </template>
 
-        <template #state="{ record }">
-          <status :text="record.state" displayText />
-        </template>
+          <template v-if="column.key === 'state'">
+            <status :text="record.state" displayText />
+          </template>
 
-        <template #virtualmachineid="{ record }">
-          <desktop-outlined v-if="record.virtualmachineid" />
-          <router-link :to="{ path: '/vm/' + record.virtualmachineid }" > {{ record.virtualmachinename || record.virtualmachineid }} </router-link>
-        </template>
+          <template v-if="column.key === 'virtualmachineid'">
+            <desktop-outlined v-if="record.virtualmachineid" />
+            <router-link :to="{ path: getVmRouteUsingType(record) + record.virtualmachineid }" > {{ record.virtualmachinename || record.virtualmachineid }} </router-link>
+          </template>
 
-        <template #associatednetworkname="{ record }">
-          <router-link v-if="record.forvirtualnetwork === true" :to="{ path: '/guestnetwork/' + record.associatednetworkid }" > {{ record.associatednetworkname || record.associatednetworkid }} </router-link>
-          <div v-else>{{ record.networkname }}</div>
-        </template>
+          <template v-if="column.key === 'associatednetworkname'">
+            <router-link v-if="record.forvirtualnetwork === true" :to="{ path: '/guestnetwork/' + record.associatednetworkid }" > {{ record.associatednetworkname || record.associatednetworkid }} </router-link>
+            <div v-else>{{ record.networkname }}</div>
+          </template>
 
-        <template #action="{ record }">
-          <tooltip-button
-            v-if="record.issourcenat !== true && record.forvirtualnetwork === true"
-            :tooltip="$t('label.action.release.ip')"
-            type="primary"
-            :danger="true"
-            icon="delete-outlined"
-            :disabled="!('disassociateIpAddress' in $store.getters.apis)"
-            @onClick="releaseIpAddress(record)" />
+          <template v-if="column.key === 'actions'">
+            <tooltip-button
+              v-if="record.issourcenat !== true && record.forvirtualnetwork === true"
+              :tooltip="$t('label.action.release.ip')"
+              type="primary"
+              :danger="true"
+              icon="delete-outlined"
+              :disabled="!('disassociateIpAddress' in $store.getters.apis)"
+              @onClick="releaseIpAddress(record)" />
+          </template>
         </template>
       </a-table>
       <a-divider/>
@@ -133,11 +155,12 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
               <a-select-option
                 v-for="ip in listPublicIpAddress"
-                :key="ip.ipaddress">{{ ip.ipaddress }} ({{ ip.state }})</a-select-option>
+                :key="ip.ipaddress"
+                :label="ip.ipaddress + '(' + ip.state + ')'">{{ ip.ipaddress }} ({{ ip.state }})</a-select-option>
             </a-select>
           </a-form-item>
           <div :span="24" class="action-button">
@@ -147,6 +170,24 @@
         </a-form>
       </a-spin>
     </a-modal>
+    <a-modal
+      v-if="changeSourceNat"
+      :title="$t('message.sourcenatip.change.warning')"
+      :visible="changeSourceNat"
+      :closable="true"
+      :footer="null"
+      @cancel="cancelChangeSourceNat"
+      centered
+      :disabled="!('updateNetwork' in $store.getters.apis)"
+      width="450px">
+      <template>
+        <a-alert :message="$t('message.sourcenatip.change.warning')" type="warning" />
+      </template>
+      <div :span="24" class="action-button">
+        <a-button @click="cancelChangeSourceNat">{{ $t('label.cancel') }}</a-button>
+        <a-button ref="submit" type="primary" @click="setSourceNatIp(record)">{{ $t('label.ok') }}</a-button>
+      </div>
+    </a-modal>
     <bulk-action-view
       v-if="showConfirmationAction || showGroupActionModal"
       :showConfirmationAction="showConfirmationAction"
@@ -164,6 +205,7 @@
       @close-modal="closeModal" />
   </div>
 </template>
+
 <script>
 import { api } from '@/api'
 import Status from '@/components/widgets/Status'
@@ -204,7 +246,7 @@
       showGroupActionModal: false,
       selectedItems: [],
       selectedColumns: [],
-      filterColumns: ['Action'],
+      filterColumns: ['Actions'],
       showConfirmationAction: false,
       message: {
         title: this.$t('label.action.bulk.release.public.ip.address'),
@@ -212,34 +254,35 @@
       },
       columns: [
         {
+          key: 'ipaddress',
           title: this.$t('label.ipaddress'),
-          dataIndex: 'ipaddress',
-          slots: { customRender: 'ipaddress' }
+          dataIndex: 'ipaddress'
         },
         {
+          key: 'state',
           title: this.$t('label.state'),
-          dataIndex: 'state',
-          slots: { customRender: 'state' }
+          dataIndex: 'state'
         },
         {
+          key: 'virtualmachineid',
           title: this.$t('label.vm'),
-          dataIndex: 'virtualmachineid',
-          slots: { customRender: 'virtualmachineid' }
+          dataIndex: 'virtualmachineid'
         },
         {
+          key: 'associatednetworkname',
           title: this.$t('label.network'),
-          dataIndex: 'associatednetworkname',
-          slots: { customRender: 'associatednetworkname' }
+          dataIndex: 'associatednetworkname'
         },
         {
-          title: '',
-          slots: { customRender: 'action' }
+          key: 'actions',
+          title: ''
         }
       ],
       showAcquireIp: false,
       acquireLoading: false,
       acquireIp: null,
-      listPublicIpAddress: []
+      listPublicIpAddress: [],
+      changeSourceNat: false
     }
   },
   created () {
@@ -312,6 +355,50 @@
         return selection.indexOf(item.id) !== -1
       }))
     },
+    setSourceNatIp (ipaddress) {
+      if (this.settingsourcenat) return
+      if (this.$route.path.startsWith('/vpc')) {
+        this.updateVpc(ipaddress)
+      } else {
+        this.updateNetwork(ipaddress)
+      }
+    },
+    updateNetwork (ipaddress) {
+      const params = {}
+      params.sourcenatipaddress = this.sourceNatIp.ipaddress
+      params.id = this.resource.id
+      this.settingsourcenat = true
+      api('updateNetwork', params).then(response => {
+        this.fetchData()
+      }).catch(error => {
+        this.$notification.error({
+          message: `${this.$t('label.error')} ${error.response.status}`,
+          description: error.response.data.updatenetworkresponse.errortext || error.response.data.errorresponse.errortext,
+          duration: 0
+        })
+      }).finally(() => {
+        this.settingsourcenat = false
+        this.cancelChangeSourceNat()
+      })
+    },
+    updateVpc (ipaddress) {
+      const params = {}
+      params.sourcenatipaddress = this.sourceNatIp.ipaddress
+      params.id = this.resource.id
+      this.settingsourcenat = true
+      api('updateVPC', params).then(response => {
+        this.fetchData()
+      }).catch(error => {
+        this.$notification.error({
+          message: `${this.$t('label.error')} ${error.response.status}`,
+          description: error.response.data.updatevpcresponse.errortext || error.response.data.errorresponse.errortext,
+          duration: 0
+        })
+      }).finally(() => {
+        this.settingsourcenat = false
+        this.cancelChangeSourceNat()
+      })
+    },
     resetSelection () {
       this.setSelection([])
     },
@@ -385,9 +472,9 @@
     releaseIpAddresses (e) {
       this.showConfirmationAction = false
       this.selectedColumns.splice(0, 0, {
+        key: 'status',
         dataIndex: 'status',
         title: this.$t('label.operation.status'),
-        slots: { customRender: 'status' },
         filters: [
           { text: 'In Progress', value: 'InProgress' },
           { text: 'Success', value: 'success' },
@@ -439,6 +526,14 @@
         })
       })
     },
+    getVmRouteUsingType (record) {
+      switch (record.virtualmachinetype) {
+        case 'DomainRouter' : return '/router/'
+        case 'ConsoleProxy' :
+        case 'SecondaryStorageVm': return '/systemvm/'
+        default: return '/vm/'
+      }
+    },
     async onShowAcquireIp () {
       this.showAcquireIp = true
       this.acquireLoading = true
@@ -471,6 +566,13 @@
     },
     closeModal () {
       this.showConfirmationAction = false
+    },
+    showChangeSourceNat (ipaddress) {
+      this.changeSourceNat = true
+      this.sourceNatIp = ipaddress
+    },
+    cancelChangeSourceNat () {
+      this.changeSourceNat = false
     }
   }
 }
diff --git a/ui/src/views/network/Ipv6FirewallRulesTab.vue b/ui/src/views/network/Ipv6FirewallRulesTab.vue
index cacaaf2..ffdcc9d 100644
--- a/ui/src/views/network/Ipv6FirewallRulesTab.vue
+++ b/ui/src/views/network/Ipv6FirewallRulesTab.vue
@@ -41,13 +41,13 @@
           <a-select
             v-model:value="newRule.traffictype"
             showSearch
-            optionFilterProp="children"
+            optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             @change="val => { handleTrafficTypeChange(val) }" >
-            <a-select-option value="ingress">{{ $t('label.ingress') }}</a-select-option>
-            <a-select-option value="egress">{{ $t('label.egress') }}</a-select-option>
+            <a-select-option value="ingress" :label="$t('label.ingress')">{{ $t('label.ingress') }}</a-select-option>
+            <a-select-option value="egress" :label="$t('label.egress')">{{ $t('label.egress') }}</a-select-option>
           </a-select>
         </div>
         <div class="form__item">
@@ -57,11 +57,11 @@
             style="width: 100%;"
             @change="resetRulePorts"
             showSearch
-            optionFilterProp="children"
+            optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option v-for="opt in protocols" :key="opt">
+            <a-select-option v-for="opt in protocols" :key="opt" :label="$t('label.' + opt)">
               {{ $t('label.' + opt) }}
             </a-select-option>
           </a-select>
@@ -107,27 +107,29 @@
       :pagination="false"
       :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
       :rowKey="record => record.id">
-      <template #traffictype="{record}">
-        {{ record.traffictype }}
-      </template>
-      <template #protocol="{record}">
-        {{ capitalise(record.protocol) }}
-      </template>
-      <template #startport="{record}">
-        {{ record.icmptype || record.startport >= 0 ? record.icmptype || record.startport : 'All' }}
-      </template>
-      <template #endport="{record}">
-        {{ record.icmpcode || record.endport >= 0 ? record.icmpcode || record.endport : 'All' }}
-      </template>
-      <template #actions="{record}">
-        <tooltip-button
-          :tooltip="$t('label.delete')"
-          :disabled="!('deleteIpv6FirewallRule' in $store.getters.apis)"
-          type="primary"
-          :danger="true"
-          icon="delete-outlined"
-          buttonClass="rule-action"
-          @click="deleteRule(record)" />
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'traffictype'">
+          {{ record.traffictype }}
+        </template>
+        <template v-if="column.key === 'protocol'">
+          {{ capitalise(record.protocol) }}
+        </template>
+        <template v-if="column.key === 'startport'">
+          {{ record.icmptype || record.startport >= 0 ? record.icmptype || record.startport : 'All' }}
+        </template>
+        <template v-if="column.key === 'endport'">
+          {{ record.icmpcode || record.endport >= 0 ? record.icmpcode || record.endport : 'All' }}
+        </template>
+        <template v-if="column.key === 'actions'">
+          <tooltip-button
+            :tooltip="$t('label.delete')"
+            :disabled="!('deleteIpv6FirewallRule' in $store.getters.apis)"
+            type="primary"
+            :danger="true"
+            icon="delete-outlined"
+            buttonClass="rule-action"
+            @click="deleteRule(record)" />
+        </template>
       </template>
     </a-table>
     <a-pagination
@@ -190,7 +192,7 @@
       showGroupActionModal: false,
       selectedItems: [],
       selectedColumns: [],
-      filterColumns: ['Action'],
+      filterColumns: ['Actions'],
       showConfirmationAction: false,
       message: {
         title: this.$t('label.action.bulk.delete.ip.v6.firewall.rules'),
@@ -222,24 +224,24 @@
           dataIndex: 'destcidrlist'
         },
         {
-          title: this.$t('label.traffictype'),
-          slots: { customRender: 'traffictype' }
+          key: 'traffictype',
+          title: this.$t('label.traffictype')
         },
         {
-          title: this.$t('label.protocol'),
-          slots: { customRender: 'protocol' }
+          key: 'protocol',
+          title: this.$t('label.protocol')
         },
         {
-          title: this.$t('label.icmptype.start.port'),
-          slots: { customRender: 'startport' }
+          key: 'startport',
+          title: this.$t('label.icmptype.start.port')
         },
         {
-          title: this.$t('label.icmpcode.end.port'),
-          slots: { customRender: 'endport' }
+          key: 'endport',
+          title: this.$t('label.icmpcode.end.port')
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          key: 'actions',
+          title: this.$t('label.actions')
         }
       ],
       protocols: [
@@ -312,9 +314,9 @@
     deleteRules (e) {
       this.showConfirmationAction = false
       this.selectedColumns.splice(0, 0, {
+        key: 'status',
         dataIndex: 'status',
         title: this.$t('label.operation.status'),
-        slots: { customRender: 'status' },
         filters: [
           { text: 'In Progress', value: 'InProgress' },
           { text: 'Success', value: 'success' },
diff --git a/ui/src/views/network/LoadBalancing.vue b/ui/src/views/network/LoadBalancing.vue
index 90ed4c0..973a624 100644
--- a/ui/src/views/network/LoadBalancing.vue
+++ b/ui/src/views/network/LoadBalancing.vue
@@ -47,11 +47,11 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="roundrobin">{{ $t('label.lb.algorithm.roundrobin') }}</a-select-option>
-            <a-select-option value="leastconn">{{ $t('label.lb.algorithm.leastconn') }}</a-select-option>
-            <a-select-option value="source">{{ $t('label.lb.algorithm.source') }}</a-select-option>
+            <a-select-option value="roundrobin" :label="$t('label.lb.algorithm.roundrobin')">{{ $t('label.lb.algorithm.roundrobin') }}</a-select-option>
+            <a-select-option value="leastconn" :label="$t('label.lb.algorithm.leastconn')">{{ $t('label.lb.algorithm.leastconn') }}</a-select-option>
+            <a-select-option value="source" :label="$t('label.lb.algorithm.source')">{{ $t('label.lb.algorithm.source') }}</a-select-option>
           </a-select>
         </div>
         <div class="form__item">
@@ -62,11 +62,11 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="tcp-proxy">{{ $t('label.tcp.proxy') }}</a-select-option>
-            <a-select-option value="tcp">{{ $t('label.tcp') }}</a-select-option>
-            <a-select-option value="udp">{{ $t('label.udp') }}</a-select-option>
+            <a-select-option value="tcp-proxy" :label="$t('label.tcp.proxy')">{{ $t('label.tcp.proxy') }}</a-select-option>
+            <a-select-option value="tcp" :label="$t('label.tcp')">{{ $t('label.tcp') }}</a-select-option>
+            <a-select-option value="udp" :label="$t('label.udp')">{{ $t('label.udp') }}</a-select-option>
           </a-select>
         </div>
         <div class="form__item">
@@ -76,9 +76,9 @@
             defaultValue="no"
             style="min-width: 100px"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option value="yes">{{ $t('label.yes') }}</a-select-option>
             <a-select-option value="no">{{ $t('label.no') }}</a-select-option>
@@ -118,42 +118,61 @@
       :pagination="false"
       :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
       :rowKey="record => record.id">
-      <template #cidrlist="{ record }">
-        <span style="white-space: pre-line"> {{ record.cidrlist?.replaceAll(" ", "\n") }}</span>
-      </template>
-      <template #algorithm="{ record }">
-        {{ returnAlgorithmName(record.algorithm) }}
-      </template>
-      <template #protocol="{record}">
-        {{ getCapitalise(record.protocol) }}
-      </template>
-      <template #stickiness="{record}">
-        <a-button @click="() => openStickinessModal(record.id)">
-          {{ returnStickinessLabel(record.id) }}
-        </a-button>
-      </template>
-      <template #autoscale="{record}">
-        <div>
-          <router-link :to="{ path: '/autoscalevmgroup/' + record.autoscalevmgroup.id }" v-if='record.autoscalevmgroup'>
-            <a-button>{{ $t('label.view') }}</a-button>
-          </router-link>
-          <router-link :to="{ path: '/action/createAutoScaleVmGroup', query: { networkid: record.networkid, lbruleid : record.id } }" v-else-if='!record.ruleInstances'>
-            <a-button>{{ $t('label.new') }}</a-button>
-          </router-link>
-        </div>
-      </template>
-      <template #healthmonitor="{ record }">
-        <a-button @click="() => openHealthMonitorModal(record.id)">
-          {{ returnHealthMonitorLabel(record.id) }}
-        </a-button>
-      </template>
-      <template #add="{record}">
-        <a-button type="primary" @click="() => { selectedRule = record; handleOpenAddVMModal() }" v-if='!record.autoscalevmgroup'>
-          <template #icon>
-            <plus-outlined />
-          </template>
-          {{ $t('label.add') }}
-        </a-button>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'cidrlist'">
+          <span style="white-space: pre-line"> {{ record.cidrlist?.replaceAll(" ", "\n") }}</span>
+        </template>
+        <template v-if="column.key === 'algorithm'">
+          {{ returnAlgorithmName(record.algorithm) }}
+        </template>
+        <template v-if="column.key === 'protocol'">
+          {{ getCapitalise(record.protocol) }}
+        </template>
+        <template v-if="column.key === 'stickiness'">
+          <a-button @click="() => openStickinessModal(record.id)">
+            {{ returnStickinessLabel(record.id) }}
+          </a-button>
+        </template>
+        <template v-if="column.key === 'autoscale'">
+          <div>
+            <router-link :to="{ path: '/autoscalevmgroup/' + record.autoscalevmgroup.id }" v-if='record.autoscalevmgroup'>
+              <a-button>{{ $t('label.view') }}</a-button>
+            </router-link>
+            <router-link :to="{ path: '/action/createAutoScaleVmGroup', query: { networkid: record.networkid, lbruleid : record.id } }" v-else-if='!record.ruleInstances'>
+              <a-button>{{ $t('label.new') }}</a-button>
+            </router-link>
+          </div>
+        </template>
+        <template v-if="column.key === 'healthmonitor'">
+          <a-button @click="() => openHealthMonitorModal(record.id)">
+            {{ returnHealthMonitorLabel(record.id) }}
+          </a-button>
+        </template>
+        <template v-if="column.key === 'add'">
+          <a-button v-if="!record.autoscalevmgroup" type="primary" @click="() => { selectedRule = record; handleOpenAddVMModal() }">
+            <template #icon><plus-outlined /></template>
+              {{ $t('label.add') }}
+          </a-button>
+        </template>
+        <template v-if="column.key === 'actions'">
+          <div class="actions">
+            <tooltip-button :tooltip="$t('label.edit')" icon="edit-outlined" @onClick="() => openEditRuleModal(record)" />
+            <tooltip-button :tooltip="$t('label.edit.tags')" :disabled="!('updateLoadBalancerRule' in $store.getters.apis)" icon="tag-outlined" @onClick="() => openTagsModal(record.id)" />
+            <a-popconfirm
+              :title="$t('label.delete') + '?'"
+              @confirm="handleDeleteRule(record)"
+              :okText="$t('label.yes')"
+              :cancelText="$t('label.no')"
+            >
+              <tooltip-button
+                :tooltip="$t('label.delete')"
+                :disabled="!('deleteLoadBalancerRule' in $store.getters.apis)"
+                type="primary"
+                :danger="true"
+                icon="delete-outlined" />
+            </a-popconfirm>
+          </div>
+        </template>
       </template>
       <template #expandedRowRender="{ record }">
         <div class="rule-instance-list">
@@ -178,25 +197,6 @@
           </div>
         </div>
       </template>
-      <template #actions="{record}">
-        <div class="actions">
-          <tooltip-button :tooltip="$t('label.edit')" icon="edit-outlined" @onClick="() => openEditRuleModal(record)" />
-          <tooltip-button :tooltip="$t('label.edit.tags')" :disabled="!('updateLoadBalancerRule' in $store.getters.apis)" icon="tag-outlined" @onClick="() => openTagsModal(record.id)" />
-          <a-popconfirm
-            :title="$t('label.delete') + '?'"
-            @confirm="handleDeleteRule(record)"
-            :okText="$t('label.yes')"
-            :cancelText="$t('label.no')"
-          >
-            <tooltip-button
-              :tooltip="$t('label.delete')"
-              :disabled="!('deleteLoadBalancerRule' in $store.getters.apis) || record.autoscalevmgroup"
-              type="primary"
-              :danger="true"
-              icon="delete-outlined" />
-          </a-popconfirm>
-        </div>
-      </template>
     </a-table>
     <a-pagination
       class="pagination"
@@ -267,7 +267,6 @@
     </a-modal>
 
     <a-modal
-      :title="$t('label.configure.sticky.policy')"
       :visible="stickinessModalVisible"
       :footer="null"
       :afterClose="closeModal"
@@ -276,6 +275,16 @@
       :okButtonProps="{ props: {htmlType: 'submit'}}"
       @cancel="stickinessModalVisible = false">
 
+      <template #title>
+        <span>{{ $t('label.configure.sticky.policy') }}</span>
+        <a
+          style="margin-left: 5px"
+          :href="$config.docBase + '/adminguide/networking/external_firewalls_and_load_balancers.html#sticky-session-policies-for-load-balancer-rules'"
+          target="_blank">
+          <question-circle-outlined />
+        </a>
+      </template>
+
       <span v-show="stickinessModalLoading" class="modal-loading">
         <loading-outlined />
       </span>
@@ -288,7 +297,10 @@
         v-ctrl-enter="handleSubmitStickinessForm"
         class="custom-ant-form"
        >
-        <a-form-item name="methodname" ref="methodname" :label="$t('label.stickiness.method')">
+        <a-form-item name="methodname" ref="methodname">
+          <template #label>
+            <tooltip-label :title="$t('label.stickiness.method')" :tooltip="createLoadBalancerStickinessPolicyParams.methodname.description" :tooltip-placement="'right'"/>
+          </template>
           <a-select
             v-focus="true"
             v-model:value="form.methodname"
@@ -296,69 +308,77 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="LbCookie">{{ $t('label.lb.cookie') }}</a-select-option>
-            <a-select-option value="AppCookie">{{ $t('label.app.cookie') }}</a-select-option>
-            <a-select-option value="SourceBased">{{ $t('label.source.based') }}</a-select-option>
-            <a-select-option value="none">{{ $t('label.none') }}</a-select-option>
+            <a-select-option value="LbCookie" :label="$t('label.lb.cookie')">{{ $t('label.lb.cookie') }}</a-select-option>
+            <a-select-option value="AppCookie" :label="$t('label.app.cookie')">{{ $t('label.app.cookie') }}</a-select-option>
+            <a-select-option value="SourceBased" :label="$t('label.source.based')">{{ $t('label.source.based') }}</a-select-option>
+            <a-select-option value="none" :label="$t('label.none')">{{ $t('label.none') }}</a-select-option>
           </a-select>
         </a-form-item>
         <a-form-item
           name="name"
           ref="name"
-          :label="$t('label.sticky.name')"
           v-show="stickinessPolicyMethod === 'LbCookie' || stickinessPolicyMethod ===
             'AppCookie' || stickinessPolicyMethod === 'SourceBased'">
           <a-input v-model:value="form.name" />
+          <template #label>
+            <tooltip-label :title="$t('label.sticky.name')" :tooltip="createLoadBalancerStickinessPolicyParams.name.description" :tooltip-placement="'right'"/>
+          </template>
         </a-form-item>
-        <a-form-item
-          name="cookieName"
-          ref="cookieName"
-          :label="$t('label.sticky.cookie-name')"
-          v-show="stickinessPolicyMethod === 'LbCookie' || stickinessPolicyMethod ===
-            'AppCookie'">
-          <a-input v-model:value="form.cookieName" />
-        </a-form-item>
-        <a-form-item
-          name="mode"
-          ref="mode"
-          :label="$t('label.sticky.mode')"
-          v-show="stickinessPolicyMethod === 'LbCookie' || stickinessPolicyMethod ===
-            'AppCookie'">
-          <a-input v-model:value="form.mode" />
-        </a-form-item>
-        <a-form-item name="nocache" ref="nocache" :label="$t('label.sticky.nocache')" v-show="stickinessPolicyMethod === 'LbCookie'">
-          <a-checkbox v-model:checked="form.nocache"></a-checkbox>
-        </a-form-item>
-        <a-form-item name="indirect" ref="indirect" :label="$t('label.sticky.indirect')" v-show="stickinessPolicyMethod === 'LbCookie'">
-          <a-checkbox v-model:checked="form.indirect"></a-checkbox>
-        </a-form-item>
-        <a-form-item name="postonly" ref="postonly" :label="$t('label.sticky.postonly')" v-show="stickinessPolicyMethod === 'LbCookie'">
-          <a-checkbox v-model:checked="form.postonly"></a-checkbox>
-        </a-form-item>
-        <a-form-item name="domain" ref="domain" :label="$t('label.domain')" v-show="stickinessPolicyMethod === 'LbCookie'">
-          <a-input v-model:value="form.domain" />
-        </a-form-item>
-        <a-form-item name="length" ref="length" :label="$t('label.sticky.length')" v-show="stickinessPolicyMethod === 'AppCookie'">
-          <a-input v-model:value="form.length" type="number" />
-        </a-form-item>
-        <a-form-item name="holdtime" ref="holdtime" :label="$t('label.sticky.holdtime')" v-show="stickinessPolicyMethod === 'AppCookie'">
-          <a-input v-model:value="form.holdtime" type="number" />
-        </a-form-item>
-        <a-form-item name="requestLearn" ref="requestLearn" :label="$t('label.sticky.request-learn')" v-show="stickinessPolicyMethod === 'AppCookie'">
-          <a-checkbox v-model:checked="form.requestLearn"></a-checkbox>
-        </a-form-item>
-        <a-form-item name="prefix" ref="prefix" :label="$t('label.sticky.prefix')" v-show="stickinessPolicyMethod === 'AppCookie'">
-          <a-checkbox v-model:checked="form.prefix"></a-checkbox>
-        </a-form-item>
-        <a-form-item name="tablesize" ref="tablesize" :label="$t('label.sticky.tablesize')" v-show="stickinessPolicyMethod === 'SourceBased'">
-          <a-input v-model:value="form.tablesize" />
-        </a-form-item>
-        <a-form-item name="expire" ref="expire" :label="$t('label.sticky.expire')" v-show="stickinessPolicyMethod === 'SourceBased'">
-          <a-input v-model:value="form.expire" />
-        </a-form-item>
-
+        <div v-if="stickinessPolicyMethod !== 'none'">
+          <br/>
+          {{ $t('message.loadbalancer.stickypolicy.configuration') }}
+          <br/>
+          <a-card>
+            <a-form-item
+              name="cookieName"
+              ref="cookieName"
+              :label="$t('label.sticky.cookie-name')"
+              v-show="stickinessPolicyMethod === 'LbCookie' || stickinessPolicyMethod ===
+                'AppCookie'">
+              <a-input v-model:value="form.cookieName" />
+            </a-form-item>
+            <a-form-item
+              name="mode"
+              ref="mode"
+              :label="$t('label.sticky.mode')"
+              v-show="stickinessPolicyMethod === 'LbCookie' || stickinessPolicyMethod ===
+                'AppCookie'">
+              <a-input v-model:value="form.mode" />
+            </a-form-item>
+            <a-form-item name="nocache" ref="nocache" :label="$t('label.sticky.nocache')" v-show="stickinessPolicyMethod === 'LbCookie'">
+              <a-checkbox v-model:checked="form.nocache"></a-checkbox>
+            </a-form-item>
+            <a-form-item name="indirect" ref="indirect" :label="$t('label.sticky.indirect')" v-show="stickinessPolicyMethod === 'LbCookie'">
+              <a-checkbox v-model:checked="form.indirect"></a-checkbox>
+            </a-form-item>
+            <a-form-item name="postonly" ref="postonly" :label="$t('label.sticky.postonly')" v-show="stickinessPolicyMethod === 'LbCookie'">
+              <a-checkbox v-model:checked="form.postonly"></a-checkbox>
+            </a-form-item>
+            <a-form-item name="domain" ref="domain" :label="$t('label.domain')" v-show="stickinessPolicyMethod === 'LbCookie'">
+              <a-input v-model:value="form.domain" />
+            </a-form-item>
+            <a-form-item name="length" ref="length" :label="$t('label.sticky.length')" v-show="stickinessPolicyMethod === 'AppCookie'">
+              <a-input v-model:value="form.length" type="number" />
+            </a-form-item>
+            <a-form-item name="holdtime" ref="holdtime" :label="$t('label.sticky.holdtime')" v-show="stickinessPolicyMethod === 'AppCookie'">
+              <a-input v-model:value="form.holdtime" type="number" />
+            </a-form-item>
+            <a-form-item name="requestLearn" ref="requestLearn" :label="$t('label.sticky.request-learn')" v-show="stickinessPolicyMethod === 'AppCookie'">
+              <a-checkbox v-model:checked="form.requestLearn"></a-checkbox>
+            </a-form-item>
+            <a-form-item name="prefix" ref="prefix" :label="$t('label.sticky.prefix')" v-show="stickinessPolicyMethod === 'AppCookie'">
+              <a-checkbox v-model:checked="form.prefix"></a-checkbox>
+            </a-form-item>
+            <a-form-item name="tablesize" ref="tablesize" :label="$t('label.sticky.tablesize')" v-show="stickinessPolicyMethod === 'SourceBased'">
+              <a-input v-model:value="form.tablesize" />
+            </a-form-item>
+            <a-form-item name="expire" ref="expire" :label="$t('label.sticky.expire')" v-show="stickinessPolicyMethod === 'SourceBased'">
+              <a-input v-model:value="form.expire" />
+            </a-form-item>
+          </a-card>
+        </div>
         <div :span="24" class="action-button">
           <a-button @click="stickinessModalVisible = false">{{ $t('label.cancel') }}</a-button>
           <a-button type="primary" ref="submit" @click="handleSubmitStickinessForm">{{ $t('label.ok') }}</a-button>
@@ -390,11 +410,11 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="roundrobin">{{ $t('label.lb.algorithm.roundrobin') }}</a-select-option>
-            <a-select-option value="leastconn">{{ $t('label.lb.algorithm.leastconn') }}</a-select-option>
-            <a-select-option value="source">{{ $t('label.lb.algorithm.source') }}</a-select-option>
+            <a-select-option value="roundrobin" :label="$t('label.lb.algorithm.roundrobin')">{{ $t('label.lb.algorithm.roundrobin') }}</a-select-option>
+            <a-select-option value="leastconn" :label="$t('label.lb.algorithm.leastconn')">{{ $t('label.lb.algorithm.leastconn') }}</a-select-option>
+            <a-select-option value="source" :label="$t('label.lb.algorithm.source')">{{ $t('label.lb.algorithm.source') }}</a-select-option>
           </a-select>
         </div>
         <div class="edit-rule__item">
@@ -404,11 +424,11 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="tcp-proxy">{{ $t('label.tcp.proxy') }}</a-select-option>
-            <a-select-option value="tcp">{{ $t('label.tcp') }}</a-select-option>
-            <a-select-option value="udp">{{ $t('label.udp') }}</a-select-option>
+            <a-select-option value="tcp-proxy" :label="$t('label.tcp.proxy')">{{ $t('label.tcp.proxy') }}</a-select-option>
+            <a-select-option value="tcp" :label="$t('label.tcp')">{{ $t('label.tcp') }}</a-select-option>
+            <a-select-option value="udp" :label="$t('label.udp')">{{ $t('label.udp') }}</a-select-option>
           </a-select>
         </div>
         <div :span="24" class="action-button">
@@ -441,12 +461,13 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option
               v-for="tier in tiers.data"
               :loading="tiers.loading"
-              :key="tier.id">
+              :key="tier.id"
+              :label="tier.displaytext">
               {{ tier.displaytext }}
             </a-select-option>
           </a-select>
@@ -467,33 +488,39 @@
           :pagination="false"
           :rowKey="record => record.id"
           :scroll="{ y: 300 }">
-          <template #name="{text, record, index}">
-            <span>
-              {{ text }}
-            </span>
-            <loading-outlined v-if="addVmModalNicLoading" />
-            <a-select
-              style="display: block"
-              v-else-if="!addVmModalNicLoading && newRule.virtualmachineid[index] === record.id"
-              mode="multiple"
-              v-model:value="newRule.vmguestip[index]"
-              showSearch
-              optionFilterProp="label"
-              :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-              }" >
-              <a-select-option v-for="(nic, nicIndex) in nics[index]" :key="nic" :value="nic">
-                {{ nic }}{{ nicIndex === 0 ? ` (${$t('label.primary')})` : null }}
-              </a-select-option>
-            </a-select>
-          </template>
+          <template #bodyCell="{ column, text, record, index }">
+            <template v-if="column.key === 'name'">
+              <span>
+                {{ text }}
+              </span>
+              <loading-outlined v-if="addVmModalNicLoading" />
+              <a-select
+                style="display: block"
+                v-else-if="!addVmModalNicLoading && newRule.virtualmachineid[index] === record.id"
+                mode="multiple"
+                v-model:value="newRule.vmguestip[index]"
+                showSearch
+                optionFilterProp="label"
+                :filterOption="(input, option) => {
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                }" >
+                <a-select-option
+                  v-for="(nic, nicIndex) in nics[index]"
+                  :key="nic"
+                  :value="nic"
+                  :label="nic + nicIndex === 0 ? ` (${$t('label.primary')})` : null">
+                  {{ nic }}{{ nicIndex === 0 ? ` (${$t('label.primary')})` : null }}
+                </a-select-option>
+              </a-select>
+            </template>
 
-          <template #state="{text}">
-            <status :text="text ? text : ''" displayText></status>
-          </template>
+            <template v-if="column.key === 'state'">
+              <status :text="text ? text : ''" displayText></status>
+            </template>
 
-          <template #action="{text, record, index}" style="text-align: center" :text="text">
-            <a-checkbox v-model:value="record.id" @change="e => fetchNics(e, index)" :disabled="newRule.autoscale" />
+            <template v-if="column.key === 'actions'" style="text-align: center" :text="text">
+              <a-checkbox v-model:value="record.id" @change="e => fetchNics(e, index)" :disabled="newRule.autoscale"/>
+            </template>
           </template>
         </a-table>
         <a-pagination
@@ -540,9 +567,9 @@
             v-model:value="monitorForm.type"
             @change="(value) => { healthMonitorParams.type = value }"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }">
             <a-select-option value="PING">PING</a-select-option>
             <a-select-option value="TCP">TCP</a-select-option>
@@ -567,9 +594,9 @@
             v-focus="true"
             v-model:value="monitorForm.httpmethodtype"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }">
             <a-select-option value="GET">GET</a-select-option>
             <a-select-option value="HEAD">HEAD</a-select-option>
@@ -648,7 +675,7 @@
       showGroupActionModal: false,
       selectedItems: [],
       selectedColumns: [],
-      filterColumns: ['State', 'Action', 'Add VMs', 'Stickiness'],
+      filterColumns: ['State', 'Actions', 'Add VMs', 'Stickiness'],
       showConfirmationAction: false,
       message: {
         title: this.$t('label.action.bulk.delete.load.balancer.rules'),
@@ -705,36 +732,36 @@
           dataIndex: 'privateport'
         },
         {
-          title: this.$t('label.cidrlist'),
-          slots: { customRender: 'cidrlist' }
+          key: 'algorithm',
+          title: this.$t('label.algorithm')
         },
         {
-          title: this.$t('label.algorithm'),
-          slots: { customRender: 'algorithm' }
+          key: 'cidrlist',
+          title: this.$t('label.cidrlist')
         },
         {
-          title: this.$t('label.protocol'),
-          slots: { customRender: 'protocol' }
+          key: 'protocol',
+          title: this.$t('label.protocol')
         },
         {
           title: this.$t('label.state'),
           dataIndex: 'state'
         },
         {
-          title: this.$t('label.action.configure.stickiness'),
-          slots: { customRender: 'stickiness' }
+          key: 'stickiness',
+          title: this.$t('label.action.configure.stickiness')
         },
         {
-          title: this.$t('label.autoscale'),
-          slots: { customRender: 'autoscale' }
+          key: 'add',
+          title: this.$t('label.add.vms')
         },
         {
-          title: this.$t('label.add.vms'),
-          slots: { customRender: 'add' }
+          key: 'autoscale',
+          title: this.$t('label.autoscale')
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          key: 'actions',
+          title: this.$t('label.actions')
         }
       ],
       tiers: {
@@ -743,15 +770,15 @@
       },
       vmColumns: [
         {
+          key: 'name',
           title: this.$t('label.name'),
           dataIndex: 'name',
-          slots: { customRender: 'name' },
           width: 220
         },
         {
+          key: 'state',
           title: this.$t('label.state'),
-          dataIndex: 'state',
-          slots: { customRender: 'state' }
+          dataIndex: 'state'
         },
         {
           title: this.$t('label.displayname'),
@@ -766,9 +793,9 @@
           dataIndex: 'zonename'
         },
         {
+          key: 'actions',
           title: this.$t('label.select'),
-          dataIndex: 'action',
-          slots: { customRender: 'action' },
+          dataIndex: 'actions',
           width: 80
         }
       ],
@@ -797,6 +824,7 @@
   },
   beforeCreate () {
     this.createLoadBalancerRuleParams = this.$getApiParams('createLoadBalancerRule')
+    this.createLoadBalancerStickinessPolicyParams = this.$getApiParams('createLBStickinessPolicy')
   },
   created () {
     this.initForm()
@@ -847,9 +875,8 @@
       this.tiers.loading = true
 
       api('listNetworks', {
-        account: this.resource.account,
-        domainid: this.resource.domainid,
         supportedservices: 'Lb',
+        isrecursive: true,
         vpcid: this.resource.vpcid
       }).then(json => {
         this.tiers.data = json.listnetworksresponse.network || []
@@ -857,7 +884,7 @@
         if (this.tiers.data?.[0]?.broadcasturi === 'tf://tf') {
           this.columns.splice(8, 0, {
             title: this.$t('label.action.health.monitor'),
-            slots: { customRender: 'healthmonitor' }
+            key: 'healthmonitor'
           })
         }
       }).catch(error => {
@@ -1311,9 +1338,9 @@
     deleteRules (e) {
       this.showConfirmationAction = false
       this.selectedColumns.splice(0, 0, {
+        key: 'status',
         dataIndex: 'status',
         title: this.$t('label.operation.status'),
-        slots: { customRender: 'status' },
         filters: [
           { text: 'In Progress', value: 'InProgress' },
           { text: 'Success', value: 'success' },
@@ -1447,9 +1474,7 @@
         keyword: this.searchQuery,
         page: this.vmPage,
         pagesize: this.vmPageSize,
-        networkid: networkId,
-        account: this.resource.account,
-        domainid: this.resource.domainid
+        networkid: networkId
       }).then(response => {
         this.vmCount = response.listvirtualmachinesresponse.count || 0
         this.vms = response.listvirtualmachinesresponse.virtualmachine || []
diff --git a/ui/src/views/network/NetworkPermissions.vue b/ui/src/views/network/NetworkPermissions.vue
index 8961b7e..a5434e5 100644
--- a/ui/src/views/network/NetworkPermissions.vue
+++ b/ui/src/views/network/NetworkPermissions.vue
@@ -44,19 +44,21 @@
         :rowKey="item => item.id"
         :pagination="false" >
 
-        <template #action="{ record }">
-          <a-popconfirm
-            :title="$t('message.confirm.remove.network.permission')"
-            @confirm="removeNetworkPermission(record.accountid, record.projectid)"
-            :okText="$t('label.yes')"
-            :cancelText="$t('label.no')" >
-            <tooltip-button
-              tooltipPlacement="bottom"
-              :tooltip="$t('label.action.delete.network.permission')"
-              type="primary"
-              :danger="true"
-              icon="delete-outlined" />
-          </a-popconfirm>
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.key === 'actions'">
+            <a-popconfirm
+              :title="$t('message.confirm.remove.network.permission')"
+              @confirm="removeNetworkPermission(record.accountid, record.projectid)"
+              :okText="$t('label.yes')"
+              :cancelText="$t('label.no')" >
+              <tooltip-button
+                tooltipPlacement="bottom"
+                :tooltip="$t('label.action.delete.network.permission')"
+                type="primary"
+                :danger="true"
+                icon="delete-outlined" />
+            </a-popconfirm>
+          </template>
         </template>
 
       </a-table>
@@ -85,15 +87,12 @@
       :footer="null"
       @cancel="showResetPermissionModal = false"
       centered
-      width="auto"
-      v-ctrl-enter="resetNetworkPermission">
+      width="auto">
       {{ $t('message.confirm.reset.network.permissions') }}
-      <a-form @submit="resetNetworkPermission">
-        <div :span="24" class="action-button">
-          <a-button @click="showResetPermissionModal = false">{{ $t('label.cancel') }}</a-button>
-          <a-button type="primary" ref="submit" @click="resetNetworkPermission">{{ $t('label.ok') }}</a-button>
-        </div>
-      </a-form>
+      <div :span="24" class="action-button">
+        <a-button @click="showResetPermissionModal = false">{{ $t('label.cancel') }}</a-button>
+        <a-button type="primary" ref="submit" @click="resetNetworkPermission">{{ $t('label.ok') }}</a-button>
+      </div>
     </a-modal>
   </div>
 </template>
@@ -140,8 +139,8 @@
           dataIndex: 'project'
         },
         {
-          title: '',
-          slots: { customRender: 'action' }
+          key: 'actions',
+          title: ''
         }
       ]
     }
diff --git a/ui/src/views/network/NicsTable.vue b/ui/src/views/network/NicsTable.vue
index d254990..f791e12 100644
--- a/ui/src/views/network/NicsTable.vue
+++ b/ui/src/views/network/NicsTable.vue
@@ -60,15 +60,17 @@
         </template>
       </a-descriptions>
     </template>
-    <template #networkname="{ text, record }">
-      <resource-icon v-if="!networkIconLoading && networkicon[record.id]" :image="networkicon[record.id]" size="1x" style="margin-right: 5px"/>
-      <apartment-outlined v-else style="margin-right: 5px" />
-      <router-link :to="{ path: '/guestnetwork/' + record.networkid }">
-        {{ text }}
-      </router-link>
-      <a-tag v-if="record.isdefault">
-        {{ $t('label.default') }}
-      </a-tag>
+    <template #bodyCell="{ column, text, record }">
+      <template v-if="column.key === 'networkname'">
+        <resource-icon v-if="!networkIconLoading && networkicon[record.id]" :image="networkicon[record.id]" size="1x" style="margin-right: 5px"/>
+        <apartment-outlined v-else style="margin-right: 5px" />
+        <router-link :to="{ path: '/guestnetwork/' + record.networkid }">
+          {{ text }}
+        </router-link>
+        <a-tag v-if="record.isdefault">
+          {{ $t('label.default') }}
+        </a-tag>
+      </template>
     </template>
   </a-table>
 </template>
@@ -97,14 +99,14 @@
     return {
       nicColumns: [
         {
+          key: 'deviceid',
           title: this.$t('label.deviceid'),
-          dataIndex: 'deviceid',
-          slots: { customRender: 'deviceid' }
+          dataIndex: 'deviceid'
         },
         {
+          key: 'networkname',
           title: this.$t('label.networkname'),
-          dataIndex: 'networkname',
-          slots: { customRender: 'networkname' }
+          dataIndex: 'networkname'
         },
         {
           title: this.$t('label.macaddress'),
diff --git a/ui/src/views/network/PortForwarding.vue b/ui/src/views/network/PortForwarding.vue
index edbf49a..d536203 100644
--- a/ui/src/views/network/PortForwarding.vue
+++ b/ui/src/views/network/PortForwarding.vue
@@ -66,10 +66,10 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option value="tcp">{{ $t('label.tcp') }}</a-select-option>
-            <a-select-option value="udp">{{ $t('label.udp') }}</a-select-option>
+            <a-select-option value="tcp" label="$t('label.tcp')">{{ $t('label.tcp') }}</a-select-option>
+            <a-select-option value="udp" :label="$t('label.udp')">{{ $t('label.udp') }}</a-select-option>
           </a-select>
         </div>
         <div class="form__item" style="margin-left: auto;">
@@ -98,33 +98,35 @@
       :pagination="false"
       :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
       :rowKey="record => record.id">
-      <template #privateport="{record}">
-        {{ record.privateport }} - {{ record.privateendport }}
-      </template>
-      <template #publicport="{record}">
-        {{ record.publicport }} - {{ record.publicendport }}
-      </template>
-      <template #protocol="{record}">
-        {{ getCapitalise(record.protocol) }}
-      </template>
-      <template #vm="{record}">
-        <div><desktop-outlined/>
-          <router-link
-            :to="{ path: '/vm/' + record.virtualmachineid }">
-            {{ record.virtualmachinename }}</router-link> ({{ record.vmguestip }})</div>
-      </template>
-      <template #actions="{record}">
-        <div class="actions">
-          <tooltip-button :tooltip="$t('label.tags')" icon="tag-outlined" buttonClass="rule-action" @onClick="() => openTagsModal(record.id)" />
-          <tooltip-button
-            :tooltip="$t('label.remove.rule')"
-            type="primary"
-            :danger="true"
-            icon="delete-outlined"
-            buttonClass="rule-action"
-            :disabled="!('deletePortForwardingRule' in $store.getters.apis)"
-            @onClick="deleteRule(record)" />
-        </div>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'privateport'">
+          {{ record.privateport }} - {{ record.privateendport }}
+        </template>
+        <template v-if="column.key === 'publicport'">
+          {{ record.publicport }} - {{ record.publicendport }}
+        </template>
+        <template v-if="column.key === 'protocol'">
+          {{ getCapitalise(record.protocol) }}
+        </template>
+        <template v-if="column.key === 'vm'">
+          <div><desktop-outlined/>
+            <router-link
+              :to="{ path: '/vm/' + record.virtualmachineid }">
+              {{ record.virtualmachinename }}</router-link> ({{ record.vmguestip }})</div>
+        </template>
+        <template v-if="column.key === 'actions'">
+          <div class="actions">
+            <tooltip-button :tooltip="$t('label.tags')" icon="tag-outlined" buttonClass="rule-action" @onClick="() => openTagsModal(record.id)" />
+            <tooltip-button
+              :tooltip="$t('label.remove.rule')"
+              type="primary"
+              :danger="true"
+              icon="delete-outlined"
+              buttonClass="rule-action"
+              :disabled="!('deletePortForwardingRule' in $store.getters.apis)"
+              @onClick="deleteRule(record)" />
+          </div>
+        </template>
       </template>
     </a-table>
     <a-pagination
@@ -215,12 +217,13 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option
               v-for="tier in tiers.data"
               :loading="tiers.loading"
-              :key="tier.id">
+              :key="tier.id"
+              :label="tier.displaytext || ''">
               {{ tier.displaytext }}
             </a-select-option>
           </a-select>
@@ -241,40 +244,46 @@
           :pagination="false"
           :rowKey="record => record.id"
           :scroll="{ y: 300 }">
-          <template #name="{text, record}">
-            <span>
-              {{ text }}
-            </span>
-            <loading-outlined v-if="addVmModalNicLoading"></loading-outlined>
-            <a-select
-              style="display: block"
-              v-else-if="!addVmModalNicLoading && newRule.virtualmachineid === record.id"
-              v-model:value="newRule.vmguestip"
-              showSearch
-              optionFilterProp="label"
-              :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-              }" >
-              <a-select-option v-for="(nic, nicIndex) in nics" :key="nic" :value="nic">
-                {{ nic }}{{ nicIndex === 0 ? ` (${$t('label.primary')})` : null }}
-              </a-select-option>
-            </a-select>
-          </template>
+          <template #bodyCell="{ column, text, record }">
+            <template v-if="column.key === 'name'">
+              <span>
+                {{ text }}
+              </span>
+              <loading-outlined v-if="addVmModalNicLoading"></loading-outlined>
+              <a-select
+                style="display: block"
+                v-else-if="!addVmModalNicLoading && newRule.virtualmachineid === record.id"
+                v-model:value="newRule.vmguestip"
+                showSearch
+                optionFilterProp="label"
+                :filterOption="(input, option) => {
+                  return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                }" >
+                <a-select-option
+                  v-for="(nic, nicIndex) in nics"
+                  :key="nic"
+                  :value="nic"
+                  :label="nic">
+                  {{ nic }}{{ nicIndex === 0 ? ` (${$t('label.primary')})` : null }}
+                </a-select-option>
+              </a-select>
+            </template>
 
-          <template #state="{text}">
-            <status :text="text ? text : ''" displayText></status>
-          </template>
+            <template v-if="column.key === 'state'">
+              <status :text="text ? text : ''" displayText></status>
+            </template>
 
-          <template #action="{record}">
-            <div style="text-align: center">
-              <a-radio-group
-                class="radio-group"
-                :key="record.id"
-                v-model:value="checked"
-                @change="($event) => checked = $event.target.value">
-                <a-radio :value="record.id" @change="e => fetchNics(e)" />
-              </a-radio-group>
-            </div>
+            <template v-if="column.key === 'actions'">
+              <div style="text-align: center">
+                <a-radio-group
+                  class="radio-group"
+                  :key="record.id"
+                  v-model:value="checked"
+                  @change="($event) => checked = $event.target.value">
+                  <a-radio :value="record.id" @change="e => fetchNics(e)" />
+                </a-radio-group>
+              </div>
+            </template>
           </template>
         </a-table>
         <a-pagination
@@ -346,7 +355,7 @@
       showGroupActionModal: false,
       selectedItems: [],
       selectedColumns: [],
-      filterColumns: ['State', 'Action'],
+      filterColumns: ['State', 'Actions'],
       showConfirmationAction: false,
       message: {
         title: this.$t('label.action.bulk.delete.portforward.rules'),
@@ -379,28 +388,28 @@
       pageSize: 10,
       columns: [
         {
-          title: this.$t('label.privateport'),
-          slots: { customRender: 'privateport' }
+          key: 'privateport',
+          title: this.$t('label.privateport')
         },
         {
-          title: this.$t('label.publicport'),
-          slots: { customRender: 'publicport' }
+          key: 'publicport',
+          title: this.$t('label.publicport')
         },
         {
-          title: this.$t('label.protocol'),
-          slots: { customRender: 'protocol' }
+          key: 'protocol',
+          title: this.$t('label.protocol')
         },
         {
           title: this.$t('label.state'),
           dataIndex: 'state'
         },
         {
-          title: this.$t('label.vm'),
-          slots: { customRender: 'vm' }
+          key: 'vm',
+          title: this.$t('label.vm')
         },
         {
-          title: this.$t('label.action'),
-          slots: { customRender: 'actions' }
+          key: 'actions',
+          title: this.$t('label.actions')
         }
       ],
       tiers: {
@@ -409,15 +418,15 @@
       },
       vmColumns: [
         {
+          key: 'name',
           title: this.$t('label.name'),
           dataIndex: 'name',
-          slots: { customRender: 'name' },
           width: 210
         },
         {
+          key: 'state',
           title: this.$t('label.state'),
-          dataIndex: 'state',
-          slots: { customRender: 'state' }
+          dataIndex: 'state'
         },
         {
           title: this.$t('label.displayname'),
@@ -437,9 +446,9 @@
           dataIndex: 'zonename'
         },
         {
+          key: 'actions',
           title: this.$t('label.select'),
-          dataIndex: 'action',
-          slots: { customRender: 'action' },
+          dataIndex: 'actions',
           width: 80
         }
       ],
@@ -490,10 +499,9 @@
       this.selectedTier = null
       this.tiers.loading = true
       api('listNetworks', {
-        account: this.resource.account,
-        domainid: this.resource.domainid,
         supportedservices: 'PortForwarding',
-        vpcid: this.resource.vpcid
+        vpcid: this.resource.vpcid,
+        listall: this.resource.vpcid !== null
       }).then(json => {
         this.tiers.data = json.listnetworksresponse.network || []
         if (this.tiers.data && this.tiers.data.length > 0) {
@@ -550,9 +558,9 @@
     deleteRules (e) {
       this.showConfirmationAction = false
       this.selectedColumns.splice(0, 0, {
+        key: 'status',
         dataIndex: 'status',
         title: this.$t('label.operation.status'),
-        slots: { customRender: 'status' },
         filters: [
           { text: 'In Progress', value: 'InProgress' },
           { text: 'Success', value: 'success' },
@@ -795,9 +803,7 @@
         keyword: this.searchQuery,
         page: this.vmPage,
         pagesize: this.vmPageSize,
-        networkid: networkId,
-        account: this.resource.account,
-        domainid: this.resource.domainid
+        networkid: networkId
       }).then(response => {
         this.vmCount = response.listvirtualmachinesresponse.count || 0
         this.vms = response.listvirtualmachinesresponse.virtualmachine
diff --git a/ui/src/views/network/ReservePublicIP.vue b/ui/src/views/network/ReservePublicIP.vue
index dc5486e..3fffc5e 100644
--- a/ui/src/views/network/ReservePublicIP.vue
+++ b/ui/src/views/network/ReservePublicIP.vue
@@ -35,9 +35,9 @@
           v-model:value="selectedAccountType"
           v-focus="true"
           showSearch
-          optionFilterProp="label"
+          optionFilterProp="value"
           :filterOption="(input, option) => {
-            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }">
           <a-select-option :value="$t('label.account')">{{ $t('label.account') }}</a-select-option>
           <a-select-option :value="$t('label.project')">{{ $t('label.project') }}</a-select-option>
@@ -71,7 +71,7 @@
             @change="changeAccount"
             v-model:value="selectedAccount"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
               return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
diff --git a/ui/src/views/network/RoutersTab.vue b/ui/src/views/network/RoutersTab.vue
index 73f7bf6..a2e9323 100644
--- a/ui/src/views/network/RoutersTab.vue
+++ b/ui/src/views/network/RoutersTab.vue
@@ -25,20 +25,22 @@
     :pagination="false"
     :loading="fetchLoading"
   >
-    <template #name="{ text, record }">
-      <router-link :to="{ path: '/router/' + record.id }" >{{ text }}</router-link>
-    </template>
-    <template #status="{ record }">
-      <status class="status" :text="record.state" displayText />
-    </template>
-    <template #requiresupgrade="{ record }">
-      {{ record.requiresupgrade ? $t('label.yes') : $t('label.no') }}
-    </template>
-    <template #isredundantrouter="{ record }">
-      {{ record.isredundantrouter ? record.redundantstate : record.isredundantrouter }}
-    </template>
-    <template #hostname="{ record }">
-      <router-link :to="{ path: '/host/' + record.hostid }" >{{ record.hostname || record.hostid }}</router-link>
+    <template #bodyCell="{ column, text, record }">
+      <template v-if="column.key === 'name'">
+        <router-link :to="{ path: '/router/' + record.id }" >{{ text }}</router-link>
+      </template>
+      <template v-if="column.key === 'status'">
+        <status class="status" :text="record.state" displayText />
+      </template>
+      <template v-if="column.key === 'requiresupgrade'">
+        {{ record.requiresupgrade ? $t('label.yes') : $t('label.no') }}
+      </template>
+      <template v-if="column.key === 'isredundantrouter'">
+        {{ record.isredundantrouter ? record.redundantstate : record.isredundantrouter }}
+      </template>
+      <template v-if="column.key === 'hostname'">
+        <router-link :to="{ path: '/host/' + record.hostid }" >{{ record.hostname || record.hostid }}</router-link>
+      </template>
     </template>
   </a-table>
 </template>
@@ -68,14 +70,14 @@
       routers: [],
       columns: [
         {
+          key: 'name',
           title: this.$t('label.name'),
-          dataIndex: 'name',
-          slots: { customRender: 'name' }
+          dataIndex: 'name'
         },
         {
+          key: 'status',
           title: this.$t('label.status'),
-          dataIndex: 'state',
-          slots: { customRender: 'status' }
+          dataIndex: 'state'
         },
         {
           title: this.$t('label.ip'),
@@ -86,19 +88,19 @@
           dataIndex: 'version'
         },
         {
+          key: 'requiresupgrade',
           title: this.$t('label.requiresupgrade'),
-          dataIndex: 'requiresupgrade',
-          slots: { customRender: 'requiresupgrade' }
+          dataIndex: 'requiresupgrade'
         },
         {
+          key: 'isredundantrouter',
           title: this.$t('label.isredundantrouter'),
-          dataIndex: 'isredundantrouter',
-          slots: { customRender: 'isredundantrouter' }
+          dataIndex: 'isredundantrouter'
         },
         {
+          key: 'hostname',
           title: this.$t('label.hostname'),
-          dataIndex: 'hostname',
-          slots: { customRender: 'hostname' }
+          dataIndex: 'hostname'
         }
       ]
     }
diff --git a/ui/src/views/network/UpdateNetwork.vue b/ui/src/views/network/UpdateNetwork.vue
index 02b826c..42c9107 100644
--- a/ui/src/views/network/UpdateNetwork.vue
+++ b/ui/src/views/network/UpdateNetwork.vue
@@ -80,6 +80,24 @@
             </a-col>
           </a-row>
         </div>
+        <a-form-item name="sourcenatipaddress" ref="sourcenatipaddress">
+          <template #label>
+            <tooltip-label :title="$t('label.sourcenatipaddress')" :tooltip="apiParams.sourcenatipaddress.description"/>
+          </template>
+          <span v-if="sourcenatchange">
+            <a-alert type="warning">
+              <template #message>
+                <span v-html="$t('message.sourcenatip.change.warning')" />
+              </template>
+            </a-alert>
+            <br/>
+          </span>
+          <a-input
+            v-model:value="form.sourcenatipaddress"
+            :placeholder="apiParams.sourcenatipaddress.description"
+            v-focus="true"
+            @change="sourcenatchange = form.sourcenatipaddress.length > 0"/>
+        </a-form-item>
         <a-form-item name="networkofferingid" ref="networkofferingid" v-if="isUpdatingIsolatedNetwork">
           <template #label>
             <tooltip-label :title="$t('label.networkofferingid')" :tooltip="apiParams.networkofferingid.description"/>
@@ -98,12 +116,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="networkOfferingLoading"
             :placeholder="apiParams.networkofferingid.description"
             @change="val => { networkOffering = networkOfferings[val] }">
-            <a-select-option v-for="(opt, optIndex) in networkOfferings" :key="optIndex">
+            <a-select-option v-for="(opt, optIndex) in networkOfferings" :key="optIndex" :label="opt.displaytext || opt.name">
               {{ opt.displaytext || opt.name }}
             </a-select-option>
           </a-select>
@@ -238,7 +256,8 @@
       minMTU: 68,
       errorPrivateMtu: '',
       errorPublicMtu: '',
-      setMTU: false
+      setMTU: false,
+      sourcenatchange: false
     }
   },
   beforeCreate () {
diff --git a/ui/src/views/network/VpcTab.vue b/ui/src/views/network/VpcTab.vue
index 0183764..57abe8e 100644
--- a/ui/src/views/network/VpcTab.vue
+++ b/ui/src/views/network/VpcTab.vue
@@ -48,10 +48,12 @@
           :rowKey="item => item.id"
           :pagination="false"
         >
-          <template #name="{ text, record }">
-            <router-link :to="{ path: '/acllist/' + record.id }">
-              {{ text }}
-            </router-link>
+          <template #bodyCell="{ column, text, record }">
+            <template v-if="column.key === 'name'">
+              <router-link :to="{ path: '/acllist/' + record.id }">
+                {{ text }}
+              </router-link>
+            </template>
           </template>
         </a-table>
         <a-pagination
@@ -75,7 +77,7 @@
           :footer="null"
           :maskClosable="false"
           :closable="true"
-          @cancel="modals.networkAcl = fetchAclList">
+          @cancel="modals.networkAcl = false">
           <a-form
             layout="vertical"
             :ref="formRef"
@@ -117,11 +119,13 @@
           :rowKey="item => item.id"
           :pagination="false"
         >
-          <template #ipaddress="{ text, record }">
-            <router-link :to="{ path: '/privategw/' + record.id }">{{ text }}</router-link>
-          </template>
-          <template #state="{ record }">
-            <status :text="record.state" displayText></status>
+          <template #bodyCell="{ column, text, record }">
+            <template v-if="column.key === 'ipaddress'">
+              <router-link :to="{ path: '/privategw/' + record.id }">{{ text }}</router-link>
+            </template>
+            <template v-if="column.key === 'state'">
+              <status :text="record.state" displayText></status>
+            </template>
           </template>
         </a-table>
         <a-pagination
@@ -163,9 +167,9 @@
                   showSearch
                   optionFilterProp="label"
                   :filterOption="(input, option) => {
-                    return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                   }" >
-                  <a-select-option v-for="item in physicalnetworks" :key="item.id" :value="item.id">
+                  <a-select-option v-for="item in physicalnetworks" :key="item.id" :value="item.id" :label="item.name">
                     {{ item.name }}
                   </a-select-option>
                 </a-select>
@@ -286,13 +290,15 @@
           :dataSource="vpnConnections"
           :pagination="false"
           :rowKey="record => record.id">
-          <template #publicip="{text, record}">
-            <router-link :to="{ path: '/s2svpnconn/' + record.id }">
-              {{ text }}
-            </router-link>
-          </template>
-          <template #state="{text}">
-            <status :text="text ? text : ''" displayText />
+          <template #bodyCell="{ column, text, record }">
+            <template v-if="column.key === 'publicip'">
+              <router-link :to="{ path: '/s2svpnconn/' + record.id }">
+                {{ text }}
+              </router-link>
+            </template>
+            <template v-if="column.key === 'state'">
+              <status :text="text ? text : ''" displayText />
+            </template>
           </template>
         </a-table>
         <a-pagination
@@ -332,9 +338,9 @@
                   showSearch
                   optionFilterProp="label"
                   :filterOption="(input, option) => {
-                    return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                   }" >
-                  <a-select-option v-for="item in vpncustomergateways" :key="item.id" :value="item.id">
+                  <a-select-option v-for="item in vpncustomergateways" :key="item.id" :value="item.id" :label="item.name">
                     {{ item.name }}
                   </a-select-option>
                 </a-select>
@@ -378,6 +384,7 @@
 import VpcTiersTab from './VpcTiersTab'
 import EventsTab from '@/components/view/EventsTab'
 import AnnotationsTab from '@/components/view/AnnotationsTab'
+import ResourceIcon from '@/components/view/ResourceIcon'
 
 export default {
   name: 'VpcTab',
@@ -388,7 +395,8 @@
     RoutersTab,
     VpcTiersTab,
     EventsTab,
-    AnnotationsTab
+    AnnotationsTab,
+    ResourceIcon
   },
   mixins: [mixinDevice],
   props: {
@@ -426,14 +434,14 @@
       vpncustomergateways: [],
       privateGatewaysColumns: [
         {
+          key: 'ipaddress',
           title: this.$t('label.ip'),
-          dataIndex: 'ipaddress',
-          slots: { customRender: 'ipaddress' }
+          dataIndex: 'ipaddress'
         },
         {
+          key: 'state',
           title: this.$t('label.state'),
-          dataIndex: 'state',
-          slots: { customRender: 'state' }
+          dataIndex: 'state'
         },
         {
           title: this.$t('label.gateway'),
@@ -450,14 +458,14 @@
       ],
       vpnConnectionsColumns: [
         {
+          key: 'publicip',
           title: this.$t('label.ip'),
-          dataIndex: 'publicip',
-          slots: { customRender: 'publicip' }
+          dataIndex: 'publicip'
         },
         {
+          key: 'state',
           title: this.$t('label.state'),
-          dataIndex: 'state',
-          slots: { customRender: 'state' }
+          dataIndex: 'state'
         },
         {
           title: this.$t('label.gateway'),
@@ -470,9 +478,9 @@
       ],
       networkAclsColumns: [
         {
+          key: 'name',
           title: this.$t('label.name'),
-          dataIndex: 'name',
-          slots: { customRender: 'name' }
+          dataIndex: 'name'
         },
         {
           title: this.$t('label.description'),
diff --git a/ui/src/views/network/VpcTiersTab.vue b/ui/src/views/network/VpcTiersTab.vue
index bd37001..214ea1a 100644
--- a/ui/src/views/network/VpcTiersTab.vue
+++ b/ui/src/views/network/VpcTiersTab.vue
@@ -80,17 +80,19 @@
                 :rowKey="item => item.id"
                 :pagination="false"
                 :loading="fetchLoading">
-                <template #name="{ record }">
-                  <router-link :to="{ path: '/vm/' + record.id}">{{ record.name }}
-                  </router-link>
-                </template>
-                <template #state="{ record }">
-                  <status :text="record.state" displayText></status>
-                </template>
-                <template #ip="{ record }">
-                  <div v-for="nic in record.nic" :key="nic.id">
-                    {{ nic.networkid === network.id ? nic.ipaddress : '' }}
-                  </div>
+                <template #bodyCell="{ column, record }">
+                  <template v-if="column.key === 'name'">
+                    <router-link :to="{ path: '/vm/' + record.id}">{{ record.name }}
+                    </router-link>
+                  </template>
+                  <template v-if="column.key === 'state'">
+                    <status :text="record.state" displayText></status>
+                  </template>
+                  <template v-if="column.key === 'ip'">
+                    <div v-for="nic in record.nic" :key="nic.id">
+                      {{ nic.networkid === network.id ? nic.ipaddress : '' }}
+                    </div>
+                  </template>
                 </template>
               </a-table>
               <a-divider/>
@@ -110,7 +112,7 @@
                 </template>
               </a-pagination>
             </a-collapse-panel>
-            <a-collapse-panel :header="$t('label.internal.lb')" key="ilb" :style="customStyle" :disabled="!showIlb(network)" >
+            <a-collapse-panel :header="$t('label.internal.lb')" key="ilb" :style="customStyle" :collapsible="!showIlb(network) ? 'disabled' : null" >
               <a-button
                 type="dashed"
                 style="margin-bottom: 15px; width: 100%"
@@ -127,9 +129,11 @@
                 :rowKey="item => item.id"
                 :pagination="false"
                 :loading="fetchLoading">
-                <template #name="{ record }">
-                  <router-link :to="{ path: '/ilb/'+ record.id}">{{ record.name }}
-                  </router-link>
+                <template #bodyCell="{ column, record }">
+                  <template v-if="column.key === 'name'">
+                    <router-link :to="{ path: '/ilb/'+ record.id}">{{ record.name }}
+                    </router-link>
+                  </template>
                 </template>
               </a-table>
               <a-divider/>
@@ -188,9 +192,9 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
-              <a-select-option v-for="item in networkOfferings" :key="item.id" :value="item.id">
+              <a-select-option v-for="item in networkOfferings" :key="item.id" :value="item.id" :label="item.displaytext || item.name || item.description">
                 {{ item.displaytext || item.name || item.description }}
               </a-select-option>
             </a-select>
@@ -252,9 +256,9 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
-              <a-select-option v-for="item in networkAclList" :key="item.id" :value="item.id">
+              <a-select-option v-for="item in networkAclList" :key="item.id" :value="item.id" :label="`${item.name}(${item.description})`">
                 <strong>{{ item.name }}</strong> ({{ item.description }})
               </a-select-option>
             </a-select>
@@ -316,9 +320,9 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
-              <a-select-option v-for="(key, idx) in Object.keys(algorithms)" :key="idx" :value="algorithms[key]">
+              <a-select-option v-for="(key, idx) in Object.keys(algorithms)" :key="idx" :value="algorithms[key]" :label="key">
                 {{ key }}
               </a-select-option>
             </a-select>
@@ -384,9 +388,9 @@
       },
       internalLbCols: [
         {
+          key: 'name',
           title: this.$t('label.name'),
-          dataIndex: 'name',
-          slots: { customRender: 'name' }
+          dataIndex: 'name'
         },
         {
           title: this.$t('label.sourceipaddress'),
@@ -401,58 +405,20 @@
           dataIndex: 'account'
         }
       ],
-      LBPublicIPCols: [
-        {
-          title: this.$t('label.ip'),
-          dataIndex: 'ipaddress',
-          slots: { customRender: 'ipaddress' }
-        },
-        {
-          title: this.$t('label.state'),
-          dataIndex: 'state'
-        },
-        {
-          title: this.$t('label.networkid'),
-          dataIndex: 'associatedNetworkName'
-        },
-        {
-          title: this.$t('label.vm'),
-          dataIndex: 'virtualmachinename'
-        }
-      ],
-      StaticNatCols: [
-        {
-          title: this.$t('label.ips'),
-          dataIndex: 'ipaddress',
-          slots: { customRender: 'ipaddress' }
-        },
-        {
-          title: this.$t('label.zoneid'),
-          dataIndex: 'zonename'
-        },
-        {
-          title: this.$t('label.networkid'),
-          dataIndex: 'associatedNetworkName'
-        },
-        {
-          title: this.$t('label.state'),
-          dataIndex: 'state'
-        }
-      ],
       vmCols: [
         {
+          key: 'name',
           title: this.$t('label.name'),
-          dataIndex: 'name',
-          slots: { customRender: 'name' }
+          dataIndex: 'name'
         },
         {
+          key: 'state',
           title: this.$t('label.state'),
-          dataIndex: 'state',
-          slots: { customRender: 'state' }
+          dataIndex: 'state'
         },
         {
-          title: this.$t('label.ip'),
-          slots: { customRender: 'ip' }
+          key: 'ip',
+          title: this.$t('label.ip')
         }
       ],
       customStyle: 'margin-bottom: 0; border: none',
diff --git a/ui/src/views/network/tungsten/FirewallPolicyTab.vue b/ui/src/views/network/tungsten/FirewallPolicyTab.vue
index f25997b..9be36fd 100644
--- a/ui/src/views/network/tungsten/FirewallPolicyTab.vue
+++ b/ui/src/views/network/tungsten/FirewallPolicyTab.vue
@@ -34,26 +34,28 @@
         :dataSource="dataSource"
         :rowKey="item => item.uuid"
         :pagination="false">
-        <template #name="{ text, record }">
+        <template #bodyCell="{ column, text, record }">
+          <template v-if="column.key === 'name'">
           <router-link :to="{ path: '/tungstenfirewallpolicy/' + record.uuid, query: { zoneid: zoneId } }">{{ text }}</router-link>
-        </template>
-        <template #firewallrule="{ record }">
-          <span v-if="record.firewallrule.length > 0">{{ record.firewallrule[0].name }}</span>
-        </template>
-        <template #action="{ record }">
-          <a-popconfirm
-            :title="$t('label.confirm.delete.tungsten.firewall.policy')"
-            @confirm="removeFirewallRule(record.uuid)"
-            :okText="$t('label.yes')"
-            :cancelText="$t('label.no')">
-            <tooltip-button
-              tooltipPlacement="bottom"
-              :tooltip="$t('label.delete.tungsten.firewall.policy')"
-              danger
-              type="primary"
-              icon="delete-outlined"
-              :loading="deleteLoading" />
-          </a-popconfirm>
+          </template>
+          <template v-if="column.key === 'firewallrule'">
+            <span v-if="record.firewallrule.length > 0">{{ record.firewallrule[0].name }}</span>
+          </template>
+          <template v-if="column.key === 'actions'">
+            <a-popconfirm
+              :title="$t('label.confirm.delete.tungsten.firewall.policy')"
+              @confirm="removeFirewallRule(record.uuid)"
+              :okText="$t('label.yes')"
+              :cancelText="$t('label.no')">
+              <tooltip-button
+                tooltipPlacement="bottom"
+                :tooltip="$t('label.delete.tungsten.firewall.policy')"
+                danger
+                type="primary"
+                icon="delete-outlined"
+                :loading="deleteLoading" />
+            </a-popconfirm>
+          </template>
         </template>
       </a-table>
       <div style="display: block; text-align: right; margin-top: 10px;">
@@ -146,14 +148,14 @@
       columns: [{
         title: this.$t('label.name'),
         dataIndex: 'name',
-        slots: { customRender: 'name' }
+        key: 'name'
       }, {
         title: this.$t('label.firewallrule'),
         dataIndex: 'firewallrule',
-        slots: { customRender: 'firewallrule' }
+        key: 'firewallrule'
       }, {
-        title: this.$t('label.action'),
-        slots: { customRender: 'action' },
+        title: this.$t('label.actions'),
+        key: 'actions',
         width: 80
       }],
       dataSource: [],
diff --git a/ui/src/views/network/tungsten/FirewallRuleTab.vue b/ui/src/views/network/tungsten/FirewallRuleTab.vue
index 7bfaa71..c19cdda 100644
--- a/ui/src/views/network/tungsten/FirewallRuleTab.vue
+++ b/ui/src/views/network/tungsten/FirewallRuleTab.vue
@@ -34,20 +34,22 @@
         :dataSource="dataSource"
         :rowKey="item => item.uuid"
         :pagination="false">
-        <template #actions="{ record }">
-          <a-popconfirm
-            :title="$t('message.confirm.remove.firewall.rule')"
-            @confirm="removeFirewallRule(record.uuid)"
-            :okText="$t('label.yes')"
-            :cancelText="$t('label.no')">
-            <tooltip-button
-              tooltipPlacement="bottom"
-              :tooltip="$t('label.remove.firewall.rule')"
-              danger
-              type="primary"
-              icon="delete-outlined"
-              :loading="deleteLoading" />
-          </a-popconfirm>
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.key === 'actions'">
+            <a-popconfirm
+              :title="$t('message.confirm.remove.firewall.rule')"
+              @confirm="removeFirewallRule(record.uuid)"
+              :okText="$t('label.yes')"
+              :cancelText="$t('label.no')">
+              <tooltip-button
+                tooltipPlacement="bottom"
+                :tooltip="$t('label.remove.firewall.rule')"
+                danger
+                type="primary"
+                icon="delete-outlined"
+                :loading="deleteLoading" />
+            </a-popconfirm>
+          </template>
         </template>
       </a-table>
       <div style="display: block; text-align: right; margin-top: 10px;">
@@ -96,9 +98,9 @@
             <a-select
               v-model:value="form.action"
               showSearch
-              optionFilterProp="label"
+              optionFilterProp="value"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :placeholder="apiParams.action.description">
               <a-select-option value="pass">PASS</a-select-option>
@@ -114,11 +116,14 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="serviceGroup.loading"
               :placeholder="apiParams.servicegroupuuid.description">
-              <a-select-option v-for="group in serviceGroup.opts" :key="group.uuid">
+              <a-select-option
+                v-for="group in serviceGroup.opts"
+                :key="group.uuid"
+                :label="group.name || group.description || group.displaytext">
                 {{ group.name || group.description || group.displaytext }}
               </a-select-option>
             </a-select>
@@ -142,11 +147,14 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="srcTag.loading"
               :placeholder="apiParams.srctaguuid.description">
-              <a-select-option v-for="tag in srcTag.opts" :key="tag.uuid">
+              <a-select-option
+                v-for="tag in srcTag.opts"
+                :key="tag.uuid"
+                :label="tag.name || tag.description || tag.displaytext">
                 {{ tag.name || tag.description || tag.displaytext }}
               </a-select-option>
             </a-select>
@@ -160,11 +168,14 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="srcAddress.loading"
               :placeholder="apiParams.srcaddressgroupuuid.description">
-              <a-select-option v-for="address in srcAddress.opts" :key="address.uuid">
+              <a-select-option
+                v-for="address in srcAddress.opts"
+                :key="address.uuid"
+                :label="address.name || address.description || address.displaytext">
                 {{ address.name || address.description || address.displaytext }}
               </a-select-option>
             </a-select>
@@ -178,11 +189,11 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="networks.loading"
               :placeholder="apiParams.srcnetworkuuid.description">
-              <a-select-option v-for="network in networks.opts" :key="network.uuid">
+              <a-select-option v-for="network in networks.opts" :key="network.uuid" :label="network.name || network.description || network.displaytext">
                 {{ network.name || network.description || network.displaytext }}
               </a-select-option>
             </a-select>
@@ -194,9 +205,9 @@
             <a-select
               v-model:value="form.direction"
               showSearch
-              optionFilterProp="label"
+              optionFilterProp="value"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :placeholder="apiParams.direction.description">
               <a-select-option value="oneway">ONE WAY</a-select-option>
@@ -222,11 +233,11 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="srcTag.loading"
               :placeholder="apiParams.desttaguuid.description">
-              <a-select-option v-for="tag in srcTag.opts" :key="tag.uuid">
+              <a-select-option v-for="tag in srcTag.opts" :key="tag.uuid" :label="tag.name || tag.description || tag.displaytext">
                 {{ tag.name || tag.description || tag.displaytext }}
               </a-select-option>
             </a-select>
@@ -240,11 +251,11 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="srcAddress.loading"
               :placeholder="apiParams.destaddressgroupuuid.description">
-              <a-select-option v-for="address in srcAddress.opts" :key="address.uuid">
+              <a-select-option v-for="address in srcAddress.opts" :key="address.uuid" :label="address.name || address.description || address.displaytext">
                 {{ address.name || address.description || address.displaytext }}
               </a-select-option>
             </a-select>
@@ -258,11 +269,11 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="networks.loading"
               :placeholder="apiParams.destnetworkuuid.description">
-              <a-select-option v-for="network in networks.opts" :key="network.uuid">
+              <a-select-option v-for="network in networks.opts" :key="network.uuid" :label="network.name || network.description || network.displaytext">
                 {{ network.name || network.description || network.displaytext }}
               </a-select-option>
             </a-select>
@@ -276,11 +287,11 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               :loading="tagType.loading"
               :placeholder="apiParams.tagtypeuuid.description">
-              <a-select-option v-for="tag in tagType.opts" :key="tag.uuid">
+              <a-select-option v-for="tag in tagType.opts" :key="tag.uuid" :label="tag.name || tag.description || tag.displaytext">
                 {{ tag.name || tag.description || tag.displaytext }}
               </a-select-option>
             </a-select>
@@ -357,7 +368,7 @@
         dataIndex: 'tagtype'
       }, {
         title: this.$t('label.actions'),
-        slots: { customRender: 'actions' },
+        key: 'actions',
         width: 80
       }],
       dataSource: [],
diff --git a/ui/src/views/network/tungsten/FirewallTagTab.vue b/ui/src/views/network/tungsten/FirewallTagTab.vue
index 8373130..b1e08e9 100644
--- a/ui/src/views/network/tungsten/FirewallTagTab.vue
+++ b/ui/src/views/network/tungsten/FirewallTagTab.vue
@@ -34,20 +34,22 @@
         :dataSource="dataSource"
         :rowKey="item => item.uuid"
         :pagination="false">
-        <template #action="{ record }">
-          <a-popconfirm
-            :title="$t('message.delete.tungsten.tag')"
-            @confirm="removeTag(record.uuid)"
-            :okText="$t('label.yes')"
-            :cancelText="$t('label.no')">
-            <tooltip-button
-              tooltipPlacement="bottom"
-              :tooltip="$t('label.remove.tag')"
-              danger
-              type="primary"
-              icon="delete-outlined"
-              :loading="deleteLoading" />
-          </a-popconfirm>
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.key === 'actions'">
+            <a-popconfirm
+              :title="$t('message.delete.tungsten.tag')"
+              @confirm="removeTag(record.uuid)"
+              :okText="$t('label.yes')"
+              :cancelText="$t('label.no')">
+              <tooltip-button
+                tooltipPlacement="bottom"
+                :tooltip="$t('label.remove.tag')"
+                danger
+                type="primary"
+                icon="delete-outlined"
+                :loading="deleteLoading" />
+            </a-popconfirm>
+          </template>
         </template>
       </a-table>
       <a-divider/>
@@ -89,11 +91,11 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }"
               v-model:value="form.taguuid"
               :placeholder="apiParams.taguuid.description">
-              <a-select-option v-for="opt in tagSrc.opts" :key="opt.uuid">{{ opt.name }}</a-select-option>
+              <a-select-option v-for="opt in tagSrc.opts" :key="opt.uuid" :label="opt.name">{{ opt.name }}</a-select-option>
             </a-select>
           </a-form-item>
 
@@ -141,8 +143,8 @@
         title: this.$t('label.name'),
         dataIndex: 'name'
       }, {
-        title: this.$t('label.action'),
-        slots: { customRender: 'action' },
+        title: this.$t('label.actions'),
+        key: 'actions',
         width: 80
       }],
       page: 1,
diff --git a/ui/src/views/network/tungsten/LogicalRouterTab.vue b/ui/src/views/network/tungsten/LogicalRouterTab.vue
index 60b3cfc..5334d5b 100644
--- a/ui/src/views/network/tungsten/LogicalRouterTab.vue
+++ b/ui/src/views/network/tungsten/LogicalRouterTab.vue
@@ -110,9 +110,9 @@
         title: this.$t('label.name'),
         dataIndex: 'name'
       }, {
-        title: this.$t('label.action'),
-        dataIndex: 'action',
-        slots: { customRender: 'action' },
+        title: this.$t('label.actions'),
+        dataIndex: 'actions',
+        key: 'actions',
         width: 80
       }],
       dataSource: [],
diff --git a/ui/src/views/network/tungsten/NetworkPolicyTab.vue b/ui/src/views/network/tungsten/NetworkPolicyTab.vue
index 91e27e7..b1970d0 100644
--- a/ui/src/views/network/tungsten/NetworkPolicyTab.vue
+++ b/ui/src/views/network/tungsten/NetworkPolicyTab.vue
@@ -32,22 +32,24 @@
       :dataSource="dataSource"
       :rowKey="(item, index) => index"
       :pagination="false">
-      <template #action="{ record }">
-        <a-popconfirm
-          v-if="'removeTungstenFabricPolicy' in $store.getters.apis"
-          placement="topRight"
-          :title="$t('message.confirm.remove.network.policy')"
-          :ok-text="$t('label.yes')"
-          :cancel-text="$t('label.no')"
-          :loading="deleteLoading"
-          @confirm="removeNetworkPolicy(record)"
-        >
-          <tooltip-button
-            :tooltip="$t('label.action.remove.network.policy')"
-            danger
-            type="primary"
-            icon="delete-outlined" />
-        </a-popconfirm>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'actions'">
+          <a-popconfirm
+            v-if="'removeTungstenFabricPolicy' in $store.getters.apis"
+            placement="topRight"
+            :title="$t('message.confirm.remove.network.policy')"
+            :ok-text="$t('label.yes')"
+            :cancel-text="$t('label.no')"
+            :loading="deleteLoading"
+            @confirm="removeNetworkPolicy(record)"
+          >
+            <tooltip-button
+              :tooltip="$t('label.action.remove.network.policy')"
+              danger
+              type="primary"
+              icon="delete-outlined" />
+          </a-popconfirm>
+        </template>
       </template>
     </a-table>
     <div style="display: block; text-align: right; margin-top: 10px;">
@@ -143,9 +145,9 @@
         title: this.$t('label.name'),
         dataIndex: 'name'
       }, {
-        title: this.$t('label.action'),
-        dataIndex: 'action',
-        slots: { customRender: 'action' },
+        title: this.$t('label.actions'),
+        dataIndex: 'actions',
+        key: 'actions',
         width: 80
       }],
       dataSource: [],
diff --git a/ui/src/views/network/tungsten/TungstenFabric.vue b/ui/src/views/network/tungsten/TungstenFabric.vue
index 066e32b..25ebf85 100644
--- a/ui/src/views/network/tungsten/TungstenFabric.vue
+++ b/ui/src/views/network/tungsten/TungstenFabric.vue
@@ -87,16 +87,16 @@
             {
               dataIndex: 'name',
               title: this.$t('label.name'),
-              slots: { customRender: 'name' }
+              key: 'name'
             },
             {
               dataIndex: 'network',
               title: this.$t('label.network'),
-              slots: { customRender: 'network' }
+              key: 'network'
             },
             {
-              title: this.$t('label.action'),
-              slots: { customRender: 'action' },
+              title: this.$t('label.actions'),
+              key: 'actions',
               width: 150
             }
           ]
@@ -135,21 +135,21 @@
             {
               dataIndex: 'name',
               title: this.$t('label.name'),
-              slots: { customRender: 'name' }
+              key: 'name'
             },
             {
               dataIndex: 'firewallpolicy',
               title: this.$t('label.firewallpolicy'),
-              slots: { customRender: 'firewallpolicy' }
+              key: 'firewallpolicy'
             },
             {
               dataIndex: 'tag',
               title: this.$t('label.tag'),
-              slots: { customRender: 'tag' }
+              key: 'tag'
             },
             {
-              title: this.$t('label.action'),
-              slots: { customRender: 'action' },
+              title: this.$t('label.actions'),
+              key: 'actions',
               width: 150
             }
           ]
@@ -206,14 +206,14 @@
           columns: [{
             dataIndex: 'name',
             title: this.$t('label.name'),
-            slots: { customRender: 'name' }
+            key: 'name'
           }, {
             dataIndex: 'network',
             title: this.$t('label.network'),
-            slots: { customRender: 'network' }
+            key: 'network'
           }, {
-            title: this.$t('label.action'),
-            slots: { customRender: 'action' },
+            title: this.$t('label.actions'),
+            key: 'actions',
             width: 150
           }]
         },
@@ -298,11 +298,11 @@
             {
               dataIndex: 'name',
               title: this.$t('label.name'),
-              slots: { customRender: 'name' }
+              key: 'name'
             },
             {
-              title: this.$t('label.action'),
-              slots: { customRender: 'action' },
+              title: this.$t('label.actions'),
+              key: 'actions',
               width: 150
             }
           ]
@@ -338,10 +338,10 @@
           columns: [{
             dataIndex: 'name',
             title: this.$t('label.name'),
-            slots: { customRender: 'name' }
+            key: 'name'
           }, {
-            title: this.$t('label.action'),
-            slots: { customRender: 'action' },
+            title: this.$t('label.actions'),
+            key: 'actions',
             width: 150
           }]
         },
@@ -411,26 +411,26 @@
             {
               dataIndex: 'name',
               title: this.$t('label.name'),
-              slots: { customRender: 'name' }
+              key: 'name'
             },
             {
               dataIndex: 'protocol',
               title: this.$t('label.protocol'),
-              slots: { customRender: 'protocol' }
+              key: 'protocol'
             },
             {
               dataIndex: 'startport',
               title: this.$t('label.startport'),
-              slots: { customRender: 'startport' }
+              key: 'startport'
             },
             {
               dataIndex: 'endport',
               title: this.$t('label.endport'),
-              slots: { customRender: 'endport' }
+              key: 'endport'
             },
             {
-              title: this.$t('label.action'),
-              slots: { customRender: 'action' },
+              title: this.$t('label.actions'),
+              key: 'actions',
               width: 150
             }
           ]
@@ -476,21 +476,21 @@
             {
               dataIndex: 'name',
               title: this.$t('label.name'),
-              slots: { customRender: 'name' }
+              key: 'name'
             },
             {
               dataIndex: 'ipprefix',
               title: this.$t('label.ipprefix'),
-              slots: { customRender: 'ipprefix' }
+              key: 'ipprefix'
             },
             {
               dataIndex: 'ipprefixlen',
               title: this.$t('label.ipprefixlen'),
-              slots: { customRender: 'ipprefixlen' }
+              key: 'ipprefixlen'
             },
             {
-              title: this.$t('label.action'),
-              slots: { customRender: 'action' },
+              title: this.$t('label.actions'),
+              key: 'actions',
               width: 150
             }
           ]
diff --git a/ui/src/views/network/tungsten/TungstenFabricPolicyRule.vue b/ui/src/views/network/tungsten/TungstenFabricPolicyRule.vue
index 0b0b3d5..c842224 100644
--- a/ui/src/views/network/tungsten/TungstenFabricPolicyRule.vue
+++ b/ui/src/views/network/tungsten/TungstenFabricPolicyRule.vue
@@ -32,28 +32,30 @@
       :dataSource="dataSource"
       :rowKey="(item, index) => index"
       :pagination="false">
-      <template #sourceport="{ record }">
-        <span>{{ record.srcstartport + ':' + record.srcendport }}</span>
-      </template>
-      <template #destport="{ record }">
-        <span>{{ record.deststartport + ':' + record.destendport }}</span>
-      </template>
-      <template #ruleAction="{ record }">
-        <a-popconfirm
-          v-if="'removeTungstenFabricPolicyRule' in $store.getters.apis"
-          placement="topRight"
-          :title="$t('message.delete.tungsten.policy.rule')"
-          :ok-text="$t('label.yes')"
-          :cancel-text="$t('label.no')"
-          :loading="deleteLoading"
-          @confirm="deleteRule(record)"
-        >
-          <tooltip-button
-            :tooltip="$t('label.delete.rule')"
-            danger
-            type="primary"
-            icon="delete-outlined" />
-        </a-popconfirm>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'sourceport'">
+          <span>{{ record.srcstartport + ':' + record.srcendport }}</span>
+        </template>
+        <template v-if="column.key === 'destport'">
+          <span>{{ record.deststartport + ':' + record.destendport }}</span>
+        </template>
+        <template v-if="column.key === 'ruleAction'">
+          <a-popconfirm
+            v-if="'removeTungstenFabricPolicyRule' in $store.getters.apis"
+            placement="topRight"
+            :title="$t('message.delete.tungsten.policy.rule')"
+            :ok-text="$t('label.yes')"
+            :cancel-text="$t('label.no')"
+            :loading="deleteLoading"
+            @confirm="deleteRule(record)"
+          >
+            <tooltip-button
+              :tooltip="$t('label.delete.rule')"
+              danger
+              type="primary"
+              icon="delete-outlined" />
+          </a-popconfirm>
+        </template>
       </template>
     </a-table>
 
@@ -247,43 +249,43 @@
       pageSize: this.$store.getters.defaultListViewPageSize,
       columns: [
         {
-          title: this.$t('label.action'),
-          dataIndex: 'action',
-          slots: { customRender: 'action' }
+          title: this.$t('label.actions'),
+          dataIndex: 'actions',
+          key: 'actions'
         },
         {
           title: this.$t('label.direction'),
           dataIndex: 'direction',
-          slots: { customRender: 'direction' }
+          key: 'direction'
         },
         {
           title: this.$t('label.protocol'),
           dataIndex: 'protocol',
-          slots: { customRender: 'protocol' }
+          key: 'protocol'
         },
         {
           title: this.$t('label.srcnetwork'),
           dataIndex: 'srcnetwork',
-          slots: { customRender: 'srcnetwork' }
+          key: 'srcnetwork'
         },
         {
           title: this.$t('label.sourceport'),
           dataIndex: 'sourceport',
-          slots: { customRender: 'sourceport' }
+          key: 'sourceport'
         },
         {
           title: this.$t('label.destnetwork'),
           dataIndex: 'destnetwork',
-          slots: { customRender: 'destnetwork' }
+          key: 'destnetwork'
         },
         {
           title: this.$t('label.destport'),
           dataIndex: 'destport',
-          slots: { customRender: 'destport' }
+          key: 'destport'
         },
         {
           dataIndex: 'ruleAction',
-          slots: { customRender: 'ruleAction' },
+          key: 'ruleAction',
           width: 50
         }
       ]
diff --git a/ui/src/views/network/tungsten/TungstenFabricPolicyTag.vue b/ui/src/views/network/tungsten/TungstenFabricPolicyTag.vue
index d4e14cf..502279a 100644
--- a/ui/src/views/network/tungsten/TungstenFabricPolicyTag.vue
+++ b/ui/src/views/network/tungsten/TungstenFabricPolicyTag.vue
@@ -32,25 +32,27 @@
       :dataSource="dataSource"
       :rowKey="(item, index) => index"
       :pagination="false">
-      <template #policy="{ record }">
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'policy'">
         <span v-if="record.policy.length > 0">{{ record.policy[0].name }}</span>
-      </template>
-      <template #action="{ record }">
-        <a-popconfirm
-          v-if="'removeTungstenFabricTag' in $store.getters.apis"
-          placement="topRight"
-          :title="$t('message.delete.tungsten.tag')"
-          :ok-text="$t('label.yes')"
-          :cancel-text="$t('label.no')"
-          :loading="deleteLoading"
-          @confirm="deleteRule(record)"
-        >
-          <tooltip-button
-            :tooltip="$t('label.delete.tag')"
-            danger
-            type="primary"
-            icon="delete-outlined" />
-        </a-popconfirm>
+        </template>
+        <template v-if="column.key === 'actions'">
+          <a-popconfirm
+            v-if="'removeTungstenFabricTag' in $store.getters.apis"
+            placement="topRight"
+            :title="$t('message.delete.tungsten.tag')"
+            :ok-text="$t('label.yes')"
+            :cancel-text="$t('label.no')"
+            :loading="deleteLoading"
+            @confirm="deleteRule(record)"
+          >
+            <tooltip-button
+              :tooltip="$t('label.delete.tag')"
+              danger
+              type="primary"
+              icon="delete-outlined" />
+          </a-popconfirm>
+        </template>
       </template>
     </a-table>
 
@@ -147,17 +149,17 @@
         {
           title: this.$t('label.name'),
           dataIndex: 'name',
-          slots: { customRender: 'name' }
+          key: 'name'
         },
         {
           title: this.$t('label.policy'),
           dataIndex: 'policy',
-          slots: { customRender: 'policy' }
+          key: 'policy'
         },
         {
-          title: this.$t('label.action'),
-          dataIndex: 'action',
-          slots: { customRender: 'action' },
+          title: this.$t('label.actions'),
+          dataIndex: 'actions',
+          key: 'actions',
           width: 70
         }
       ]
diff --git a/ui/src/views/network/tungsten/TungstenNetworkTable.vue b/ui/src/views/network/tungsten/TungstenNetworkTable.vue
index 7bb0e90..bed85f8 100644
--- a/ui/src/views/network/tungsten/TungstenNetworkTable.vue
+++ b/ui/src/views/network/tungsten/TungstenNetworkTable.vue
@@ -25,52 +25,49 @@
       :pagination="false"
       :rowKey="(record, idx) => record.id || record.name || idx + '-' + Math.random()"
       :scroll="{ y: 350 }">
-      <template #name="{ text, record }">
-        <!-- <QuickView
-          :actions="actions"
-          :enabled="true"
-          :resource="record"
-          @exec-action="(action) => execAction(action, record)"/> -->
+      <template #bodyCell="{ column, text, record }">
+        <template v-if="column.key === 'name'">
         <router-link v-if="apiName === 'listTungstenFabricPolicy'" :to="{ path: '/tungstenpolicy/' + record.uuid, query: { zoneid: resource.zoneid } }" >{{ text }}</router-link>
         <router-link v-else-if="apiName === 'listTungstenFabricApplicationPolicySet'" :to="{ path: '/tungstenpolicyset/' + record.uuid, query: { zoneid: resource.zoneid } }" >{{ text }}</router-link>
         <span v-else>{{ text }}</span>
-      </template>
-      <template #tungstenvms="{ record }">
-        <ul v-if="record.tungstenvms.length > 0"><li v-for="item in record.tungstenvms" :key="item.uuid">{{ item.name }}</li></ul>
-      </template>
-      <template #network="{ record }">
-        <ul v-if="record.network.length > 0"><li v-for="item in record.network" :key="item.uuid"><span v-if="item.name">{{ item.name }}</span></li></ul>
-      </template>
-      <template #firewallpolicy="{ record }">
-        <span v-if="record.firewallpolicy.length > 0">{{ record.firewallpolicy.map(item => item.name).join(',') }}</span>
-      </template>
-      <template #firewallrule="{ record }">
-        <span v-if="record.firewallrule.length > 0">{{ record.firewallrule[0].name }}</span>
-      </template>
-      <template #tungstenroutingpolicyterm="{ record }">
-        <span v-if="record.tungstenroutingpolicyterm.length > 0">{{ record.tungstenroutingpolicyterm[0].name }}</span>
-      </template>
-      <template #vm="{ record }">
-        <ul v-if="record.vm.length > 0"><li v-for="item in record.vm" :key="item.uuid">{{ item.name }}</li></ul>
-      </template>
-      <template #nic="{ record }">
-        <ul v-if="record.nic.length > 0"><li v-for="item in record.nic" :key="item.uuid">{{ item.name }}</li></ul>
-      </template>
-      <template #tag="{ record }">
-        <div class="tags" v-for="tag in record.tag" :key="tag.uuid">
-          <a-tag :key="tag.uuid">{{ tag.name }}</a-tag>
-        </div>
-      </template>
-      <template #action="{ record }">
-        <span v-for="(action, index) in actions" :key="index" style="margin-right: 5px">
-          <tooltip-button
-            v-if="action.dataView && ('show' in action ? action.show(record, $store.getters) : true)"
-            :tooltip="$t(action.label)"
-            :danger="['delete-outlined', 'DeleteOutlined'].includes(action.icon)"
-            :type="(['DeleteOutlined', 'delete-outlined'].includes(action.icon) ? 'primary' : 'default')"
-            :icon="action.icon"
-            @click="() => execAction(action, record)" />
-        </span>
+        </template>
+        <template v-if="column.key === 'tungstenvms'">
+          <ul v-if="record.tungstenvms.length > 0"><li v-for="item in record.tungstenvms" :key="item.uuid">{{ item.name }}</li></ul>
+        </template>
+        <template v-if="column.key === 'network'">
+          <ul v-if="record.network.length > 0"><li v-for="item in record.network" :key="item.uuid"><span v-if="item.name">{{ item.name }}</span></li></ul>
+        </template>
+        <template v-if="column.key === 'firewallpolicy'">
+          <span v-if="record.firewallpolicy.length > 0">{{ record.firewallpolicy.map(item => item.name).join(',') }}</span>
+        </template>
+        <template v-if="column.key === 'firewallrule'">
+          <span v-if="record.firewallrule.length > 0">{{ record.firewallrule[0].name }}</span>
+        </template>
+        <template v-if="column.key === 'tungstenroutingpolicyterm'">
+          <span v-if="record.tungstenroutingpolicyterm.length > 0">{{ record.tungstenroutingpolicyterm[0].name }}</span>
+        </template>
+        <template v-if="column.key === 'vm'">
+          <ul v-if="record.vm.length > 0"><li v-for="item in record.vm" :key="item.uuid">{{ item.name }}</li></ul>
+        </template>
+        <template v-if="column.key === 'nic'">
+          <ul v-if="record.nic.length > 0"><li v-for="item in record.nic" :key="item.uuid">{{ item.name }}</li></ul>
+        </template>
+        <template v-if="column.key === 'tag'">
+          <div class="tags" v-for="tag in record.tag" :key="tag.uuid">
+            <a-tag :key="tag.uuid">{{ tag.name }}</a-tag>
+          </div>
+        </template>
+        <template v-if="column.key === 'actions'">
+          <span v-for="(action, index) in actions" :key="index" style="margin-right: 5px">
+            <tooltip-button
+              v-if="action.dataView && ('show' in action ? action.show(record, $store.getters) : true)"
+              :tooltip="$t(action.label)"
+              :danger="['delete-outlined', 'DeleteOutlined'].includes(action.icon)"
+              :type="(['DeleteOutlined', 'delete-outlined'].includes(action.icon) ? 'primary' : 'default')"
+              :icon="action.icon"
+              @click="() => execAction(action, record)" />
+          </span>
+        </template>
       </template>
     </a-table>
     <a-pagination
diff --git a/ui/src/views/offering/AddComputeOffering.vue b/ui/src/views/offering/AddComputeOffering.vue
index ae8e07e..5cd68c5 100644
--- a/ui/src/views/offering/AddComputeOffering.vue
+++ b/ui/src/views/offering/AddComputeOffering.vue
@@ -51,12 +51,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :placeholder="apiParams.systemvmtype.description">
-            <a-select-option key="domainrouter">{{ $t('label.domain.router') }}</a-select-option>
-            <a-select-option key="consoleproxy">{{ $t('label.console.proxy') }}</a-select-option>
-            <a-select-option key="secondarystoragevm">{{ $t('label.secondary.storage.vm') }}</a-select-option>
+            <a-select-option key="domainrouter" :label="$t('label.domain.router')">{{ $t('label.domain.router') }}</a-select-option>
+            <a-select-option key="consoleproxy" :label="$t('label.console.proxy')">{{ $t('label.console.proxy') }}</a-select-option>
+            <a-select-option key="secondarystoragevm" :label="$t('label.secondary.storage.vm')">{{ $t('label.secondary.storage.vm') }}</a-select-option>
           </a-select>
         </a-form-item>
         <a-form-item name="offeringtype" ref="offeringtype" :label="$t('label.offeringtype')" v-show="!isSystem">
@@ -218,12 +218,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="deploymentPlannerLoading"
             :placeholder="apiParams.deploymentplanner.description"
             @change="val => { handleDeploymentPlannerChange(val) }">
-            <a-select-option v-for="(opt) in deploymentPlanners" :key="opt.name">
+            <a-select-option v-for="(opt) in deploymentPlanners" :key="opt.name" :label="opt.name || opt.description || ''">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -259,10 +259,10 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :placeholder="$t('label.vgputype')">
-            <a-select-option v-for="(opt, optIndex) in vGpuTypes" :key="optIndex">
+            <a-select-option v-for="(opt, optIndex) in vGpuTypes" :key="optIndex" :label="opt">
               {{ opt }}
             </a-select-option>
           </a-select>
@@ -331,9 +331,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option v-for="policy in storagePolicies" :key="policy.id">
+            <a-select-option v-for="policy in storagePolicies" :key="policy.id" :label="policy.name || policy.id || ''">
               {{ policy.name || policy.id }}
             </a-select-option>
           </a-select>
@@ -516,9 +516,9 @@
                     mode="tags"
                     v-model:value="form.storagetags"
                     showSearch
-                    optionFilterProp="label"
+                    optionFilterProp="value"
                     :filterOption="(input, option) => {
-                      return option.children?.[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                      return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
                     }"
                     :loading="storageTagLoading"
                     :placeholder="apiParams.tags.description"
@@ -707,7 +707,6 @@
       })
       this.rules = reactive({
         name: [{ required: true, message: this.$t('message.error.required.input') }],
-        displaytext: [{ required: true, message: this.$t('message.error.required.input') }],
         cpunumber: [
           { required: true, message: this.$t('message.error.required.input') },
           this.naturalNumberRule
diff --git a/ui/src/views/offering/AddDiskOffering.vue b/ui/src/views/offering/AddDiskOffering.vue
index 880eae5..576721d 100644
--- a/ui/src/views/offering/AddDiskOffering.vue
+++ b/ui/src/views/offering/AddDiskOffering.vue
@@ -205,9 +205,9 @@
             mode="tags"
             v-model:value="form.tags"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children?.[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="storageTagLoading"
             :placeholder="apiParams.tags.description"
@@ -278,9 +278,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option v-for="policy in storagePolicies" :key="policy.id">
+            <a-select-option v-for="policy in storagePolicies" :key="policy.id" :label="policy.name || policy.id || ''">
               {{ policy.name || policy.id }}
             </a-select-option>
           </a-select>
@@ -357,7 +357,6 @@
       })
       this.rules = reactive({
         name: [{ required: true, message: this.$t('message.error.required.input') }],
-        displaytext: [{ required: true, message: this.$t('message.error.required.input') }],
         disksize: [
           { required: true, message: this.$t('message.error.required.input') },
           { type: 'number', validator: this.validateNumber }
diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue
index abdb9da..17359e4 100644
--- a/ui/src/views/offering/AddNetworkOffering.vue
+++ b/ui/src/views/offering/AddNetworkOffering.vue
@@ -252,11 +252,11 @@
             optionFilterProp="label"
             v-model:value="form.serviceofferingid"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="serviceOfferingLoading"
             :placeholder="apiParams.serviceofferingid.description">
-            <a-select-option v-for="(opt) in serviceOfferings" :key="opt.id">
+            <a-select-option v-for="(opt) in serviceOfferings" :key="opt.id" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -320,11 +320,11 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="registeredServicePackageLoading"
             :placeholder="$t('label.service.lb.netscaler.servicepackages')">
-            <a-select-option v-for="(opt, optIndex) in registeredServicePackages" :key="optIndex">
+            <a-select-option v-for="(opt, optIndex) in registeredServicePackages" :key="optIndex" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -577,7 +577,6 @@
       })
       this.rules = reactive({
         name: [{ required: true, message: this.$t('message.error.name') }],
-        displaytext: [{ required: true, message: this.$t('message.error.description') }],
         networkrate: [{ type: 'number', validator: this.validateNumber }],
         serviceofferingid: [{ required: true, message: this.$t('message.error.select') }],
         domainid: [{ type: 'array', required: true, message: this.$t('message.error.select') }],
diff --git a/ui/src/views/offering/AddVpcOffering.vue b/ui/src/views/offering/AddVpcOffering.vue
index 9b9d576..738a03a 100644
--- a/ui/src/views/offering/AddVpcOffering.vue
+++ b/ui/src/views/offering/AddVpcOffering.vue
@@ -108,11 +108,11 @@
             optionFilterProp="label"
             v-model:value="form.serviceofferingid"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="serviceOfferingLoading"
             :placeholder="apiParams.serviceofferingid.description">
-            <a-select-option v-for="(opt) in serviceOfferings" :key="opt.id">
+            <a-select-option v-for="(opt) in serviceOfferings" :key="opt.id" :label="opt.name || opt.description">
               {{ opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -245,7 +245,6 @@
       })
       this.rules = reactive({
         name: [{ required: true, message: this.$t('message.error.name') }],
-        displaytext: [{ required: true, message: this.$t('message.error.description') }],
         domainid: [{ type: 'array', required: true, message: this.$t('message.error.select') }],
         zoneid: [{
           type: 'array',
diff --git a/ui/src/views/offering/ImportBackupOffering.vue b/ui/src/views/offering/ImportBackupOffering.vue
index a8becc9..9b8e9d6 100644
--- a/ui/src/views/offering/ImportBackupOffering.vue
+++ b/ui/src/views/offering/ImportBackupOffering.vue
@@ -72,9 +72,9 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
-          <a-select-option v-for="opt in externals.opts" :key="opt.id">
+          <a-select-option v-for="opt in externals.opts" :key="opt.id" :label="opt.name">
             {{ opt.name }}
           </a-select-option>
         </a-select>
diff --git a/ui/src/views/plugins/quota/QuotaBalance.vue b/ui/src/views/plugins/quota/QuotaBalance.vue
index ce8f28d..ab81615 100644
--- a/ui/src/views/plugins/quota/QuotaBalance.vue
+++ b/ui/src/views/plugins/quota/QuotaBalance.vue
@@ -26,11 +26,13 @@
       :pagination="false"
       :scroll="{ y: '55vh' }"
     >
-      <template #quota="{ text }">
-        <span v-if="text!==null">{{ `${currency} ${text}` }}</span>
-      </template>
-      <template #credit="{ text }">
-        <span v-if="text!==null">{{ `${currency} ${text}` }}</span>
+      <template #bodyCell="{ column, text }">
+        <template v-if="column.key === 'quota'">
+          <span v-if="text!==null">{{ `${currency} ${text}` }}</span>
+        </template>
+        <template v-if="column.key === 'credit'">
+          <span v-if="text!==null">{{ `${currency} ${text}` }}</span>
+        </template>
       </template>
     </a-table>
   </div>
@@ -65,22 +67,22 @@
     columns () {
       return [
         {
+          key: 'date',
           title: this.$t('label.date'),
           dataIndex: 'date',
-          width: 'calc(100% / 3)',
-          slots: { customRender: 'date' }
+          width: 'calc(100% / 3)'
         },
         {
+          key: 'quota',
           title: this.$t('label.quota.value'),
           dataIndex: 'quota',
-          width: 'calc(100% / 3)',
-          slots: { customRender: 'quota' }
+          width: 'calc(100% / 3)'
         },
         {
+          key: 'credit',
           title: this.$t('label.credit'),
           dataIndex: 'credit',
-          width: 'calc(100% / 3)',
-          slots: { customRender: 'credit' }
+          width: 'calc(100% / 3)'
         }
       ]
     }
diff --git a/ui/src/views/plugins/quota/QuotaUsage.vue b/ui/src/views/plugins/quota/QuotaUsage.vue
index f8e339f..04a5f4f 100644
--- a/ui/src/views/plugins/quota/QuotaUsage.vue
+++ b/ui/src/views/plugins/quota/QuotaUsage.vue
@@ -26,8 +26,10 @@
       :pagination="false"
       :scroll="{ y: '55vh' }"
     >
-      <template #quota="{ text }">
-        <span v-if="text!==undefined">{{ `${currency} ${text}` }}</span>
+      <template #bodyCell="{ column, text }">
+        <template v-if="column.key === 'quota'">
+          <span v-if="text!==undefined">{{ `${currency} ${text}` }}</span>
+        </template>
       </template>
     </a-table>
   </div>
@@ -63,22 +65,22 @@
     columns () {
       return [
         {
+          key: 'name',
           title: this.$t('label.quota.type.name'),
           dataIndex: 'name',
-          width: 'calc(100% / 3)',
-          slots: { customRender: 'name' }
+          width: 'calc(100% / 3)'
         },
         {
+          key: 'unit',
           title: this.$t('label.quota.type.unit'),
           dataIndex: 'unit',
-          width: 'calc(100% / 3)',
-          slots: { customRender: 'unit' }
+          width: 'calc(100% / 3)'
         },
         {
+          key: 'quota',
           title: this.$t('label.quota.usage'),
           dataIndex: 'quota',
-          width: 'calc(100% / 3)',
-          slots: { customRender: 'quota' }
+          width: 'calc(100% / 3)'
         }
       ]
     }
diff --git a/ui/src/views/project/AccountsTab.vue b/ui/src/views/project/AccountsTab.vue
index fd3408b..8c7282b 100644
--- a/ui/src/views/project/AccountsTab.vue
+++ b/ui/src/views/project/AccountsTab.vue
@@ -26,42 +26,44 @@
           :dataSource="dataSource"
           :pagination="false"
           :rowKey="rowItem => rowItem.userid ? rowItem.userid : (rowItem.accountid || rowItem.account)">
-          <template #user="{ record }">
-            <span v-if="record.userid">{{ record.username }}</span>
-          </template>
-          <template #projectrole="{ record }">
-            <span v-if="record.projectroleid">{{ getProjectRole(record) }}</span>
-          </template>
-          <template #action="{ record }">
-            <div>
-              <span v-if="imProjectAdmin && dataSource.length > 1" class="account-button-action">
-                <tooltip-button
-                  tooltipPlacement="top"
-                  :tooltip="record.userid ? $t('label.make.user.project.owner') : $t('label.make.project.owner')"
-                  v-if="record.role !== owner"
-                  type="default"
-                  icon="arrow-up-outlined"
-                  size="small"
-                  @onClick="promoteAccount(record)" />
-                <tooltip-button
-                  tooltipPlacement="top"
-                  :tooltip="record.userid ? $t('label.demote.project.owner.user') : $t('label.demote.project.owner')"
-                  v-if="updateProjectApi.params.filter(x => x.name === 'swapowner').length > 0 && record.role === owner"
-                  type="default"
-                  icon="arrow-down-outlined"
-                  size="small"
-                  @onClick="demoteAccount(record)" />
-                <tooltip-button
-                  tooltipPlacement="top"
-                  :tooltip="record.userid ? $t('label.remove.project.user') : $t('label.remove.project.account')"
-                  type="primary"
-                  :danger="true"
-                  icon="delete-outlined"
-                  size="small"
-                  :disabled="!('deleteAccountFromProject' in $store.getters.apis)"
-                  @onClick="onShowConfirmDelete(record)" />
-              </span>
-            </div>
+          <template #bodyCell="{ column, record }">
+            <template v-if="column.key === 'user'">
+              <span v-if="record.userid">{{ record.username }}</span>
+            </template>
+            <template v-if="column.key === 'projectrole'">
+              <span v-if="record.projectroleid">{{ getProjectRole(record) }}</span>
+            </template>
+            <template v-if="column.key === 'actions'">
+              <div>
+                <span v-if="imProjectAdmin && dataSource.length > 1" class="account-button-action">
+                  <tooltip-button
+                    tooltipPlacement="top"
+                    :tooltip="record.userid ? $t('label.make.user.project.owner') : $t('label.make.project.owner')"
+                    v-if="record.role !== owner"
+                    type="default"
+                    icon="arrow-up-outlined"
+                    size="small"
+                    @onClick="promoteAccount(record)" />
+                  <tooltip-button
+                    tooltipPlacement="top"
+                    :tooltip="record.userid ? $t('label.demote.project.owner.user') : $t('label.demote.project.owner')"
+                    v-if="updateProjectApi.params.filter(x => x.name === 'swapowner').length > 0 && record.role === owner"
+                    type="default"
+                    icon="arrow-down-outlined"
+                    size="small"
+                    @onClick="demoteAccount(record)" />
+                  <tooltip-button
+                    tooltipPlacement="top"
+                    :tooltip="record.userid ? $t('label.remove.project.user') : $t('label.remove.project.account')"
+                    type="primary"
+                    :danger="true"
+                    icon="delete-outlined"
+                    size="small"
+                    :disabled="!('deleteAccountFromProject' in $store.getters.apis)"
+                    @onClick="onShowConfirmDelete(record)" />
+                </span>
+              </div>
+            </template>
           </template>
         </a-table>
         <a-pagination
@@ -122,31 +124,31 @@
   created () {
     this.columns = [
       {
+        key: 'account',
         title: this.$t('label.account'),
-        dataIndex: 'account',
-        slots: { customRender: 'account' }
+        dataIndex: 'account'
       },
       {
+        key: 'role',
         title: this.$t('label.roletype'),
-        dataIndex: 'role',
-        slots: { customRender: 'role' }
+        dataIndex: 'role'
       },
       {
-        title: this.$t('label.action'),
-        dataIndex: 'action',
-        slots: { customRender: 'action' }
+        key: 'actions',
+        title: this.$t('label.actions'),
+        dataIndex: 'actions'
       }
     ]
     if (this.isProjectRolesSupported()) {
       this.columns.splice(1, 0, {
+        key: 'user',
         title: this.$t('label.user'),
-        dataIndex: 'userid',
-        slots: { customRender: 'user' }
+        dataIndex: 'userid'
       })
       this.columns.splice(this.columns.length - 1, 0, {
+        key: 'projectrole',
         title: this.$t('label.project.role'),
-        dataIndex: 'projectroleid',
-        slots: { customRender: 'projectrole' }
+        dataIndex: 'projectroleid'
       })
     }
     this.page = 1
diff --git a/ui/src/views/project/AddAccountOrUserToProject.vue b/ui/src/views/project/AddAccountOrUserToProject.vue
index 31af9b0..e65c6a7 100644
--- a/ui/src/views/project/AddAccountOrUserToProject.vue
+++ b/ui/src/views/project/AddAccountOrUserToProject.vue
@@ -55,9 +55,9 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
-              <a-select-option v-for="role in projectRoles" :key="role.id">
+              <a-select-option v-for="role in projectRoles" :key="role.id" :label="role.name">
                 {{ role.name }}
               </a-select-option>
             </a-select>
@@ -70,9 +70,9 @@
               v-model:value="form.roletype"
               :placeholder="apiParams.addAccountToProject.roletype.description"
               showSearch
-              optionFilterProp="label"
+              optionFilterProp="value"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
               <a-select-option value="Admin">Admin</a-select-option>
               <a-select-option value="Regular">Regular</a-select-option>
@@ -128,9 +128,9 @@
               showSearch
               optionFilterProp="label"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
-              <a-select-option v-for="role in projectRoles" :key="role.id">
+              <a-select-option v-for="role in projectRoles" :key="role.id" :label="role.name">
                 {{ role.name }}
               </a-select-option>
             </a-select>
@@ -143,9 +143,9 @@
               v-model:value="form.roletype"
               :placeholder="apiParams.addUserToProject.roletype.description"
               showSearch
-              optionFilterProp="label"
+              optionFilterProp="value"
               :filterOption="(input, option) => {
-                return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
               }" >
               <a-select-option value="Admin">Admin</a-select-option>
               <a-select-option value="Regular">Regular</a-select-option>
diff --git a/ui/src/views/project/InvitationsTemplate.vue b/ui/src/views/project/InvitationsTemplate.vue
index af13412..88159fc 100644
--- a/ui/src/views/project/InvitationsTemplate.vue
+++ b/ui/src/views/project/InvitationsTemplate.vue
@@ -36,26 +36,28 @@
           :pagination="false"
           :rowKey="record => record.id || record.account"
           @change="onChangeTable">
-          <template #state="{ text }">
-            <status :text="text ? text : ''" displayText />
-          </template>
-          <template #action="{ record }">
-            <div v-if="record.state===stateAllow" class="account-button-action">
-              <tooltip-button
-                tooltipPlacement="top"
-                :tooltip="$t('label.accept.project.invitation')"
-                icon="check-outlined"
-                size="small"
-                @onClick="onShowConfirmAcceptInvitation(record)"/>
-              <tooltip-button
-                tooltipPlacement="top"
-                :tooltip="$t('label.decline.invitation')"
-                type="primary"
-                :danger="true"
-                icon="close-outlined"
-                size="small"
-                @onClick="onShowConfirmRevokeInvitation(record)"/>
-            </div>
+          <template #bodyCell="{ column, text, record }">
+            <template v-if="column.key === 'state'">
+              <status :text="text ? text : ''" displayText />
+            </template>
+            <template v-if="column.key === 'actions'">
+              <div v-if="record.state===stateAllow" class="account-button-action">
+                <tooltip-button
+                  tooltipPlacement="top"
+                  :tooltip="$t('label.accept.project.invitation')"
+                  icon="check-outlined"
+                  size="small"
+                  @onClick="onShowConfirmAcceptInvitation(record)"/>
+                <tooltip-button
+                  tooltipPlacement="top"
+                  :tooltip="$t('label.decline.invitation')"
+                  type="primary"
+                  :danger="true"
+                  icon="close-outlined"
+                  size="small"
+                  @onClick="onShowConfirmRevokeInvitation(record)"/>
+              </div>
+            </template>
           </template>
         </a-table>
         <a-pagination
@@ -108,25 +110,25 @@
   created () {
     this.columns = [
       {
+        key: 'project',
         title: this.$t('label.project'),
-        dataIndex: 'project',
-        slots: { customRender: 'project' }
+        dataIndex: 'project'
       },
       {
+        key: 'account',
         title: this.$t('label.account'),
-        dataIndex: 'account',
-        slots: { customRender: 'account' }
+        dataIndex: 'account'
       },
       {
+        key: 'domain',
         title: this.$t('label.domain'),
-        dataIndex: 'domain',
-        slots: { customRender: 'domain' }
+        dataIndex: 'domain'
       },
       {
+        key: 'state',
         title: this.$t('label.state'),
         dataIndex: 'state',
         width: 130,
-        slots: { customRender: 'state' },
         filters: [
           {
             text: this.$t('state.pending'),
@@ -148,10 +150,10 @@
         filterMultiple: false
       },
       {
-        title: this.$t('label.action'),
-        dataIndex: 'action',
-        width: 80,
-        slots: { customRender: 'action' }
+        key: 'actions',
+        title: this.$t('label.actions'),
+        dataIndex: 'actions',
+        width: 80
       }
     ]
 
@@ -161,9 +163,9 @@
     this.apiParams = this.$getApiParams('listProjectInvitations')
     if (this.apiParams.userid) {
       this.columns.splice(2, 0, {
+        key: 'user',
         title: this.$t('label.user'),
-        dataIndex: 'userid',
-        slots: { customRender: 'user' }
+        dataIndex: 'userid'
       })
     }
     this.fetchData()
diff --git a/ui/src/views/project/iam/ProjectRolePermissionTab.vue b/ui/src/views/project/iam/ProjectRolePermissionTab.vue
index df82d21..7b24098a 100644
--- a/ui/src/views/project/iam/ProjectRolePermissionTab.vue
+++ b/ui/src/views/project/iam/ProjectRolePermissionTab.vue
@@ -61,7 +61,6 @@
         handle=".drag-handle"
         animation="200"
         ghostClass="drag-ghost"
-        tag="transition-group"
         :component-data="{type: 'transition'}"
         item-key="id">
         <template #item="{element}">
diff --git a/ui/src/views/project/iam/ProjectRoleTab.vue b/ui/src/views/project/iam/ProjectRoleTab.vue
index d8d8b44..a0768db 100644
--- a/ui/src/views/project/iam/ProjectRoleTab.vue
+++ b/ui/src/views/project/iam/ProjectRoleTab.vue
@@ -27,31 +27,33 @@
           :loading="loading"
           :columns="columns"
           :dataSource="dataSource"
-          :rowKey="(record,idx) => record.projectid + '-' + idx"
+          :rowKey="(record, index) => record.projectid + '-' + index"
           :pagination="false">
           <template #expandedRowRender="{ record }">
             <ProjectRolePermissionTab class="table" :resource="resource" :role="record"/>
           </template>
-          <template #name="{ record }"> {{ record.name }} </template>
-          <template #description="{ record }">
-            {{ record.description }}
-          </template>
-          <template #action="{ record }">
-            <tooltip-button
-              tooltipPlacement="top"
-              :tooltip="$t('label.update.project.role')"
-              icon="edit-outlined"
-              size="small"
-              style="margin:10px"
-              @onClick="openUpdateModal(record)" />
-            <tooltip-button
-              tooltipPlacement="top"
-              :tooltip="$t('label.remove.project.role')"
-              type="primary"
-              :danger="true"
-              icon="delete-outlined"
-              size="small"
-              @onClick="deleteProjectRole(record)" />
+          <template #bodyCell="{ column, record }">
+            <template v-if="column.key === 'name'"> {{ record.name }} </template>
+            <template v-if="column.key === 'description'">
+              {{ record.description }}
+            </template>
+            <template v-if="column.key === 'actions'">
+              <tooltip-button
+                tooltipPlacement="top"
+                :tooltip="$t('label.update.project.role')"
+                icon="edit-outlined"
+                size="small"
+                style="margin:10px"
+                @onClick="openUpdateModal(record)" />
+              <tooltip-button
+                tooltipPlacement="top"
+                :tooltip="$t('label.remove.project.role')"
+                type="primary"
+                :danger="true"
+                icon="delete-outlined"
+                size="small"
+                @onClick="deleteProjectRole(record)" />
+            </template>
           </template>
         </a-table>
         <a-modal
@@ -149,20 +151,21 @@
   created () {
     this.columns = [
       {
+        key: 'name',
         title: this.$t('label.name'),
         dataIndex: 'name',
-        width: '35%',
-        slots: { customRender: 'name' }
+        width: '35%'
       },
       {
+        key: 'description',
         title: this.$t('label.description'),
         dataIndex: 'description'
       },
       {
-        title: this.$t('label.action'),
-        dataIndex: 'action',
-        width: 100,
-        slots: { customRender: 'action' }
+        key: 'actions',
+        title: this.$t('label.actions'),
+        dataIndex: 'actions',
+        width: 100
       }
     ]
     this.initForm()
diff --git a/ui/src/views/setting/ConfigurationHierarchy.vue b/ui/src/views/setting/ConfigurationHierarchy.vue
index c3cfddb..45060ef 100644
--- a/ui/src/views/setting/ConfigurationHierarchy.vue
+++ b/ui/src/views/setting/ConfigurationHierarchy.vue
@@ -26,18 +26,18 @@
     :rowClassName="getRowClassName"
     style="overflow-y: auto; margin-left: 10px" >
 
-    <template #name="{ record }">
-      <span :style="hierarchyExists ? 'padding-left: 0px;' : 'padding-left: 25px;'">
-        <b><span v-if="record.parent">└─ &nbsp;</span>{{record.displaytext }} </b> {{ ' (' + record.name + ')' }}
-      </span>
-      <br/>
-      <span :style="record.parent ? 'padding-left: 50px; display:block' : 'padding-left: 25px; display:block'">{{ record.description }}</span>
+    <template #bodyCell="{ column, record }">
+      <template v-if="column.key === 'name'">
+    <span :style="hierarchyExists ? 'padding-left: 0px;' : 'padding-left: 25px;'">
+      <b><span v-if="record.parent">└─ &nbsp;</span>{{record.displaytext }} </b> {{ ' (' + record.name + ')' }}
+    </span>
+    <br/>
+    <span :style="record.parent ? 'padding-left: 50px; display:block' : 'padding-left: 25px; display:block'">{{ record.description }}</span>
+      </template>
+      <template v-if="column.key === 'value'">
+        <ConfigurationValue :configrecord="record" />
+      </template>
     </template>
-
-    <template #value="{ record }">
-      <ConfigurationValue :configrecord="record" />
-    </template>
-
   </a-table>
 </template>
 
diff --git a/ui/src/views/setting/ConfigurationTab.vue b/ui/src/views/setting/ConfigurationTab.vue
index 0948a13..11c0b04 100644
--- a/ui/src/views/setting/ConfigurationTab.vue
+++ b/ui/src/views/setting/ConfigurationTab.vue
@@ -138,12 +138,12 @@
         {
           title: 'name',
           dataIndex: 'name',
-          slots: { customRender: 'name' }
+          key: 'name'
         },
         {
           title: 'value',
           dataIndex: 'value',
-          slots: { customRender: 'value' },
+          key: 'value',
           width: '29%'
         }
       ]
diff --git a/ui/src/views/setting/ConfigurationTable.vue b/ui/src/views/setting/ConfigurationTable.vue
index d818251..6854852 100644
--- a/ui/src/views/setting/ConfigurationTable.vue
+++ b/ui/src/views/setting/ConfigurationTable.vue
@@ -27,11 +27,13 @@
       :rowKey="record => record.name"
       :rowClassName="getRowClassName" >
 
-      <template #name="{ record }">
-        <b> {{record.displaytext }} </b> {{ ' (' + record.name + ')' }} <br/> {{ record.description }}
-      </template>
-      <template #value="{ record }">
-        <ConfigurationValue :configrecord="record" />
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'name'">
+          <b> {{record.displaytext }} </b> {{ ' (' + record.name + ')' }} <br/> {{ record.description }}
+        </template>
+        <template v-if="column.key === 'value'">
+          <ConfigurationValue :configrecord="record" />
+        </template>
       </template>
     </a-table>
     <a-pagination
diff --git a/ui/src/views/storage/AttachVolume.vue b/ui/src/views/storage/AttachVolume.vue
index 96e81ba3..de0a2f7 100644
--- a/ui/src/views/storage/AttachVolume.vue
+++ b/ui/src/views/storage/AttachVolume.vue
@@ -41,9 +41,9 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
-          <a-select-option v-for="vm in virtualmachines" :key="vm.id">
+          <a-select-option v-for="vm in virtualmachines" :key="vm.id" :label="vm.name || vm.displayname">
             {{ vm.name || vm.displayname }}
           </a-select-option>
         </a-select>
diff --git a/ui/src/views/storage/ChangeOfferingForVolume.vue b/ui/src/views/storage/ChangeOfferingForVolume.vue
index 203a2da..5ab8039 100644
--- a/ui/src/views/storage/ChangeOfferingForVolume.vue
+++ b/ui/src/views/storage/ChangeOfferingForVolume.vue
@@ -41,13 +41,14 @@
         showSearch
         optionFilterProp="label"
         :filterOption="(input, option) => {
-          return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+          return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
         }"
         @change="id => onChangeDiskOffering(id)">
         <a-select-option
           v-for="(offering, index) in diskOfferings"
           :value="offering.id"
-          :key="index">
+          :key="index"
+          :label="offering.displaytext || offering.name">
           {{ offering.displaytext || offering.name }}
         </a-select-option>
       </a-select>
diff --git a/ui/src/views/storage/CreateSnapshotFromVMSnapshot.vue b/ui/src/views/storage/CreateSnapshotFromVMSnapshot.vue
index 5702bc4..409e931 100644
--- a/ui/src/views/storage/CreateSnapshotFromVMSnapshot.vue
+++ b/ui/src/views/storage/CreateSnapshotFromVMSnapshot.vue
@@ -40,12 +40,13 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
           <a-select-option
             v-for="(volume, index) in volumes"
             :value="volume.id"
-            :key="index">
+            :key="index"
+            :label="volume.displaytext || volume.name">
             {{ volume.displaytext || volume.name }}
           </a-select-option>
         </a-select>
diff --git a/ui/src/views/storage/CreateVolume.vue b/ui/src/views/storage/CreateVolume.vue
index 7f11033..d1c5cc5 100644
--- a/ui/src/views/storage/CreateVolume.vue
+++ b/ui/src/views/storage/CreateVolume.vue
@@ -74,12 +74,13 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
           <a-select-option
             v-for="(offering, index) in offerings"
             :value="offering.id"
-            :key="index">
+            :key="index"
+            :label="offering.displaytext || offering.name">
             {{ offering.displaytext || offering.name }}
           </a-select-option>
         </a-select>
diff --git a/ui/src/views/storage/FormSchedule.vue b/ui/src/views/storage/FormSchedule.vue
index 235be2e..c689de2 100644
--- a/ui/src/views/storage/FormSchedule.vue
+++ b/ui/src/views/storage/FormSchedule.vue
@@ -74,8 +74,10 @@
                 name="timeSelect"
                 ref="timeSelect">
                 <a-time-picker
-                  format="HH:mm"
-                  v-model:value="form.timeSelect" />
+                  use12Hours
+                  format="h:mm A"
+                  v-model:value="form.timeSelect"
+                  style="width: 100%;" />
               </a-form-item>
             </a-col>
             <a-col :md="24" :lg="12" v-if="form.intervaltype==='weekly'">
@@ -85,9 +87,9 @@
                   showSearch
                   optionFilterProp="label"
                   :filterOption="(input, option) => {
-                    return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                   }" >
-                  <a-select-option v-for="(opt, optIndex) in dayOfWeek" :key="optIndex">
+                  <a-select-option v-for="(opt, optIndex) in dayOfWeek" :key="optIndex" :label="opt.name || opt.description">
                     {{ opt.name || opt.description }}
                   </a-select-option>
                 </a-select>
@@ -98,9 +100,9 @@
                 <a-select
                   v-model:value="form['day-of-month']"
                   showSearch
-                  optionFilterProp="label"
+                  optionFilterProp="value"
                   :filterOption="(input, option) => {
-                    return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
                   }" >
                   <a-select-option v-for="opt in dayOfMonth" :key="opt.name">
                     {{ opt.name }}
@@ -128,9 +130,9 @@
                   showSearch
                   optionFilterProp="label"
                   :filterOption="(input, option) => {
-                    return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                   }" >
-                  <a-select-option v-for="opt in timeZoneMap" :key="opt.id">
+                  <a-select-option v-for="opt in timeZoneMap" :key="opt.id" :label="opt.name || opt.description">
                     {{ opt.name || opt.description }}
                   </a-select-option>
                 </a-select>
diff --git a/ui/src/views/storage/MigrateVolume.vue b/ui/src/views/storage/MigrateVolume.vue
index 62bed70..761fe02 100644
--- a/ui/src/views/storage/MigrateVolume.vue
+++ b/ui/src/views/storage/MigrateVolume.vue
@@ -50,9 +50,9 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option v-for="(diskOffering, index) in diskOfferings" :value="diskOffering.id" :key="index">
+            <a-select-option v-for="(diskOffering, index) in diskOfferings" :value="diskOffering.id" :key="index" :label="diskOffering.displaytext">
               {{ diskOffering.displaytext }}
             </a-select-option>
           </a-select>
diff --git a/ui/src/views/storage/RestoreAttachBackupVolume.vue b/ui/src/views/storage/RestoreAttachBackupVolume.vue
index 41a8f76..72c38ac 100644
--- a/ui/src/views/storage/RestoreAttachBackupVolume.vue
+++ b/ui/src/views/storage/RestoreAttachBackupVolume.vue
@@ -34,11 +34,12 @@
           showSearch
           optionFilterProp="label"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
           <a-select-option
             v-for="(opt) in volumeOptions.opts"
-            :key="opt.id">
+            :key="opt.id"
+            :label="opt.name">
             {{ opt.name }}
           </a-select-option>
         </a-select>
@@ -49,9 +50,9 @@
           v-model:value="form.virtualmachineid"
           :loading="virtualMachineOptions.loading"
           showSearch
-          optionFilterProp="label"
+          optionFilterProp="value"
           :filterOption="(input, option) => {
-            return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
           }" >
           <a-select-option
             v-for="(opt) in virtualMachineOptions.opts"
diff --git a/ui/src/views/storage/ScheduledSnapshots.vue b/ui/src/views/storage/ScheduledSnapshots.vue
index 0c0f6d1..8c95d0b 100644
--- a/ui/src/views/storage/ScheduledSnapshots.vue
+++ b/ui/src/views/storage/ScheduledSnapshots.vue
@@ -24,54 +24,56 @@
       :rowKey="record => record.id"
       :pagination="false"
       :loading="loading">
-      <template #icon="{ record }">
-        <label class="interval-icon">
-          <span v-if="record.intervaltype===0">
-            <clock-circle-outlined />
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'icon'">
+          <label class="interval-icon">
+            <span v-if="record.intervaltype===0">
+              <clock-circle-outlined />
+            </span>
+            <span class="custom-icon icon-daily" v-else-if="record.intervaltype===1">
+              <calendar-outlined />
+            </span>
+            <span class="custom-icon icon-weekly" v-else-if="record.intervaltype===2">
+              <calendar-outlined />
+            </span>
+            <span class="custom-icon icon-monthly" v-else-if="record.intervaltype===3">
+              <calendar-outlined />
+            </span>
+          </label>
+        </template>
+        <template v-if="column.key === 'time'">
+          <label class="interval-content">
+            <span v-if="record.intervaltype===0">{{ record.schedule + $t('label.min.past.hour') }}</span>
+            <span v-else>{{ record.schedule.split(':')[1] + ':' + record.schedule.split(':')[0] }}</span>
+          </label>
+        </template>
+        <template v-if="column.key === 'interval'">
+          <span v-if="record.intervaltype===2">
+            {{ `${$t('label.every')} ${$t(listDayOfWeek[record.schedule.split(':')[2] - 1])}` }}
           </span>
-          <span class="custom-icon icon-daily" v-else-if="record.intervaltype===1">
-            <calendar-outlined />
+          <span v-else-if="record.intervaltype===3">
+            {{ `${$t('label.day')} ${record.schedule.split(':')[2]} ${$t('label.of.month')}` }}
           </span>
-          <span class="custom-icon icon-weekly" v-else-if="record.intervaltype===2">
-            <calendar-outlined />
-          </span>
-          <span class="custom-icon icon-monthly" v-else-if="record.intervaltype===3">
-            <calendar-outlined />
-          </span>
-        </label>
-      </template>
-      <template #time="{ record }">
-        <label class="interval-content">
-          <span v-if="record.intervaltype===0">{{ record.schedule + $t('label.min.past.hour') }}</span>
-          <span v-else>{{ record.schedule.split(':')[1] + ':' + record.schedule.split(':')[0] }}</span>
-        </label>
-      </template>
-      <template #interval="{ record }">
-        <span v-if="record.intervaltype===2">
-          {{ `${$t('label.every')} ${$t(listDayOfWeek[record.schedule.split(':')[2] - 1])}` }}
-        </span>
-        <span v-else-if="record.intervaltype===3">
-          {{ `${$t('label.day')} ${record.schedule.split(':')[2]} ${$t('label.of.month')}` }}
-        </span>
-      </template>
-      <template #timezone="{ record }">
-        <label>{{ getTimeZone(record.timezone) }}</label>
-      </template>
-      <template #tags="{ record }">
-        <a-tag v-for="(tag, index) in record.tags" :key="index">{{ tag.key + '=' + tag.value }}</a-tag>
-      </template>
-      <template #action="{ record }">
-        <div class="account-button-action">
-          <tooltip-button
-            tooltipPlacement="top"
-            :tooltip="$t('label.delete')"
-            type="primary"
-            :danger="true"
-            icon="close-outlined"
-            size="small"
-            :loading="actionLoading"
-            @onClick="handleClickDelete(record)" />
-        </div>
+        </template>
+        <template v-if="column.key === 'timezone'">
+          <label>{{ getTimeZone(record.timezone) }}</label>
+        </template>
+        <template v-if="column.key === 'tags'">
+          <a-tag v-for="(tag, index) in record.tags" :key="index">{{ tag.key + '=' + tag.value }}</a-tag>
+        </template>
+        <template v-if="column.key === 'actions'">
+          <div class="account-button-action">
+            <tooltip-button
+              tooltipPlacement="top"
+              :tooltip="$t('label.delete')"
+              type="primary"
+              :danger="true"
+              icon="close-outlined"
+              size="small"
+              :loading="actionLoading"
+              @onClick="handleClickDelete(record)" />
+          </div>
+        </template>
       </template>
     </a-table>
   </div>
@@ -112,41 +114,41 @@
   created () {
     this.columns = [
       {
+        key: 'icon',
         title: '',
         dataIndex: 'icon',
-        width: 30,
-        slots: { customRender: 'icon' }
+        width: 30
       },
       {
+        key: 'time',
         title: this.$t('label.time'),
-        dataIndex: 'schedule',
-        slots: { customRender: 'time' }
+        dataIndex: 'schedule'
       },
       {
+        key: 'interval',
         title: '',
-        dataIndex: 'interval',
-        slots: { customRender: 'interval' }
+        dataIndex: 'interval'
       },
       {
+        key: 'timezone',
         title: this.$t('label.timezone'),
-        dataIndex: 'timezone',
-        slots: { customRender: 'timezone' }
+        dataIndex: 'timezone'
       },
       {
+        key: 'keep',
         title: this.$t('label.keep'),
-        dataIndex: 'maxsnaps',
-        slots: { customRender: 'keep' }
+        dataIndex: 'maxsnaps'
       },
       {
+        key: 'tags',
         title: this.$t('label.tags'),
-        dataIndex: 'tags',
-        slots: { customRender: 'tags' }
+        dataIndex: 'tags'
       },
       {
-        title: this.$t('label.action'),
-        dataIndex: 'action',
-        width: 50,
-        slots: { customRender: 'action' }
+        key: 'actions',
+        title: this.$t('label.actions'),
+        dataIndex: 'actions',
+        width: 50
       }
     ]
   },
diff --git a/ui/src/views/storage/UploadLocalVolume.vue b/ui/src/views/storage/UploadLocalVolume.vue
index 3548e02..75775c9 100644
--- a/ui/src/views/storage/UploadLocalVolume.vue
+++ b/ui/src/views/storage/UploadLocalVolume.vue
@@ -33,7 +33,7 @@
           <a-upload-dragger
             :multiple="false"
             :fileList="fileList"
-            :remove="handleRemove"
+            @remove="handleRemove"
             :beforeUpload="beforeUpload"
             v-model:value="form.file">
             <p class="ant-upload-drag-icon">
@@ -84,10 +84,14 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
-            <a-select-option v-for="opt in offerings" :key="opt.id">
-              {{ opt.name || opt.displaytext }}
+            <a-select-option
+              v-for="(offering, index) in offerings"
+              :value="offering.id"
+              :key="index"
+              :label="offering.displaytext || offering.name">
+              {{ offering.displaytext || offering.name }}
             </a-select-option>
           </a-select>
         </a-form-item>
@@ -98,9 +102,9 @@
           <a-select
             v-model:value="form.format"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option v-for="format in formats" :key="format">
               {{ format }}
@@ -125,12 +129,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="domainLoading"
             :placeholder="$t('label.domainid')"
             @change="val => { handleDomainChange(domainList[val].id) }">
-            <a-select-option v-for="(opt, optIndex) in domainList" :key="optIndex">
+            <a-select-option v-for="(opt, optIndex) in domainList" :key="optIndex" :label="opt.path || opt.name || opt.description">
               {{ opt.path || opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -142,9 +146,9 @@
           <a-select
             v-model:value="form.account"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :placeholder="$t('label.account')"
             @change="val => { handleAccountChange(val) }">
diff --git a/ui/src/views/storage/UploadVolume.vue b/ui/src/views/storage/UploadVolume.vue
index 5bfdcfa..937c3ad 100644
--- a/ui/src/views/storage/UploadVolume.vue
+++ b/ui/src/views/storage/UploadVolume.vue
@@ -70,9 +70,9 @@
           <a-select
             v-model:value="form.format"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option v-for="format in formats" :key="format">
               {{ format }}
@@ -90,12 +90,13 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }" >
             <a-select-option
               v-for="(offering, index) in offerings"
               :value="offering.id"
-              :key="index">
+              :key="index"
+              :label="offering.displaytext || offering.name">
               {{ offering.displaytext || offering.name }}
             </a-select-option>
           </a-select>
@@ -118,12 +119,12 @@
             showSearch
             optionFilterProp="label"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :loading="domainLoading"
             :placeholder="$t('label.domainid')"
             @change="val => { handleDomainChange(domainList[val].id) }">
-            <a-select-option v-for="(opt, optIndex) in domainList" :key="optIndex">
+            <a-select-option v-for="(opt, optIndex) in domainList" :key="optIndex" :label="opt.path || opt.name || opt.description">
               {{ opt.path || opt.name || opt.description }}
             </a-select-option>
           </a-select>
@@ -135,9 +136,9 @@
           <a-select
             v-model:value="form.account"
             showSearch
-            optionFilterProp="label"
+            optionFilterProp="value"
             :filterOption="(input, option) => {
-              return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
             }"
             :placeholder="$t('label.account')"
             @change="val => { handleAccountChange(val) }">
diff --git a/ui/src/views/tools/ImportUnmanagedInstance.vue b/ui/src/views/tools/ImportUnmanagedInstance.vue
index 1e5629b..7e89d48 100644
--- a/ui/src/views/tools/ImportUnmanagedInstance.vue
+++ b/ui/src/views/tools/ImportUnmanagedInstance.vue
@@ -180,7 +180,7 @@
                 :cpuSpeed="getCPUSpeed()"
                 @update-iops-value="updateFieldValue"
                 @update-compute-cpunumber="updateFieldValue"
-                @update-compute-cpuspeed="updateFieldValue"
+                @update-compute-cpuspeed="updateCpuSpeed"
                 @update-compute-memory="updateFieldValue" />
               <div v-if="resource.disk && resource.disk.length > 1">
                 <a-form-item name="selection" ref="selection">
@@ -195,10 +195,10 @@
                     showSearch
                     optionFilterProp="label"
                     :filterOption="(input, option) => {
-                      return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                      return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
                     }"
                     @change="val => { selectedRootDiskIndex = val }">
-                    <a-select-option v-for="(opt, optIndex) in resource.disk" :key="optIndex">
+                    <a-select-option v-for="(opt, optIndex) in resource.disk" :key="optIndex" :label="opt.label || opt.id">
                       {{ opt.label || opt.id }}
                     </a-select-option>
                   </a-select>
@@ -595,6 +595,15 @@
         this.selectMatchingComputeOffering()
       })
     },
+    updateCpuSpeed (name, value) {
+      if (this.computeOffering.iscustomized) {
+        if (this.computeOffering.serviceofferingdetails) {
+          this.updateFieldValue(this.cpuSpeedKey, this.computeOffering.cpuspeed)
+        } else {
+          this.updateFieldValue(this.cpuSpeedKey, value)
+        }
+      }
+    },
     updateFieldValue (name, value) {
       this.form[name] = value
     },
diff --git a/ui/src/views/tools/ManageInstances.vue b/ui/src/views/tools/ManageInstances.vue
index 1e6cf3a..460ff91 100644
--- a/ui/src/views/tools/ManageInstances.vue
+++ b/ui/src/views/tools/ManageInstances.vue
@@ -139,8 +139,10 @@
                   size="middle"
                   :rowClassName="getRowClassName"
                 >
-                  <template #state="{text}">
-                    <status :text="text ? text : ''" displayText />
+                  <template #bodyCell="{ column, text }">
+                    <template v-if="column.key === 'state'">
+                      <status :text="text ? text : ''" displayText />
+                    </template>
                   </template>
                 </a-table>
                 <div class="instances-card-footer">
@@ -205,11 +207,13 @@
                   size="middle"
                   :rowClassName="getRowClassName"
                 >
-                  <template #name="{text, record}" href="javascript:;">
-                    <router-link :to="{ path: '/vm/' + record.id }">{{ text }}</router-link>
-                  </template>
-                  <template #state="{text}">
-                    <status :text="text ? text : ''" displayText />
+                  <template #bodyCell="{ column, text, record }">
+                    <template v-if="column.key === 'name'">
+                      <router-link :to="{ path: '/vm/' + record.id }">{{ text }}</router-link>
+                    </template>
+                    <template v-if="column.key === 'state'">
+                      <status :text="text ? text : ''" displayText />
+                    </template>
                   </template>
                 </a-table>
                 <div class="instances-card-footer">
@@ -295,9 +299,9 @@
         width: 100
       },
       {
+        key: 'state',
         title: this.$t('label.state'),
-        dataIndex: 'powerstate',
-        slots: { customRender: 'state' }
+        dataIndex: 'powerstate'
       },
       {
         title: this.$t('label.hostname'),
@@ -310,19 +314,19 @@
     ]
     const managedInstancesColumns = [
       {
+        key: 'name',
         title: this.$t('label.name'),
         dataIndex: 'name',
-        width: 100,
-        slots: { customRender: 'name' }
+        width: 100
       },
       {
         title: this.$t('label.instancename'),
         dataIndex: 'instancename'
       },
       {
+        key: 'state',
         title: this.$t('label.state'),
-        dataIndex: 'state',
-        slots: { customRender: 'state' }
+        dataIndex: 'state'
       },
       {
         title: this.$t('label.hostname'),
@@ -505,7 +509,7 @@
     },
     filterOption (input, option) {
       return (
-        option.children[0].children.toUpperCase().indexOf(input.toUpperCase()) >= 0
+        option.label.toUpperCase().indexOf(input.toUpperCase()) >= 0
       )
     },
     fetchOptions (param, name, exclude) {
diff --git a/ui/tests/mockData/ActionButton.mock.json b/ui/tests/mockData/ActionButton.mock.json
index 85ff8f1..7ec4deb 100644
--- a/ui/tests/mockData/ActionButton.mock.json
+++ b/ui/tests/mockData/ActionButton.mock.json
@@ -33,4 +33,4 @@
       }
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/ui/tests/mockData/AutogenView.mock.json b/ui/tests/mockData/AutogenView.mock.json
index 8d932e0..56807cc 100644
--- a/ui/tests/mockData/AutogenView.mock.json
+++ b/ui/tests/mockData/AutogenView.mock.json
@@ -458,7 +458,8 @@
       "meta": {
         "title": "label.title",
         "icon": "play-circle-outlined",
-        "permission": ["testApiNameCase1"]
+        "permission": ["testApiNameCase1"],
+        "columns": ["column1", "column2", "column3"]
       },
       "component": {},
       "children": [{
@@ -487,7 +488,8 @@
       "meta": {
         "title": "label.title",
         "icon": "play-circle-outlined",
-        "permission": ["testApiNameCase1"]
+        "permission": ["testApiNameCase1"],
+        "columns": ["column1"]
       },
       "component": {}
     },
diff --git a/ui/tests/mockData/MigrateWizard.mock.json b/ui/tests/mockData/MigrateWizard.mock.json
index 30f61ca..2e423bc 100644
--- a/ui/tests/mockData/MigrateWizard.mock.json
+++ b/ui/tests/mockData/MigrateWizard.mock.json
@@ -102,4 +102,4 @@
       "component": {}
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/ui/tests/unit/components/view/ActionButton.spec.js b/ui/tests/unit/components/view/ActionButton.spec.js
index 29ade02..7e41f0b 100644
--- a/ui/tests/unit/components/view/ActionButton.spec.js
+++ b/ui/tests/unit/components/view/ActionButton.spec.js
@@ -51,6 +51,7 @@
 describe('Components > View > ActionButton.vue', () => {
   beforeEach(() => {
     jest.clearAllMocks()
+    jest.spyOn(console, 'warn').mockImplementation(() => {})
   })
 
   describe('Template', () => {
diff --git a/ui/tests/unit/views/AutogenView.spec.js b/ui/tests/unit/views/AutogenView.spec.js
index fe890ea..d22c9a2 100644
--- a/ui/tests/unit/views/AutogenView.spec.js
+++ b/ui/tests/unit/views/AutogenView.spec.js
@@ -16,6 +16,7 @@
 // under the License.
 
 import { flushPromises } from '@vue/test-utils'
+import { ref } from 'vue'
 
 import mockAxios from '../../mock/mockAxios'
 import AutogenView from '@/views/AutogenView'
@@ -180,6 +181,7 @@
 describe('Views > AutogenView.vue', () => {
   beforeEach(async () => {
     jest.clearAllMocks()
+    jest.spyOn(console, 'warn').mockImplementation(() => {})
 
     delete window.ResizeObserver
     delete window.ls
@@ -253,6 +255,9 @@
           case 'RefValidateFields':
             wrapper.vm.formRef.value.validateFields = originalFunc[key]
             break
+          case 'formRef':
+            wrapper.vm.formRef = originalFunc[key]
+            break
           case 'switchProject':
             wrapper.vm.switchProject = originalFunc[key]
             break
@@ -549,10 +554,13 @@
         await flushPromises()
 
         expect(wrapper.vm.columns.length).toEqual(2)
+        expect(wrapper.vm.columns[0].key).toEqual('name')
         expect(wrapper.vm.columns[0].title).toEqual('name-en')
         expect(wrapper.vm.columns[0].dataIndex).toEqual('name')
-        expect(wrapper.vm.columns[0].slots).toEqual({ customRender: 'name' })
         expect(typeof wrapper.vm.columns[0].sorter).toBe('function')
+        expect(wrapper.vm.columns[1].key).toEqual('filtercolumn')
+        expect(wrapper.vm.columns[1].dataIndex).toEqual('filtercolumn')
+        expect(wrapper.vm.columns[1].customFilterDropdown).toBeTruthy()
         done(0)
       })
 
@@ -623,7 +631,7 @@
       //   })
       //   await router.push({ name: 'testRouter12', params: { id: 'test-id' } })
       //   await flushPromises()
-      //
+
       //   expect(mockAxios).toHaveBeenCalled()
       //   expect(mockAxios).toHaveBeenLastCalledWith({
       //     url: '/',
@@ -731,14 +739,12 @@
         expect(wrapper.vm.items).toEqual([{
           id: 'test-id',
           name: 'test-name-value',
-          key: 0,
-          column1: 'test-name-value'
+          key: 0
         }])
         expect(wrapper.vm.resource).toEqual({
           id: 'test-id',
           name: 'test-name-value',
-          key: 0,
-          column1: 'test-name-value'
+          key: 0
         })
         done()
       })
@@ -2287,12 +2293,21 @@
       it('formRef makes validation calls when handleSubmit() is called in list view', async (done) => {
         originalFunc.callGroupApi = wrapper.vm.callGroupApi
         originalFunc.fetchData = wrapper.vm.fetchData
+        originalFunc.formRef = wrapper.vm.formRef
         wrapper.vm.fetchData = jest.fn()
         wrapper.vm.callGroupApi = jest.fn((params, resourceName) => {
           return new Promise(resolve => {
             resolve()
           })
         })
+        if (!wrapper.vm.formRef) {
+          wrapper.vm.formRef = ref()
+        }
+        wrapper.vm.formRef.value.validate = jest.fn((params, resourceName) => {
+          return new Promise(resolve => {
+            resolve()
+          })
+        })
 
         const fetchData = jest.spyOn(wrapper.vm, 'fetchData')
         const callGroupApi = jest.spyOn(wrapper.vm, 'callGroupApi')
@@ -2311,6 +2326,11 @@
           items: [{
             id: 'test-id-value-1',
             name: 'test-name-value-1'
+          }],
+          columns: [{
+            key: 'column1',
+            dataIndex: 'column1',
+            title: 'column1'
           }]
         })
         await wrapper.vm.handleSubmit(event)
diff --git a/ui/tests/unit/views/compute/MigrateWizard.spec.js b/ui/tests/unit/views/compute/MigrateWizard.spec.js
index ab44b74..f352b2d 100644
--- a/ui/tests/unit/views/compute/MigrateWizard.spec.js
+++ b/ui/tests/unit/views/compute/MigrateWizard.spec.js
@@ -93,12 +93,12 @@
 describe('Views > compute > MigrateWizard.vue', () => {
   beforeEach(() => {
     jest.clearAllMocks()
+    jest.spyOn(console, 'warn').mockImplementation(() => {})
 
     if (!wrapper) {
       mockAxios.mockResolvedValue({ findhostsformigrationresponse: { count: 0, host: [] } })
       wrapper = factory({
-        props: { resource: {} },
-        data: { columns: [] }
+        props: { resource: {} }
       })
     }
 
@@ -107,7 +107,6 @@
 
   afterEach(() => {
     if (wrapper) {
-      wrapper.vm.columns = []
       wrapper.vm.searchQuery = ''
       wrapper.vm.page = 1
       wrapper.vm.pageSize = 10
@@ -132,7 +131,6 @@
       it('API should be called with resource is empty and searchQuery is empty', async (done) => {
         await mockAxios.mockResolvedValue({ findhostsformigrationresponse: { count: 0, host: [] } })
         await wrapper.setProps({ resource: {} })
-        await wrapper.setData({ columns: [] })
         await wrapper.vm.fetchData()
         await flushPromises()
 
@@ -156,7 +154,6 @@
       it('API should be called with resource.id is empty and searchQuery is empty', async (done) => {
         await mockAxios.mockResolvedValue({ findhostsformigrationresponse: { count: 0, host: [] } })
         await wrapper.setProps({ resource: { id: null } })
-        await wrapper.setData({ columns: [] })
         await wrapper.vm.fetchData()
         await flushPromises()
 
@@ -180,7 +177,6 @@
       it('API should be called with resource.id is not empty and searchQuery is empty', async (done) => {
         await mockAxios.mockResolvedValue({ findhostsformigrationresponse: { count: 0, host: [] } })
         await wrapper.setProps({ resource: { id: 'test-id-value' } })
-        await wrapper.setData({ columns: [] })
         await wrapper.vm.fetchData()
         await flushPromises()
 
@@ -204,7 +200,7 @@
       it('API should be called with resource.id is not empty and searchQuery is not empty', async (done) => {
         await mockAxios.mockResolvedValue({ findhostsformigrationresponse: { count: 0, host: [] } })
         await wrapper.setProps({ resource: { id: 'test-id-value' } })
-        await wrapper.setData({ searchQuery: 'test-query-value', columns: [] })
+        await wrapper.setData({ searchQuery: 'test-query-value' })
         await wrapper.vm.fetchData()
         await flushPromises()
 
@@ -231,8 +227,7 @@
         await wrapper.setData({
           searchQuery: 'test-query-value',
           page: 2,
-          pageSize: 20,
-          columns: []
+          pageSize: 20
         })
         await wrapper.vm.fetchData()
         await flushPromises()
diff --git a/ui/vue.config.js b/ui/vue.config.js
index 09f0423..c74218b 100644
--- a/ui/vue.config.js
+++ b/ui/vue.config.js
@@ -127,6 +127,7 @@
         modifyVars: {
           // https://ant.design/docs/spec/colors
           // https://vue.ant.design/docs/vue/customize-theme/
+          'root-entry-name': 'default'
         },
         javascriptEnabled: true
       }
diff --git a/usage/pom.xml b/usage/pom.xml
index 389d34a..d6ea06d 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
     </parent>
     <dependencies>
         <dependency>
diff --git a/utils/pom.xml b/utils/pom.xml
index 963aaca..4360e18 100755
--- a/utils/pom.xml
+++ b/utils/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <dependencies>
@@ -118,6 +118,11 @@
             <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>com.cronutils</groupId>
+            <artifactId>cron-utils</artifactId>
+            <version>${cs.cron-utils.version}</version>
+        </dependency>
         <!-- Test dependency in mysql for db tests -->
         <dependency>
             <groupId>mysql</groupId>
diff --git a/utils/src/main/java/com/cloud/utils/DateUtil.java b/utils/src/main/java/com/cloud/utils/DateUtil.java
index 4d0157f..41afcb1 100644
--- a/utils/src/main/java/com/cloud/utils/DateUtil.java
+++ b/utils/src/main/java/com/cloud/utils/DateUtil.java
@@ -22,6 +22,9 @@
 import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.TimeZone;
@@ -31,6 +34,13 @@
 import java.time.OffsetDateTime;
 
 import com.cloud.utils.exception.CloudRuntimeException;
+import com.cronutils.descriptor.CronDescriptor;
+import com.cronutils.model.CronType;
+import com.cronutils.model.definition.CronDefinition;
+import com.cronutils.model.definition.CronDefinitionBuilder;
+import com.cronutils.parser.CronParser;
+import org.springframework.scheduling.support.CronExpression;
+
 
 public class DateUtil {
     public static final int HOURS_IN_A_MONTH = 30 * 24;
@@ -52,7 +62,7 @@
     };
 
     public static Date currentGMTTime() {
-        // Date object always stores miliseconds offset based on GMT internally
+        // Date object always stores milliseconds offset based on GMT internally
         return new Date();
     }
 
@@ -295,4 +305,35 @@
         return (dateCalendar1.getTimeInMillis() - dateCalendar2.getTimeInMillis() )/1000;
 
     }
+
+    public static CronExpression parseSchedule(String schedule) {
+        if (schedule != null) {
+            // CronExpression's granularity is in seconds. Prepending "0 " to change the granularity to minutes.
+            return CronExpression.parse(String.format("0 %s", schedule));
+        } else {
+            return null;
+        }
+    }
+
+    public static String getHumanReadableSchedule(CronExpression schedule) {
+        CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.SPRING);
+        CronParser parser = new CronParser(cronDefinition);
+        CronDescriptor descriptor = CronDescriptor.instance();
+        return descriptor.describe(parser.parse(schedule.toString()));
+    }
+
+    public static ZonedDateTime getZoneDateTime(Date date, ZoneId tzId) {
+        if (date == null) {
+            return null;
+        }
+        ZonedDateTime zonedDate = ZonedDateTime.ofInstant(date.toInstant(), tzId);
+        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), TimeZone.getDefault().toZoneId());
+        zonedDate = zonedDate.withYear(localDateTime.getYear())
+                .withMonth(localDateTime.getMonthValue())
+                .withDayOfMonth(localDateTime.getDayOfMonth())
+                .withHour(localDateTime.getHour())
+                .withMinute(localDateTime.getMinute())
+                .withSecond(localDateTime.getSecond());
+        return zonedDate;
+    }
 }
diff --git a/utils/src/main/java/com/cloud/utils/LogUtils.java b/utils/src/main/java/com/cloud/utils/LogUtils.java
index edfb53f..a458be7 100644
--- a/utils/src/main/java/com/cloud/utils/LogUtils.java
+++ b/utils/src/main/java/com/cloud/utils/LogUtils.java
@@ -28,6 +28,7 @@
 
 import org.apache.log4j.Appender;
 import org.apache.log4j.FileAppender;
+import org.apache.commons.lang3.ObjectUtils;
 import org.apache.log4j.Logger;
 import org.apache.log4j.xml.DOMConfigurator;
 
@@ -78,21 +79,29 @@
         return fileNames;
     }
 
+    /**
+     * Tries to convert message parameters to JSON format and use them in the message.
+     * @param formatMessage message to format.
+     * @param objects objects to convert to JSON. A null object will be defaulted to the String "null";
+     * if it is not possible to convert an object to JSON, the object's 'toString' will be used instead.
+     * @return the formatted message.
+     */
     public static String logGsonWithoutException(String formatMessage, Object ... objects) {
         List<String> gsons = new ArrayList<>();
         for (Object object : objects) {
             try {
                 gsons.add(GSON.toJson(object));
             } catch (Exception e) {
-                LOGGER.debug(String.format("Failed to log object [%s] using GSON.", object != null ? object.getClass().getSimpleName() : "null"));
-                gsons.add("error to decode");
+                Object errObj = ObjectUtils.defaultIfNull(object, "null");
+                LOGGER.trace(String.format("Failed to log object [%s] using GSON.", errObj.getClass().getSimpleName()));
+                gsons.add("error decoding " + errObj);
             }
         }
         try {
             return String.format(formatMessage, gsons.toArray());
         } catch (Exception e) {
             String errorMsg = String.format("Failed to log objects using GSON due to: [%s].", e.getMessage());
-            LOGGER.error(errorMsg, e);
+            LOGGER.trace(errorMsg, e);
             return errorMsg;
         }
     }
diff --git a/utils/src/main/java/com/cloud/utils/concurrency/SynchronizationEvent.java b/utils/src/main/java/com/cloud/utils/concurrency/SynchronizationEvent.java
index 5207ad4..5871c0c 100644
--- a/utils/src/main/java/com/cloud/utils/concurrency/SynchronizationEvent.java
+++ b/utils/src/main/java/com/cloud/utils/concurrency/SynchronizationEvent.java
@@ -65,13 +65,13 @@
         }
     }
 
-    public boolean waitEvent(long timeOutMiliseconds) throws InterruptedException {
+    public boolean waitEvent(long timeOutMilliseconds) throws InterruptedException {
         synchronized (this) {
             if (signalled)
                 return true;
 
             try {
-                wait(timeOutMiliseconds);
+                wait(timeOutMilliseconds);
                 return signalled;
             } catch (InterruptedException e) {
                 // TODO, we don't honor time out semantics when the waiting thread is interrupted
diff --git a/utils/src/test/java/com/cloud/utils/FileUtilTest.java b/utils/src/test/java/com/cloud/utils/FileUtilTest.java
index 70ad39c..87e1a18 100644
--- a/utils/src/test/java/com/cloud/utils/FileUtilTest.java
+++ b/utils/src/test/java/com/cloud/utils/FileUtilTest.java
@@ -20,49 +20,52 @@
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.io.File;
 
 import static org.mockito.ArgumentMatchers.nullable;
 
-@PrepareForTest(value = {SshHelper.class})
-@RunWith(PowerMockRunner.class)
-@PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.parsers.*", "javax.xml.*", "org.w3c.dom.*", "org.xml.*"})
+@RunWith(MockitoJUnitRunner.class)
 public class FileUtilTest {
 
     @Test
     public void successfulScpTest() throws Exception {
-        PowerMockito.mockStatic(SshHelper.class);
+        MockedStatic<SshHelper> sshHelperMocked = Mockito.mockStatic(SshHelper.class);
         String basePath = "/tmp";
         String[] files = new String[] { "file1.txt" };
         int sshPort = 3922;
         String controlIp = "10.0.0.10";
         String destPath = "/home/cloud/";
         File pemFile = new File("/root/.ssh/id_rsa");
-        PowerMockito.doNothing().when(SshHelper.class, "scpTo", Mockito.anyString(), Mockito.anyInt(), Mockito.anyString(), Mockito.any(File.class), nullable(String.class), Mockito.anyString(), Mockito.any(String[].class), Mockito.anyString());
+        sshHelperMocked.when(() ->
+                SshHelper.scpTo(
+                        Mockito.anyString(), Mockito.anyInt(), Mockito.anyString(), Mockito.any(File.class), nullable(String.class), Mockito.anyString(), Mockito.any(String[].class), Mockito.anyString()
+                )).then(invocation -> null);
         FileUtil.scpPatchFiles(controlIp, destPath, sshPort, pemFile, files, basePath);
+        sshHelperMocked.close();
     }
 
     @Test
     public void FailingScpFilesTest() throws Exception {
-        PowerMockito.mockStatic(SshHelper.class);
         String basePath = "/tmp";
         String[] files = new String[] { "file1.txt" };
         int sshPort = 3922;
         String controlIp = "10.0.0.10";
         String destPath = "/home/cloud/";
         File pemFile = new File("/root/.ssh/id_rsa");
-        PowerMockito.doThrow(new Exception()).when(SshHelper.class, "scpTo", Mockito.anyString(), Mockito.anyInt(), Mockito.anyString(), Mockito.any(File.class), Mockito.anyString(), Mockito.anyString(), Mockito.any(String[].class), Mockito.anyString());
+        MockedStatic<SshHelper> sshHelperMocked = Mockito.mockStatic(SshHelper.class);
+        sshHelperMocked.when(() ->
+                SshHelper.scpTo(Mockito.anyString(), Mockito.anyInt(), Mockito.anyString(), Mockito.any(File.class), Mockito.anyString(), Mockito.anyString(), Mockito.any(String[].class), Mockito.anyString()
+                )).thenThrow(new Exception());
         try {
             FileUtil.scpPatchFiles(controlIp, destPath, sshPort, pemFile, files, basePath);
         } catch (Exception e) {
             Assert.assertEquals("Failed to scp files to system VM", e.getMessage());
         }
+        sshHelperMocked.close();
 
     }
 
diff --git a/utils/src/test/java/com/cloud/utils/ScriptTest.java b/utils/src/test/java/com/cloud/utils/ScriptTest.java
index e6ed64a..12963dc 100644
--- a/utils/src/test/java/com/cloud/utils/ScriptTest.java
+++ b/utils/src/test/java/com/cloud/utils/ScriptTest.java
@@ -130,6 +130,6 @@
     public void testFindScript() {
         Assume.assumeTrue(SystemUtils.IS_OS_LINUX);
         String script = Script.findScript("/bin", "pwd");
-        Assert.assertNotNull("/bin/pwd shoud be there on linux", script);
+        Assert.assertNotNull("/bin/pwd should be there on linux", script);
     }
 }
diff --git a/utils/src/test/java/com/cloud/utils/TestProfiler.java b/utils/src/test/java/com/cloud/utils/TestProfiler.java
index 1520963..1d2d5f7 100644
--- a/utils/src/test/java/com/cloud/utils/TestProfiler.java
+++ b/utils/src/test/java/com/cloud/utils/TestProfiler.java
@@ -23,16 +23,11 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
 
 import com.cloud.utils.testcase.Log4jEnabledTestCase;
+import org.mockito.junit.MockitoJUnitRunner;
 
-@RunWith(PowerMockRunner.class)
-@PowerMockIgnore({ "javax.management.*", "com.sun.org.apache.xerces.*", "javax.xml.*",
-        "org.xml.*", "org.w3c.dom.*", "com.sun.org.apache.xalan.*", "javax.activation.*" })
-@PrepareForTest(Profiler.class)
+@RunWith(MockitoJUnitRunner.class)
 public class TestProfiler extends Log4jEnabledTestCase {
 
     private static final long SLEEP_TIME_NANO = 1000000000L;
diff --git a/utils/src/test/java/com/cloud/utils/UriUtilsParametrizedTest.java b/utils/src/test/java/com/cloud/utils/UriUtilsParametrizedTest.java
index 68479f5..3f1e707 100644
--- a/utils/src/test/java/com/cloud/utils/UriUtilsParametrizedTest.java
+++ b/utils/src/test/java/com/cloud/utils/UriUtilsParametrizedTest.java
@@ -31,18 +31,12 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.powermock.modules.junit4.PowerMockRunnerDelegate;
 
 import com.google.common.collect.ImmutableSet;
 
-@RunWith(PowerMockRunner.class)
-@PowerMockRunnerDelegate(Parameterized.class)
-@PowerMockIgnore({"javax.xml.*", "org.apache.xerces.*", "org.xml.*", "org.w3c.*"})
+@RunWith(Parameterized.class)
 public class UriUtilsParametrizedTest {
     @FunctionalInterface
     public interface ThrowingBlock<E extends Exception> {
@@ -149,14 +143,11 @@
     }
 
     @Test
-    @PrepareForTest({UriUtils.class})
-
     public void validateUrl() throws Exception {
 
+        MockedStatic<InetAddress> inetAddressMocked = Mockito.mockStatic(InetAddress.class);
         InetAddress inetAddressMock = Mockito.mock(InetAddress.class);
-
-        PowerMockito.mockStatic(InetAddress.class);
-        PowerMockito.when(InetAddress.getByName(Mockito.anyString())).thenReturn(inetAddressMock);
+        inetAddressMocked.when(() -> InetAddress.getByName(Mockito.anyString())).thenReturn(inetAddressMock);
 
         if (expectSuccess) {
             UriUtils.validateUrl(format, url);
@@ -164,14 +155,14 @@
             assertThrows(() -> UriUtils.validateUrl(format, url), IllegalArgumentException.class);
         }
 
-        PowerMockito.verifyStatic(InetAddress.class);
-        InetAddress.getByName(Mockito.anyString());
+        inetAddressMocked.verify(() -> InetAddress.getByName(Mockito.anyString()));
 
         Mockito.verify(inetAddressMock).isAnyLocalAddress();
         Mockito.verify(inetAddressMock).isLinkLocalAddress();
         Mockito.verify(inetAddressMock).isLoopbackAddress();
         Mockito.verify(inetAddressMock).isMulticastAddress();
 
+        inetAddressMocked.close();
     }
 
     @Test
diff --git a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
index 53e2e3a..4a6c5df 100644
--- a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
+++ b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
@@ -52,15 +52,12 @@
 import com.googlecode.ipv6.IPv6Network;
 
 import org.junit.runner.RunWith;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.runners.MockitoJUnitRunner;
 
 
-@RunWith(PowerMockRunner.class)
-@PowerMockIgnore({"jdk.xml.internal.*", "javax.xml.parsers.*", "org.xml.sax.*", "org.w3c.dom.*"})
+@RunWith(MockitoJUnitRunner.class)
 public class NetUtilsTest {
     private static final String WIDE_SHARED_NET_CIDR_IP = "10.20.0.0";
     private static final List<String> WIDE_SHARED_NET_USED_IPS = List.of("10.20.0.22", "10.20.1.22", "10.20.2.22");
@@ -815,34 +812,34 @@
     }
 
     @Test
-    @PrepareForTest(NetUtils.class)
     public void getNetworkInterfaceTestReturnNullWhenGetByNameReturnsNull() throws SocketException {
-        PowerMockito.mockStatic(NetworkInterface.class);
-        PowerMockito.when(NetworkInterface.getByName(Mockito.anyString())).thenReturn(null);
+        MockedStatic<NetworkInterface> networkInterfaceMocked = Mockito.mockStatic(NetworkInterface.class);
+        Mockito.when(NetworkInterface.getByName(Mockito.anyString())).thenReturn(null);
         NetworkInterface result = NetUtils.getNetworkInterface("  test   ");
 
         Assert.assertNull(result);
+        networkInterfaceMocked.close();
     }
 
     @Test
-    @PrepareForTest(NetUtils.class)
     public void getNetworkInterfaceTestReturnNullWhenGetByNameThrowsException() throws SocketException {
-        PowerMockito.mockStatic(NetworkInterface.class);
-        PowerMockito.when(NetworkInterface.getByName(Mockito.anyString())).thenThrow(SocketException.class);
+        MockedStatic<NetworkInterface> networkInterfaceMocked = Mockito.mockStatic(NetworkInterface.class);
+        Mockito.when(NetworkInterface.getByName(Mockito.anyString())).thenThrow(SocketException.class);
         NetworkInterface result = NetUtils.getNetworkInterface("  test   ");
 
         Assert.assertNull(result);
+        networkInterfaceMocked.close();
     }
 
     @Test
-    @PrepareForTest(NetUtils.class)
     public void getNetworkInterfaceTestReturnInterfaceReturnedByGetByName() throws SocketException {
-        NetworkInterface expected = PowerMockito.mock(NetworkInterface.class);
-        PowerMockito.mockStatic(NetworkInterface.class);
-        PowerMockito.when(NetworkInterface.getByName(Mockito.anyString())).thenReturn(expected);
+        MockedStatic<NetworkInterface> networkInterfaceMocked = Mockito.mockStatic(NetworkInterface.class);
+        NetworkInterface expected = Mockito.mock(NetworkInterface.class);
+        Mockito.when(NetworkInterface.getByName(Mockito.anyString())).thenReturn(expected);
 
         NetworkInterface result = NetUtils.getNetworkInterface("  test   ");
 
         Assert.assertEquals(expected, result);
+        networkInterfaceMocked.close();
     }
 }
diff --git a/utils/src/test/java/com/cloud/utils/ssh/SshHelperTest.java b/utils/src/test/java/com/cloud/utils/ssh/SshHelperTest.java
index 37bd089..04d8443 100644
--- a/utils/src/test/java/com/cloud/utils/ssh/SshHelperTest.java
+++ b/utils/src/test/java/com/cloud/utils/ssh/SshHelperTest.java
@@ -25,38 +25,31 @@
 import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.runners.MockitoJUnitRunner;
 
 import com.trilead.ssh2.ChannelCondition;
 import com.trilead.ssh2.Connection;
 import com.trilead.ssh2.Session;
 
-@PrepareForTest({ Thread.class, SshHelper.class })
-@PowerMockIgnore({ "javax.management.*", "com.sun.org.apache.xerces.*", "javax.xml.*",
-        "org.xml.*", "org.w3c.dom.*", "com.sun.org.apache.xalan.*", "javax.activation.*" })
-@RunWith(PowerMockRunner.class)
+@RunWith(MockitoJUnitRunner.class)
 public class SshHelperTest {
 
     @Test
     public void canEndTheSshConnectionTest() throws Exception {
-        PowerMockito.spy(SshHelper.class);
+        MockedStatic<SshHelper> sshHelperMocked = Mockito.mockStatic(SshHelper.class, Mockito.CALLS_REAL_METHODS);
         Session mockedSession = Mockito.mock(Session.class);
 
-        PowerMockito.doReturn(true).when(SshHelper.class, "isChannelConditionEof", Mockito.anyInt());
-        Mockito.when(mockedSession.waitForCondition(ChannelCondition.EXIT_STATUS, 1l)).thenReturn(0);
-        PowerMockito.doNothing().when(SshHelper.class, "throwSshExceptionIfConditionsTimeout", Mockito.anyInt());
+        Mockito.when(SshHelper.isChannelConditionEof(Mockito.anyInt())).thenReturn(true);
+        Mockito.when(mockedSession.waitForCondition(ChannelCondition.EXIT_STATUS, 1L)).thenReturn(0);
 
         SshHelper.canEndTheSshConnection(1, mockedSession, 0);
-
-        PowerMockito.verifyStatic(SshHelper.class);
-        SshHelper.isChannelConditionEof(Mockito.anyInt());
-        SshHelper.throwSshExceptionIfConditionsTimeout(Mockito.anyInt());
+        sshHelperMocked.verify(() -> SshHelper.isChannelConditionEof(Mockito.anyInt()), Mockito.times(1));
+        sshHelperMocked.verify(() -> SshHelper.throwSshExceptionIfConditionsTimeout(Mockito.anyInt()));
 
         Mockito.verify(mockedSession).waitForCondition(ChannelCondition.EXIT_STATUS, 1l);
+        sshHelperMocked.close();
     }
 
     @Test(expected = SshException.class)
@@ -143,7 +136,6 @@
     @Test
     public void openConnectionSessionTest() throws IOException, InterruptedException {
         Connection conn = Mockito.mock(Connection.class);
-        PowerMockito.mockStatic(Thread.class);
         SshHelper.openConnectionSession(conn);
 
         Mockito.verify(conn).openSession();
diff --git a/utils/src/test/java/com/cloud/utils/validation/ChecksumUtilTest.java b/utils/src/test/java/com/cloud/utils/validation/ChecksumUtilTest.java
index 08cc389..2b99275 100644
--- a/utils/src/test/java/com/cloud/utils/validation/ChecksumUtilTest.java
+++ b/utils/src/test/java/com/cloud/utils/validation/ChecksumUtilTest.java
@@ -20,37 +20,35 @@
 import org.apache.cloudstack.utils.security.DigestHelper;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
+
 
 import java.io.File;
 
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-@PrepareForTest(value = {Script.class, DigestHelper.class})
-@RunWith(PowerMockRunner.class)
-@PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.parsers.*", "javax.xml.*", "org.w3c.dom.*", "org.xml.*"})
+@RunWith(MockitoJUnitRunner.class)
 public class ChecksumUtilTest {
 
     @Test
     public void invalidFileForCheckSumValidationTest() {
-        PowerMockito.mockStatic(Script.class);
+        MockedStatic<Script> scriptMocked = Mockito.mockStatic(Script.class);
         Mockito.when(Script.findScript(Mockito.anyString(), Mockito.anyString())).thenReturn(null);
         try {
             ChecksumUtil.calculateCurrentChecksum(Mockito.anyString(), Mockito.anyString());
         } catch (Exception e) {
             assertTrue(e.getMessage().contains("Unable to find cloudScripts path, cannot update SystemVM"));
         }
+        scriptMocked.close();
     }
 
     @Test
     public void generateChecksumTest() {
-        PowerMockito.mockStatic(Script.class);
-        PowerMockito.mockStatic(DigestHelper.class);
+        MockedStatic<Script> scriptMocked = Mockito.mockStatic(Script.class);
+        MockedStatic<DigestHelper> digestHelperMocked = Mockito.mockStatic(DigestHelper.class);
         Mockito.when(Script.findScript(Mockito.anyString(), Mockito.anyString())).thenReturn("/dummyPath");
         Mockito.when(DigestHelper.calculateChecksum(Mockito.any(File.class))).thenReturn("dummy-checksum");
         try {
@@ -58,5 +56,7 @@
         } catch (Exception e) {
             fail("Failed to generate checksum");
         }
+        scriptMocked.close();
+        digestHelperMocked.close();
     }
 }
diff --git a/utils/src/test/java/org/apache/cloudstack/utils/jsinterpreter/JsInterpreterTest.java b/utils/src/test/java/org/apache/cloudstack/utils/jsinterpreter/JsInterpreterTest.java
index 1567d89..d181462 100644
--- a/utils/src/test/java/org/apache/cloudstack/utils/jsinterpreter/JsInterpreterTest.java
+++ b/utils/src/test/java/org/apache/cloudstack/utils/jsinterpreter/JsInterpreterTest.java
@@ -35,16 +35,12 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
 
 import javax.script.ScriptEngine;
 
-@RunWith(PowerMockRunner.class)
-@PowerMockIgnore({"javax.xml.*", "org.apache.xerces.*", "org.xml.*", "org.w3c.*"})
-@PrepareForTest(JsInterpreter.class)
+@RunWith(MockitoJUnitRunner.class)
 public class JsInterpreterTest {
     private long timeout = 2000;
 
@@ -95,7 +91,6 @@
     public void executeScriptTestReturnResultOfScriptExecution() {
         String script = "5";
         Object expected = new Object();
-        Mockito.doReturn(script).when(jsInterpreterSpy).addVariablesToScript(Mockito.anyString());
         Mockito.doReturn(expected).when(jsInterpreterSpy).executeScript(Mockito.anyString());
 
         Object result = jsInterpreterSpy.executeScript(script);
@@ -173,9 +168,8 @@
     }
 
     @Test
-    @PrepareForTest(NashornScriptEngineFactory.class)
     public void setScriptEngineDisablingJavaLanguageTest() {
-        NashornScriptEngineFactory nashornScriptEngineFactoryMock = Mockito.mock(NashornScriptEngineFactory.class);
+        NashornScriptEngineFactory nashornScriptEngineFactoryMock = Mockito.spy(NashornScriptEngineFactory.class);
         ScriptEngine scriptEngineMock = Mockito.mock(ScriptEngine.class);
 
         Mockito.doReturn(scriptEngineMock).when(nashornScriptEngineFactoryMock).getScriptEngine(Mockito.anyString());
diff --git a/utils/src/test/java/org/apache/cloudstack/utils/reflectiontostringbuilderutils/ReflectionToStringBuilderUtilsTest.java b/utils/src/test/java/org/apache/cloudstack/utils/reflectiontostringbuilderutils/ReflectionToStringBuilderUtilsTest.java
index 4a2a2a6..75befde 100644
--- a/utils/src/test/java/org/apache/cloudstack/utils/reflectiontostringbuilderutils/ReflectionToStringBuilderUtilsTest.java
+++ b/utils/src/test/java/org/apache/cloudstack/utils/reflectiontostringbuilderutils/ReflectionToStringBuilderUtilsTest.java
@@ -33,16 +33,12 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.MockedStatic;
 import org.mockito.Mockito;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 import org.reflections.ReflectionUtils;
 
-@RunWith(PowerMockRunner.class)
-@PowerMockIgnore({"org.w3c.*", "javax.xml.*", "org.xml.*"})
-@PrepareForTest(ReflectionToStringBuilderUtils.class)
+@RunWith(MockitoJUnitRunner.class)
 public class ReflectionToStringBuilderUtilsTest extends TestCase {
 
     private static final Set<ToStringStyle> TO_STRING_STYLES = new HashSet<>(Arrays.asList(ToStringStyle.DEFAULT_STYLE, ToStringStyle.JSON_STYLE, ToStringStyle.MULTI_LINE_STYLE,
@@ -95,60 +91,63 @@
 
     @Test
     public void validateGetObjectClassInvalidObjectMustReturnNull(){
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.isValidObject(Mockito.any())).thenReturn(false);
-
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.isValidObject(Mockito.any())).thenReturn(false);
         Class<?> result = ReflectionToStringBuilderUtils.getObjectClass("test");
 
         Assert.assertNull(result);
+        reflectionToStringBuilderUtilsMocked.close();
     }
 
     @Test
     public void validateGetObjectClassObjectIsNotACollectionMustReturnObjectClass(){
         Class<?> expectedResult = classToReflect;
 
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.isValidObject(Mockito.any())).thenReturn(true);
-        PowerMockito.when(ReflectionToStringBuilderUtils.isCollection(Mockito.any())).thenReturn(false);
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.isValidObject(Mockito.any())).thenReturn(true);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.isCollection(Mockito.any())).thenReturn(false);
 
         Class<?> result = ReflectionToStringBuilderUtils.getObjectClass("test");
 
         Assert.assertEquals(expectedResult, result);
+        reflectionToStringBuilderUtilsMocked.close();
     }
 
     @Test
     public void validateGetObjectClassObjectIsAnEmptyCollectionMustReturnNull(){
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.isValidObject(Mockito.any())).thenReturn(true);
-        PowerMockito.when(ReflectionToStringBuilderUtils.isCollection(Mockito.any())).thenReturn(true);
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.isValidObject(Mockito.any())).thenReturn(true);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.isCollection(Mockito.any())).thenReturn(true);
 
         Class<?> result = ReflectionToStringBuilderUtils.getObjectClass(new ArrayList<String>());
 
         Assert.assertNull(result);
+        reflectionToStringBuilderUtilsMocked.close();
     }
 
     @Test
     public void validateGetObjectClassObjectIsACollectionWithOnlyNullValuesMustReturnNull(){
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.isValidObject(Mockito.any())).thenReturn(true);
-        PowerMockito.when(ReflectionToStringBuilderUtils.isCollection(Mockito.any())).thenReturn(true);
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.isValidObject(Mockito.any())).thenReturn(true);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.isCollection(Mockito.any())).thenReturn(true);
 
         Class<?> result = ReflectionToStringBuilderUtils.getObjectClass(new ArrayList<String>(Arrays.asList(null, null)));
 
         Assert.assertNull(result);
+        reflectionToStringBuilderUtilsMocked.close();
     }
 
     @Test
     public void validateGetObjectClassObjectIsACollectionWithAtLeastOneObjectsMustReturnObjectClass(){
         Class<?> expectedResult = classToReflect;
-
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.isValidObject(Mockito.any())).thenReturn(true);
-        PowerMockito.when(ReflectionToStringBuilderUtils.isCollection(Mockito.any())).thenReturn(true);
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.isValidObject(Mockito.any())).thenReturn(true);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.isCollection(Mockito.any())).thenReturn(true);
 
         Class<?> result = ReflectionToStringBuilderUtils.getObjectClass(new ArrayList<>(Arrays.asList(null, "test1")));
 
         Assert.assertEquals(expectedResult, result);
+        reflectionToStringBuilderUtilsMocked.close();
     }
 
     @Test
@@ -163,12 +162,13 @@
 
     @Test
     public void validateGetNonSelectedFieldsNullObjectClassMustReturnNull(){
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.getObjectClass(Mockito.any())).thenReturn(null);
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.getObjectClass(Mockito.any())).thenReturn(null);
 
         String[] result = ReflectionToStringBuilderUtils.getNonSelectedFields(null, "test1", "test2");
 
         Assert.assertNull(result);
+        reflectionToStringBuilderUtilsMocked.close();
     }
 
     @Test
@@ -250,26 +250,28 @@
 
     @Test
     public void validateReflectOnlySelectedFieldsNullNonSelectedFieldsMustReturnNull() throws Exception{
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.getNonSelectedFields(Mockito.any(), Mockito.any())).thenReturn(null);
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.getNonSelectedFields(Mockito.any(), Mockito.any())).thenReturn(null);
 
         TO_STRING_STYLES.forEach(style -> {
             String result = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(null, style, "-");
             Assert.assertNull(result);
         });
+        reflectionToStringBuilderUtilsMocked.close();
     }
 
     @Test
     public void validateReflectOnlySelectedFieldsEmptyNonSelectedFieldsMustReturnEmptyString() throws Exception{
         String expectedResult = "";
 
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.getNonSelectedFields(Mockito.any(), Mockito.any())).thenReturn(new String[0]);
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.getNonSelectedFields(Mockito.any(), Mockito.any())).thenReturn(new String[0]);
 
         TO_STRING_STYLES.forEach(style -> {
             String result = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(null, style, "-");
             Assert.assertEquals(expectedResult, result);
         });
+        reflectionToStringBuilderUtilsMocked.close();
     }
 
     @Test
@@ -277,80 +279,85 @@
         String fieldToRemove = classToReflectRemovedField;
         String expectedResult = "test";
 
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.getNonSelectedFields(Mockito.any(), Mockito.any())).thenReturn(classToReflectFieldsNamesArray);
-        PowerMockito.when(ReflectionToStringBuilderUtils.reflectCollection(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any())).thenReturn(expectedResult);
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.getNonSelectedFields(Mockito.any(), Mockito.any())).thenReturn(classToReflectFieldsNamesArray);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.reflectCollection(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any())).thenReturn(expectedResult);
 
         TO_STRING_STYLES.forEach(style -> {
             String result = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(new Object(), style, "-", fieldToRemove);
             Assert.assertEquals(expectedResult, result);
         });
+        reflectionToStringBuilderUtilsMocked.close();
     }
 
     @Test
     public void validateReflectOnlySelectedFieldsObjectIsNotACollectionMustReflectObject() throws Exception{
         String expectedResult = "test";
 
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.getNonSelectedFields(Mockito.any(), Mockito.any())).thenReturn(classToReflectFieldsNamesArray);
-        PowerMockito.when(ReflectionToStringBuilderUtils.reflectCollection(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any())).thenReturn(null);
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.getNonSelectedFields(Mockito.any(), Mockito.any())).thenReturn(classToReflectFieldsNamesArray);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.reflectCollection(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any())).thenReturn(null);
 
         for (ToStringStyle style : TO_STRING_STYLES){
-            PowerMockito.doReturn(expectedResult).when(ReflectionToStringBuilderUtils.class, "getReflectedObject", Mockito.any(), Mockito.any(), Mockito.any());
+            reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.getReflectedObject(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(expectedResult);
             String result = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(expectedResult, style, "-", classToReflectFieldsNamesArray);
             Assert.assertEquals(expectedResult, result);
         }
+        reflectionToStringBuilderUtilsMocked.close();
     }
 
     @Test
     public void validateReflectOnlySelectedFieldsDefaultStyleReflectionNullMustReturnNull(){
         String expectedResult = null;
 
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.reflectOnlySelectedFields(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any())).thenReturn(null);
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.reflectOnlySelectedFields(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any())).thenReturn(null);
 
         String result = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(new Object(), (String[]) null);
         Assert.assertEquals(expectedResult, result);
+        reflectionToStringBuilderUtilsMocked.close();
     }
 
     @Test
     public void validateReflectOnlySelectedFieldsDefaultStyleReflectCollectionMustReturnValue(){
         String expectedResult = "[test]";
 
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.reflectOnlySelectedFields(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any())).thenReturn("test");
-        PowerMockito.when(ReflectionToStringBuilderUtils.isCollection(Mockito.any())).thenReturn(true);
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.reflectOnlySelectedFields(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any())).thenReturn("test");
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.isCollection(Mockito.any())).thenReturn(true);
 
         String result = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(new Object());
         Assert.assertEquals(expectedResult, result);
+        reflectionToStringBuilderUtilsMocked.close();
     }
 
     @Test
     public void validateReflectOnlySelectedFieldsDefaultStyleReflectMustReturnValue(){
         String expectedResult = "test";
 
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.reflectOnlySelectedFields(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any())).thenReturn(expectedResult);
-        PowerMockito.when(ReflectionToStringBuilderUtils.isCollection(Mockito.any())).thenReturn(false);
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.reflectOnlySelectedFields(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any())).thenReturn(expectedResult);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.isCollection(Mockito.any())).thenReturn(false);
 
         String result = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(new Object());
         Assert.assertEquals(expectedResult, result);
+        reflectionToStringBuilderUtilsMocked.close();
     }
 
     @Test
     public void reflectCollectionTestCallBaseReflectCollectionMethodWithDefaultParameters() {
         String expected = "test";
 
-        PowerMockito.spy(ReflectionToStringBuilderUtils.class);
-        PowerMockito.when(ReflectionToStringBuilderUtils.reflectCollection(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any())).thenReturn(expected);
+        MockedStatic<ReflectionToStringBuilderUtils> reflectionToStringBuilderUtilsMocked = Mockito.mockStatic(ReflectionToStringBuilderUtils.class, Mockito.CALLS_REAL_METHODS);
+        reflectionToStringBuilderUtilsMocked.when(() -> ReflectionToStringBuilderUtils.reflectCollection(Mockito.any(), Mockito.any(), Mockito.anyString(), Mockito.any())).thenReturn(expected);
 
         Object object = Mockito.mock(Object.class);
         String result = ReflectionToStringBuilderUtils.reflectCollection(object);
 
         Assert.assertEquals(expected, result);
 
-        PowerMockito.verifyStatic(ReflectionToStringBuilderUtils.class);
         String[] excludeFields = null;
-        ReflectionToStringBuilderUtils.reflectCollection(object, DEFAULT_STYLE, DEFAULT_MULTIPLE_VALUES_SEPARATOR, excludeFields);
+        reflectionToStringBuilderUtilsMocked.verify(() -> ReflectionToStringBuilderUtils.reflectCollection(object, DEFAULT_STYLE, DEFAULT_MULTIPLE_VALUES_SEPARATOR, excludeFields));
+        reflectionToStringBuilderUtilsMocked.close();
     }
 }
diff --git a/utils/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/utils/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d4
--- /dev/null
+++ b/utils/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/vmware-base/pom.xml b/vmware-base/pom.xml
index 89bf9c6..8d7b716 100644
--- a/vmware-base/pom.xml
+++ b/vmware-base/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.cloudstack</groupId>
         <artifactId>cloudstack</artifactId>
-        <version>4.18.1.0-SNAPSHOT</version>
+        <version>4.19.0.0-SNAPSHOT</version>
     </parent>
     <dependencies>
         <dependency>
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/BaseMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/BaseMO.java
index 430eb6d..153efe2 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/BaseMO.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/BaseMO.java
@@ -114,7 +114,7 @@
                 key = field.getKey();
             } catch (Exception e) {
                 // assuming the exception is caused by concurrent operation from other places
-                // so we retieve the key again
+                // so we retrieve the key again
                 key = getCustomFieldKey(fieldName);
             }
         }
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java
index 095b20c..e78c843 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java
@@ -69,7 +69,7 @@
 //
 public class ClusterMO extends BaseMO implements VmwareHypervisorHost {
     private static final Logger s_logger = Logger.getLogger(ClusterMO.class);
-    private ManagedObjectReference _environmentBrowser = null;
+    protected ManagedObjectReference _environmentBrowser = null;
 
     public ClusterMO(VmwareContext context, ManagedObjectReference morCluster) {
         super(context, morCluster);
@@ -740,4 +740,22 @@
             throw new CloudRuntimeException(msg);
         }
     }
+
+    @Override
+    public GuestOsDescriptor getGuestOsDescriptor(String guestOsId) throws Exception {
+        VirtualMachineConfigOption vmConfigOption = _context.getService().queryConfigOption(getEnvironmentBrowser(), null, null);
+        List<GuestOsDescriptor> guestDescriptors = vmConfigOption.getGuestOSDescriptor();
+        for (GuestOsDescriptor descriptor : guestDescriptors) {
+            if (guestOsId != null && guestOsId.equalsIgnoreCase(descriptor.getId())) {
+                return descriptor;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public List<GuestOsDescriptor> getGuestOsDescriptors() throws Exception {
+        VirtualMachineConfigOption vmConfigOption = _context.getService().queryConfigOption(getEnvironmentBrowser(), null, null);
+        return vmConfigOption.getGuestOSDescriptor();
+    }
 }
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java
index a76e7d9..497c172 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DatastoreMO.java
@@ -281,7 +281,7 @@
                 return false;
             }
         } catch (Exception e) {
-            s_logger.error(String.format("Cannot move file to destination datastore due to file %s due to exeception %s", srcFullPath, e.getMessage()));
+            s_logger.error(String.format("Cannot move file to destination datastore due to file %s due to exception %s", srcFullPath, e.getMessage()));
             return false;
         }
 
@@ -307,7 +307,7 @@
         String url = getContext().composeDatastoreBrowseUrl(dcPair.second(), fullPath);
 
         // TODO, VMware currently does not have a formal API to list Datastore directory content,
-        // folloing hacking may have performance hit if datastore has a large number of files
+        // following hacking may have performance hit if datastore has a large number of files
         return _context.listDatastoreDirContent(url);
     }
 
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java
index 15d80fc..3b96e7e 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java
@@ -36,6 +36,7 @@
 import com.vmware.vim25.CustomFieldStringValue;
 import com.vmware.vim25.DatastoreSummary;
 import com.vmware.vim25.DynamicProperty;
+import com.vmware.vim25.GuestOsDescriptor;
 import com.vmware.vim25.HostConfigManager;
 import com.vmware.vim25.HostConnectInfo;
 import com.vmware.vim25.HostFirewallInfo;
@@ -1088,7 +1089,7 @@
 
         HostListSummaryQuickStats stats = getHostQuickStats();
         if (stats.getOverallCpuUsage() == null || stats.getOverallMemoryUsage() == null)
-            throw new Exception("Unable to get valid overal CPU/Memory usage data, host may be disconnected");
+            throw new Exception("Unable to get valid overall CPU/Memory usage data, host may be disconnected");
 
         resourceSummary.setEffectiveCpu(totalCpu - stats.getOverallCpuUsage());
 
@@ -1165,6 +1166,26 @@
         return null;
     }
 
+    @Override
+    public GuestOsDescriptor getGuestOsDescriptor(String guestOsId) throws Exception {
+        ManagedObjectReference morParent = getParentMor();
+        if (morParent.getType().equals("ClusterComputeResource")) {
+            ClusterMO clusterMo = new ClusterMO(_context, morParent);
+            return clusterMo.getGuestOsDescriptor(guestOsId);
+        }
+        return null;
+    }
+
+    @Override
+    public List<GuestOsDescriptor> getGuestOsDescriptors() throws Exception {
+        ManagedObjectReference morParent = getParentMor();
+        if (morParent.getType().equals("ClusterComputeResource")) {
+            ClusterMO clusterMo = new ClusterMO(_context, morParent);
+            return clusterMo.getGuestOsDescriptors();
+        }
+        return null;
+    }
+
     public String getHostManagementIp(String managementPortGroup) throws Exception {
         HostNetworkInfo netInfo = getHostNetworkInfo();
 
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HttpNfcLeaseMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HttpNfcLeaseMO.java
index 6e4980c..367a21b 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HttpNfcLeaseMO.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HttpNfcLeaseMO.java
@@ -159,11 +159,11 @@
         public void run() {
             while (!_done) {
                 try {
-                    Thread.sleep(1000);            // update progess every 1 second
+                    Thread.sleep(1000);            // update progress every 1 second
                     updateLeaseProgress(_percent);
                 } catch (InterruptedException e) {
                     if (s_logger.isInfoEnabled())
-                        s_logger.info("ProgressReporter is interrupted, quiting");
+                        s_logger.info("ProgressReporter is interrupted, quitting");
                     break;
                 } catch (Exception e) {
                     s_logger.warn("Unexpected exception ", e);
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java
index 5cc8899..12ef462 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java
@@ -1866,7 +1866,7 @@
 
     /**
      * deploys a new VM from a ovf spec. It ignores network, defaults locale to 'US'
-     * @throws Exception shoud be a VmwareResourceException
+     * @throws Exception should be a VmwareResourceException
      */
     public static void importVmFromOVF(VmwareHypervisorHost host, String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption, ManagedObjectReference morRp,
                                        ManagedObjectReference morHost, String configurationId) throws CloudRuntimeException, IOException {
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
index cecdb47..bd9bc03 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
@@ -1881,7 +1881,7 @@
 
                         // tar files into OVA
                         if (packToOva) {
-                            // Important! we need to sync file system before we can safely use tar to work around a linux kernal bug(or feature)
+                            // Important! we need to sync file system before we can safely use tar to work around a linux kernel bug(or feature)
                             s_logger.info("Sync file system before we package OVA...");
 
                             Script commandSync = new Script(true, "sync", 0, s_logger);
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java
index ce2f178..2177b06 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java
@@ -20,6 +20,7 @@
 
 import com.vmware.vim25.ClusterDasConfigInfo;
 import com.vmware.vim25.ComputeResourceSummary;
+import com.vmware.vim25.GuestOsDescriptor;
 import com.vmware.vim25.ManagedObjectReference;
 import com.vmware.vim25.ObjectContent;
 import com.vmware.vim25.VirtualMachineConfigSpec;
@@ -91,5 +92,10 @@
     ComputeResourceSummary getHyperHostHardwareSummary() throws Exception;
 
     LicenseAssignmentManagerMO getLicenseAssignmentManager() throws Exception;
+
     String getRecommendedDiskController(String guestOsId) throws Exception;
+
+    GuestOsDescriptor getGuestOsDescriptor(String guestOsId) throws Exception;
+
+    List<GuestOsDescriptor> getGuestOsDescriptors() throws Exception;
 }
diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareContext.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareContext.java
index 1599408..9da2ee3 100644
--- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareContext.java
+++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/util/VmwareContext.java
@@ -550,7 +550,7 @@
      * Url for the query
      *     https://vsphere-1.lab.vmops.com/folder/Fedora-clone-test?dcPath=cupertino&dsName=NFS+datastore
      *
-     * Returned conent from vSphere
+     * Returned content from vSphere
      *
         <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
         <html>
diff --git a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/DatastoreMOTest.java b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/DatastoreMOTest.java
index cf16979..6e1793a 100644
--- a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/DatastoreMOTest.java
+++ b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/DatastoreMOTest.java
@@ -22,28 +22,24 @@
 import com.vmware.vim25.FileInfo;
 import com.vmware.vim25.HostDatastoreBrowserSearchResults;
 import com.vmware.vim25.ManagedObjectReference;
-import com.vmware.vim25.VimPortType;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.MockedConstruction;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.ArrayList;
 
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 
-/**
- * Created by sudharma_jain on 6/13/17.
- */
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(DatastoreMO.class)
+
+@RunWith(MockitoJUnitRunner.class)
 public class DatastoreMOTest {
     @Mock
     VmwareContext _context ;
@@ -51,22 +47,20 @@
     VmwareClient _client;
     @Mock
     ManagedObjectReference _mor;
-    @Mock
-    HostDatastoreBrowserMO browserMo;
-    @Mock
-    VimPortType vimPortType;
 
     DatastoreMO datastoreMO ;
     String fileName = "ROOT-5.vmdk";
 
+    MockedConstruction<HostDatastoreBrowserMO> hostDataStoreBrowserMoConstruction;
+
 
     @Before
     public void setUp() throws Exception {
 
         datastoreMO = new DatastoreMO(_context, _mor);
-        PowerMockito.whenNew(HostDatastoreBrowserMO.class).withAnyArguments().thenReturn(browserMo);
         when(_context.getVimClient()).thenReturn(_client);
-        when(_client.getDynamicProperty(any(ManagedObjectReference.class), eq("name"))).thenReturn("252d36c96cfb32f48ce7756ccb79ae37");
+        when(_client.getDynamicProperty(any(ManagedObjectReference.class), eq("name"))).thenReturn(
+                "252d36c96cfb32f48ce7756ccb79ae37");
 
         ArrayList<HostDatastoreBrowserSearchResults> results = new ArrayList<>();
 
@@ -92,23 +86,28 @@
         results.add(r2);
         results.add(r3);
 
-        when(browserMo.searchDatastore(any(String.class), any(String.class), eq(true))).thenReturn(null);
-        when(browserMo.searchDatastoreSubFolders(any(String.class),any(String.class), any(Boolean.class) )).thenReturn(results);
+        hostDataStoreBrowserMoConstruction = Mockito.mockConstruction(HostDatastoreBrowserMO.class, (mock, context) -> {
+            when(mock.searchDatastore(any(String.class), any(String.class), eq(true))).thenReturn(null);
+            when(mock.searchDatastoreSubFolders(any(String.class),any(String.class), any(Boolean.class) )).thenReturn(results);
+        });
     }
 
     @After
     public void tearDown() throws Exception {
-
+        hostDataStoreBrowserMoConstruction.close();
     }
 
     @Test
     public void testSearchFileInSubFolders() throws Exception {
-        assertEquals("Unexpected Behavior: search should exclude .snapshot folder", "[252d36c96cfb32f48ce7756ccb79ae37] i-2-5-VM/ROOT-5.vmdk", datastoreMO.searchFileInSubFolders(fileName, false, ".snapshot") );
+        assertEquals("Unexpected Behavior: search should exclude .snapshot folder",
+                "[252d36c96cfb32f48ce7756ccb79ae37] i-2-5-VM/ROOT-5.vmdk",
+                datastoreMO.searchFileInSubFolders(fileName, false, ".snapshot"));
     }
 
     @Test
     public void testSearchFileInSubFoldersWithExcludeMultipleFolders() throws Exception {
-        assertEquals("Unexpected Behavior: search should exclude folders", datastoreMO.searchFileInSubFolders(fileName, false, "i-2-5-VM, .snapshot/hourly.2017-02-23_1705"), "[252d36c96cfb32f48ce7756ccb79ae37] .snapshot/hourly.2017-02-23_1605/i-2-5-VM/ROOT-5.vmdk" );
+        assertEquals("Unexpected Behavior: search should exclude folders",
+                "[252d36c96cfb32f48ce7756ccb79ae37] .snapshot/hourly.2017-02-23_1605/i-2-5-VM/ROOT-5.vmdk",
+                datastoreMO.searchFileInSubFolders(fileName, false, "i-2-5-VM, .snapshot/hourly.2017-02-23_1705"));
     }
-
 }
diff --git a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HostMOTest.java b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HostMOTest.java
new file mode 100644
index 0000000..5314f8f
--- /dev/null
+++ b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HostMOTest.java
@@ -0,0 +1,97 @@
+// 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.hypervisor.vmware.mo;
+
+import com.cloud.hypervisor.vmware.util.VmwareClient;
+import com.cloud.hypervisor.vmware.util.VmwareContext;
+import com.vmware.vim25.GuestOsDescriptor;
+import com.vmware.vim25.ManagedObjectReference;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockedConstruction;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class HostMOTest {
+
+    @Mock
+    VmwareContext _context ;
+    @Mock
+    VmwareClient _client;
+    @Mock
+    ManagedObjectReference _mor;
+    @Mock
+    ManagedObjectReference _environmentBrowser;
+
+    @Mock
+    GuestOsDescriptor guestOsDescriptor;
+
+    HostMO hostMO ;
+    ClusterMO clusterMO ;
+
+    AutoCloseable closeable;
+
+    @Before
+    public void setUp() throws Exception {
+        closeable = MockitoAnnotations.openMocks(this);
+        hostMO = new HostMO(_context, _mor);
+        clusterMO = new ClusterMO(_context, _mor);
+        clusterMO._environmentBrowser = _environmentBrowser;
+        when(_context.getVimClient()).thenReturn(_client);
+        when(_client.getDynamicProperty(any(ManagedObjectReference.class), eq("parent"))).thenReturn(_mor);
+        when(_mor.getType()).thenReturn("ClusterComputeResource");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        closeable.close();
+    }
+
+    @Test
+    public void testGetGuestOsDescriptors() throws Exception {
+        List<GuestOsDescriptor> guestOsDescriptors = new ArrayList<>();
+        guestOsDescriptors.add(guestOsDescriptor);
+        try (MockedConstruction<ClusterMO> ignored = Mockito.mockConstruction(ClusterMO.class,
+                (mock, context) -> when(mock.getGuestOsDescriptors()).thenReturn(guestOsDescriptors))) {
+            List<GuestOsDescriptor> result = hostMO.getGuestOsDescriptors();
+            Assert.assertEquals(guestOsDescriptor, result.get(0));
+        }
+    }
+
+    @Test
+    public void testGetGuestOsDescriptor() throws Exception {
+        try (MockedConstruction<ClusterMO> ignored = Mockito.mockConstruction(ClusterMO.class,
+                (mock, context) -> when(mock.getGuestOsDescriptor(any(String.class))).thenReturn(guestOsDescriptor))) {
+            GuestOsDescriptor result = hostMO.getGuestOsDescriptor("1");
+            Assert.assertEquals(guestOsDescriptor, result);
+        }
+    }
+}
diff --git a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java
index ff4169d..1c888a0 100644
--- a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java
+++ b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/HypervisorHostHelperTest.java
@@ -20,10 +20,10 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.when;
 
 import java.util.HashMap;
@@ -85,9 +85,11 @@
     String prefix;
     String svlanId = null;
 
+    AutoCloseable closeable;
+
     @Before
     public void setup() throws Exception {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         when(context.getServiceContent()).thenReturn(serviceContent);
         when(serviceContent.getAbout()).thenReturn(aboutInfo);
         when(clusterMO.getClusterConfigInfo()).thenReturn(clusterConfigInfo);
@@ -102,12 +104,9 @@
     public static void tearDownAfterClass() throws Exception {
     }
 
-    @Before
-    public void setUp() throws Exception {
-    }
-
     @After
     public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
@@ -129,8 +128,8 @@
     @Test
     public void testGetVcenterApiVersionWithNullContextObject() throws Exception {
         assertNull(HypervisorHostHelper.getVcenterApiVersion(null));
-        verifyZeroInteractions(aboutInfo);
-        verifyZeroInteractions(serviceContent);
+        verifyNoInteractions(aboutInfo);
+        verifyNoInteractions(serviceContent);
     }
 
     @Test
diff --git a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMOTest.java b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMOTest.java
index 7d07a90..570f2a7 100644
--- a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMOTest.java
+++ b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMOTest.java
@@ -35,13 +35,13 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
@@ -56,12 +56,14 @@
 
     VirtualMachineMO vmMo;
 
+    AutoCloseable closeable;
+
     private List<VirtualDevice> getVirtualScSiDeviceList(Class<?> cls) {
 
         List<VirtualDevice> deviceList = new ArrayList<>();
         try {
 
-            VirtualSCSIController scsiController = (VirtualSCSIController)cls.newInstance();
+            VirtualSCSIController scsiController = (VirtualSCSIController)cls.getDeclaredConstructor().newInstance();
             scsiController.setSharedBus(VirtualSCSISharing.NO_SHARING);
             scsiController.setBusNumber(0);
             scsiController.setKey(1);
@@ -76,7 +78,7 @@
 
     @Before
     public void setup() {
-        MockitoAnnotations.initMocks(this);
+        closeable = MockitoAnnotations.openMocks(this);
         vmMo = new VirtualMachineMO(context, mor);
         when(context.getVimClient()).thenReturn(client);
     }
@@ -89,12 +91,9 @@
     public static void tearDownAfterClass() throws Exception {
     }
 
-    @Before
-    public void setUp() throws Exception {
-    }
-
     @After
     public void tearDown() throws Exception {
+        closeable.close();
     }
 
     @Test
diff --git a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/util/VmwareContextTest.java b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/util/VmwareContextTest.java
index 732d45c..6e48806 100644
--- a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/util/VmwareContextTest.java
+++ b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/util/VmwareContextTest.java
@@ -26,7 +26,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
-import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.junit.MockitoJUnitRunner;
 
 @RunWith(MockitoJUnitRunner.class)
 public class VmwareContextTest {
@@ -42,6 +42,9 @@
         Mockito.doReturn(conn).when(vmwareContext).getHTTPConnection("http://example.com", "PUT");
         //This method should not throw any exception. Ref: CLOUDSTACK-8669
         vmwareContext.uploadResourceContent("http://example.com", "content".getBytes());
+        Mockito.verify(vmwareContext, Mockito.times(1)).getHTTPConnection("http://example.com", "PUT");
+        Mockito.verify(conn, Mockito.times(1)).getOutputStream();
+        Mockito.verify(conn, Mockito.times(1)).getInputStream();
     }
 
 }
diff --git a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/util/VmwareHelperTest.java b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/util/VmwareHelperTest.java
index 4417748..1376fdd 100644
--- a/vmware-base/src/test/java/com/cloud/hypervisor/vmware/util/VmwareHelperTest.java
+++ b/vmware-base/src/test/java/com/cloud/hypervisor/vmware/util/VmwareHelperTest.java
@@ -18,6 +18,7 @@
 package com.cloud.hypervisor.vmware.util;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -37,7 +38,7 @@
     public void prepareDiskDeviceTestNotLimitingIOPS() throws Exception {
         Mockito.when(virtualMachineMO.getIDEDeviceControllerKey()).thenReturn(1);
         VirtualDisk virtualDisk = (VirtualDisk) VmwareHelper.prepareDiskDevice(virtualMachineMO, null, -1, new String[1], null, 0, 0, null);
-        assertEquals(null, virtualDisk.getStorageIOAllocation());
+        assertNull(virtualDisk.getStorageIOAllocation());
     }
 
     @Test
@@ -51,6 +52,6 @@
     public void prepareDiskDeviceTestLimitingIOPSToZero() throws Exception {
         Mockito.when(virtualMachineMO.getIDEDeviceControllerKey()).thenReturn(1);
         VirtualDisk virtualDisk = (VirtualDisk) VmwareHelper.prepareDiskDevice(virtualMachineMO, null, -1, new String[1], null, 0, 0, Long.valueOf(0));
-        assertEquals(null, virtualDisk.getStorageIOAllocation());
+        assertNull(virtualDisk.getStorageIOAllocation());
     }
 }
diff --git a/vmware-base/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/vmware-base/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d4
--- /dev/null
+++ b/vmware-base/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline