Test suite updates:

- Move test suite to use @vscode/test-electron, so that we can now test all available code not just things that don't call the vscode api.
- Create additonal unit tests, adding on to previous ones already made.
- Restructure some code to make code flow better and easier to test.
- Remove commented out lines from .vscode/launch.json.
- Add new packages to the package LICENSE file.
- Remove moo packages as they aren't used

Closes #118
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index c46a682..1d50790 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -111,5 +111,8 @@
         if: runner.os == 'Windows'
       - run: yarn install
       - run: yarn package
+      - run: xvfb-run -a yarn test
+        if: runner.os == 'Linux'
       - run: yarn test
+        if: runner.os != 'Linux'
       - run: $SBT test
diff --git a/.vscode/launch.json b/.vscode/launch.json
index b11cd6d..03c9cee 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -33,20 +33,16 @@
 		},
 		{
 			"name": "Tests",
-			"type": "node",
+			"type": "extensionHost",
 			"request": "launch",
-			"cwd": "${workspaceFolder}",
-			"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
+			"runtimeExecutable": "${execPath}",
 			"args": [
-				"-u", "tdd",
-				"--timeout", "999999",
-				"--colors",
-				"./out/tests/"
+				"--extensionDevelopmentPath=${workspaceFolder}",
+				"--extensionTestsPath=${workspaceFolder}/out/tests/suite"
 			],
 			"outFiles": [
-				"${workspaceFolder}/out/**/*.js"
+				"${workspaceFolder}/out/tests/**/*.js",
 			],
-			"internalConsoleOptions": "openOnSessionStart",
 			"preLaunchTask": "npm: compile"
 		}
 	]
diff --git a/build.sbt b/build.sbt
index 81ed76e..23c1fdc 100644
--- a/build.sbt
+++ b/build.sbt
@@ -23,7 +23,7 @@
 lazy val commonSettings =
   Seq(
     version := {
-      val versionRegex = raw"""  "version": "(.*)",""".r
+      val versionRegex = raw""""version": "(.*)",""".r
       val packageJsonStr = scala.io.Source.fromFile("package.json").mkString
       versionRegex.findFirstMatchIn(packageJsonStr) match {
         case Some(m) => m.group(1)
diff --git a/build/package/LICENSE b/build/package/LICENSE
index 9ea213b..d2bace7 100644
--- a/build/package/LICENSE
+++ b/build/package/LICENSE
@@ -675,40 +675,6 @@
     SOFTWARE.
 
 - extension/dist/ext/extension.js
-  This product bundles 'moo' from the above files.
-  These files are available under the BSD 3-Clause License:
-
-    BSD 3-Clause License
-
-    Copyright (c) 2017, Tim Radvan (tjvr)
-    All rights reserved.
-
-    Redistribution and use in source and binary forms, with or without
-    modification, are permitted provided that the following conditions are met:
-
-    * Redistributions of source code must retain the above copyright notice, this
-      list of conditions and the following disclaimer.
-
-    * Redistributions in binary form must reproduce the above copyright notice,
-      this list of conditions and the following disclaimer in the documentation
-      and/or other materials provided with the distribution.
-
-    * Neither the name of the copyright holder nor the names of its
-      contributors may be used to endorse or promote products derived from
-      this software without specific prior written permission.
-
-    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-- extension/dist/ext/extension.js
   This product bundles 'MD5 file' from the above files.
   These files are available under the MIT License:
 
@@ -1107,6 +1073,112 @@
     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     THE SOFTWARE.
 
+- extension/dist/ext/extension.js
+  This product bundles 'uuid' from the above files.
+  This package is available under the MIT LICENSE:
+
+    The MIT License (MIT)
+
+    Copyright (c) 2010-2020 Robert Kieffer and other contributors
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+- extension/dist/ext/extension.js
+  This product bundles 'wait-port' from the above files.
+  This package is available under the MIT LICENSE:
+
+    MIT License
+
+    Copyright (c) 2017 Dave Kerr
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in all
+    copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+    SOFTWARE.
+
+- extension/dist/ext/extension.js
+  This product bundles 'chalk' from the above files.
+  This package is available under the MIT LICENSE:
+
+    MIT License
+
+    Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+- extension/dist/ext/extension.js
+  This product bundles 'commander' from the above files.
+  This package is available under the MIT LICENSE:
+
+    (The MIT License)
+
+    Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
+
+    Permission is hereby granted, free of charge, to any person obtaining
+    a copy of this software and associated documentation files (the
+    'Software'), to deal in the Software without restriction, including
+    without limitation the rights to use, copy, modify, merge, publish,
+    distribute, sublicense, and/or sell copies of the Software, and to
+    permit persons to whom the Software is furnished to do so, subject to
+    the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+- extension/dist/ext/extension.js
+  This product bundles 'debug' from the above files.
+  This package is available under the MIT LICENSE:
+
+    (The MIT License)
+
+    Copyright (c) 2014-2017 TJ Holowaychuk <tj@vision-media.ca>
+    Copyright (c) 2018-2021 Josh Junon
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+    and associated documentation files (the 'Software'), to deal in the Software without restriction,
+    including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+    subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in all copies or substantial
+    portions of the Software.
+
+    THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+    LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
 - ch.qos.logback.logback-classic-<VERSION>.jar in daffodil-debugger-<VERSION>.zip
 - ch.qos.logback.logback-core-<VERSION>.jar in daffodil-debugger-<VERSION>.zip
   This product bundles 'logback' from the above files.
diff --git a/package.json b/package.json
index 8dfdaed..a81ffdd 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "apache-daffodil-vscode",
   "displayName": "Apache Daffodil VS Code Extension",
   "description": "VS Code extension for Apache Daffodil DFDL schema debugging",
-  "version": "1.1.0",
+  "version": "1.1.0-SNAPSHOT",
   "daffodilVersion": "3.3.0",
   "omegaEditServerHash": "ffabce0d095364d1c863466f522dfa0ac2f0574d6394a82c0239a613bb84baf7c7b9fd92fdb0457e1d3c9321249acc21567d7dcfd6ff0528e0e792da1b487407",
   "publisher": "asf",
@@ -35,21 +35,21 @@
     "package": "yarn package-setup && yarn package-create",
     "package-setup": "node -e \"require('./build/scripts/package.ts').setup()\"",
     "package-create": "node -e \"require('./build/scripts/package.ts').create()\"",
-    "pretest": "yarn run compile",
-    "test": "node node_modules/mocha/bin/_mocha -u tdd --timeout 999999 --colors ./out/tests",
+    "pretest": "yarn run compile && yarn run webpack",
+    "test": "node ./out/tests/runTest.js",
     "sbt": "sbt universal:packageBin"
   },
   "dependencies": {
     "@grpc/grpc-js": "^1.5.4",
-    "@types/moo": "^0.5.5",
     "await-notify": "1.0.1",
     "child_process": "1.0.2",
     "google-protobuf": "3.20.1",
     "hexy": "0.3.4",
-    "moo": "0.5.1",
     "omega-edit": "0.9.20",
     "unzip-stream": "0.3.1",
+    "uuid": "^8.3.2",
     "vscode-debugadapter": "1.51.0",
+    "wait-port": "^0.3.0",
     "xdg-app-paths": "7.3.0"
   },
   "devDependencies": {
@@ -57,6 +57,7 @@
     "@types/mocha": "^9.1.1",
     "@types/node": "^18.0.0",
     "@types/vscode": "^1.55.0",
+    "@vscode/test-electron": "^2.1.5",
     "glob": "8.0.3",
     "mocha": "10.0.0",
     "prettier": "2.7.1",
diff --git a/src/adapter/activateDaffodilDebug.ts b/src/adapter/activateDaffodilDebug.ts
index 15331a3..3f7e03f 100644
--- a/src/adapter/activateDaffodilDebug.ts
+++ b/src/adapter/activateDaffodilDebug.ts
@@ -24,6 +24,43 @@
 import * as omegaEditClient from '../omega_edit/client'
 import * as dfdlLang from '../language/dfdl'
 
+/** Method to file path for program and data
+ * Details:
+ *   Required so that the vscode api commands:
+ *     - extension.dfdl-debug.getProgramName
+ *     - extension.dfdl-debug.getDataName
+ *   can be sent a file instead of always opening up a prompt.
+ *   Always makes it so the vscode api commands above are able
+ *   to be tested inside of the test suite
+ */
+async function getFile(fileRequested, label, title) {
+  let file = ''
+
+  if (fileRequested && fs.existsSync(fileRequested)) {
+    file = fileRequested
+  } else if (fileRequested && !fs.existsSync(fileRequested)) {
+    file = ''
+  } else {
+    file = await vscode.window
+      .showOpenDialog({
+        canSelectMany: false,
+        openLabel: label,
+        canSelectFiles: true,
+        canSelectFolders: false,
+        title: title,
+      })
+      .then((fileUri) => {
+        if (fileUri && fileUri[0]) {
+          return fileUri[0].fsPath
+        }
+
+        return ''
+      })
+  }
+
+  return file
+}
+
 // Function for setting up the commands for Run and Debug file
 function createDebugRunFileConfigs(
   resource: vscode.Uri,
@@ -113,49 +150,30 @@
       }
     ),
     vscode.commands.registerCommand('toggle.experimental', async (_) => {
-      const action = await vscode.window.showQuickPick(['Yes', 'No'], {
-        title: 'Enable Experimental Features?',
-        canPickMany: false,
-      })
-
       vscode.commands.executeCommand(
         'setContext',
         'experimentalFeaturesEnabled',
-        action === 'Yes' ? true : false
+        true
       )
 
-      if (action === 'Yes') {
-        omegaEditClient.activate(context)
+      omegaEditClient.activate(context)
 
-        vscode.window.showInformationMessage(
-          'DFDL: Experimental Features Enabled!'
-        )
-      }
+      vscode.window.showInformationMessage(
+        'DFDL: Experimental Features Enabled!'
+      )
     })
   )
 
   context.subscriptions.push(
     vscode.commands.registerCommand(
       'extension.dfdl-debug.getProgramName',
-      async (_) => {
+      async (fileRequested = null) => {
         // Open native file explorer to allow user to select data file from anywhere on their machine
-        let programFile = await vscode.window
-          .showOpenDialog({
-            canSelectMany: false,
-            openLabel: 'Select DFDL schema to debug',
-            canSelectFiles: true,
-            canSelectFolders: false,
-            title: 'Select DFDL schema to debug',
-          })
-          .then((fileUri) => {
-            if (fileUri && fileUri[0]) {
-              return fileUri[0].fsPath
-            }
-
-            return ''
-          })
-
-        return programFile
+        return await getFile(
+          fileRequested,
+          'Select DFDL schema to debug',
+          'Select DFDL schema to debug'
+        )
       }
     )
   )
@@ -163,23 +181,13 @@
   context.subscriptions.push(
     vscode.commands.registerCommand(
       'extension.dfdl-debug.getDataName',
-      async (_) => {
+      async (fileRequested = null) => {
         // Open native file explorer to allow user to select data file from anywhere on their machine
-        return await vscode.window
-          .showOpenDialog({
-            canSelectMany: false,
-            openLabel: 'Select input data file to debug',
-            canSelectFiles: true,
-            canSelectFolders: false,
-            title: 'Select input data file to debug',
-          })
-          .then((fileUri) => {
-            if (fileUri && fileUri[0]) {
-              return fileUri[0].fsPath
-            }
-
-            return ''
-          })
+        return await getFile(
+          fileRequested,
+          'Select input data file to debug',
+          'Select input data file to debug'
+        )
       }
     )
   )
diff --git a/src/daffodilDebugger.ts b/src/daffodilDebugger.ts
index 69abe21..9f6e6fa 100644
--- a/src/daffodilDebugger.ts
+++ b/src/daffodilDebugger.ts
@@ -17,14 +17,13 @@
 
 import * as vscode from 'vscode'
 import * as fs from 'fs'
-import * as unzip from 'unzip-stream'
 import * as os from 'os'
 import * as child_process from 'child_process'
 import { deactivate } from './adapter/extension'
 import { LIB_VERSION } from './version'
 import XDGAppPaths from 'xdg-app-paths'
 import * as path from 'path'
-import { regexp } from './utils'
+import { regexp, unzipFile, runScript } from './utils'
 import { getDaffodilVersion } from './daffodil'
 import { Artifact } from './classes/artifact'
 
@@ -87,8 +86,6 @@
 
   // If useExistingServer var set to false make sure version of debugger entered is downloaded then ran
   if (!config.useExistingServer) {
-    const delay = (ms: number) => new Promise((res) => setTimeout(res, ms))
-
     if (vscode.workspace.workspaceFolders !== undefined) {
       let rootPath = xdgAppPaths.data()
 
@@ -120,18 +117,7 @@
         }
 
         // Unzip file
-        await new Promise((res, rej) => {
-          let stream = fs
-            .createReadStream(filePath)
-            .pipe(unzip.Extract({ path: `${rootPath}` }))
-          stream.on('close', () => {
-            try {
-              res(filePath)
-            } catch (err) {
-              rej(err)
-            }
-          })
-        })
+        await unzipFile(filePath, rootPath)
       }
 
       // Stop debugger if running
@@ -145,11 +131,6 @@
         child_process.exec(
           "kill -9 $(ps -ef | grep 'daffodil' | grep 'jar' | awk '{ print $2 }') || return 0"
         ) // ensure debugger server not running and
-        child_process.execSync(
-          `chmod +x ${rootPath.replace(regexp['space'], '\\ ')}/${
-            artifact.name
-          }/bin/${artifact.scriptName}`
-        ) // make sure debugger is executable
       }
 
       // Get program file before debugger starts to avoid timeout
@@ -184,14 +165,18 @@
         : vscode.Uri.parse('').fsPath
 
       // Get daffodilDebugger class paths to be added to the debugger
-      let daffodilDebugClasspath = config.daffodilDebugClasspath.includes(
-        '${workspaceFolder}'
-      )
-        ? config.daffodilDebugClasspath.replace(
-            regexp['workspace'],
-            workspaceFolder
-          )
-        : config.daffodilDebugClasspath
+      let daffodilDebugClasspath = ''
+
+      if (config.daffodilDebugClassPath) {
+        daffodilDebugClasspath = config.daffodilDebugClasspath.includes(
+          '${workspaceFolder}'
+        )
+          ? config.daffodilDebugClasspath.replace(
+              regexp['workspace'],
+              workspaceFolder
+            )
+          : config.daffodilDebugClasspath
+      }
 
       // Start debugger in terminal based on scriptName
 
@@ -206,20 +191,16 @@
       let shellArgs =
         os.platform() === 'win32' ? [] : ['--login', '-c', artifact.scriptName]
 
-      let terminal = vscode.window.createTerminal({
-        name: artifact.scriptName,
-        cwd: `${rootPath}/daffodil-debugger-${daffodilVersion}-${LIB_VERSION}/bin/`,
-        hideFromUser: false,
-        shellPath: shellPath,
-        shellArgs: shellArgs,
-        env: {
+      await runScript(
+        `${rootPath}/daffodil-debugger-${daffodilVersion}-${LIB_VERSION}`,
+        artifact,
+        shellPath,
+        shellArgs,
+        {
           DAFFODIL_DEBUG_CLASSPATH: daffodilDebugClasspath,
         },
-      })
-      terminal.show()
-
-      // Wait for 5000 ms to make sure debugger is running before the extension tries to connect to it
-      await delay(5000)
+        'daffodil'
+      )
     }
   }
 
diff --git a/src/language/providers/attributeCompletion.ts b/src/language/providers/attributeCompletion.ts
index ef283aa..bbf60ea 100644
--- a/src/language/providers/attributeCompletion.ts
+++ b/src/language/providers/attributeCompletion.ts
@@ -28,38 +28,22 @@
 } from './utils'
 
 import { attributeCompletion } from './intellisense/attributeItems'
+import { getCommonItems, createCompletionItem } from './utils'
 
 function getCompletionItems(
   itemsToUse: string[],
   preVal: string = '',
   additionalItems: string = ''
 ) {
-  let compItems: vscode.CompletionItem[] = []
-  let noPreVals: string[] = [
-    'dfdl:choiceBranchKey=',
-    'dfdl:representation',
-    'dfdl:choiceDispatchKey=',
-    'dfdl:simpleType',
-    'xs:restriction',
-  ]
+  let compItems: vscode.CompletionItem[] = getCommonItems(
+    itemsToUse,
+    preVal,
+    additionalItems
+  )
 
   attributeCompletion(additionalItems).items.forEach((e) => {
     if (itemsToUse.includes(e.item)) {
-      const completionItem = new vscode.CompletionItem(e.item)
-
-      if (preVal !== '' && !noPreVals.includes(e.item)) {
-        completionItem.insertText = new vscode.SnippetString(
-          preVal + e.snippetString
-        )
-      } else {
-        completionItem.insertText = new vscode.SnippetString(e.snippetString)
-      }
-
-      if (e.markdownString) {
-        completionItem.documentation = new vscode.MarkdownString(
-          e.markdownString
-        )
-      }
+      const completionItem = createCompletionItem(e, preVal)
       compItems.push(completionItem)
     }
   })
@@ -200,16 +184,6 @@
 
             var xmlItems = [
               {
-                item: 'type=',
-                snippetString:
-                  preVal +
-                  'type="${1|xs:string,xs:decimal,xs:float,xs:double,xs:integer,xs:nonNegativeInteger,xs:int,xs:unsignedInt,xs:short,xs:unsignedShort,xs:long,xs:unsignedLong,xs:byte,xs:unsignedByte,xs:hexBinary,xs:boolean' +
-                  additionalItems +
-                  '|}"$0',
-                markdownString:
-                  'attribute to specify a simple type element type',
-              },
-              {
                 item: 'external=',
                 snippetString: preVal + 'external="${1|true,false|}"$0',
               },
@@ -227,14 +201,13 @@
                   e.snippetString
                 )
 
-                if (e.markdownString) {
-                  completionItem.documentation = new vscode.MarkdownString(
-                    e.markdownString
-                  )
-                }
                 compItems.push(completionItem)
               })
 
+              getCommonItems(['type='], '', additionalItems).forEach((ci) => {
+                compItems.push(ci)
+              })
+
               return compItems
             }
           }
diff --git a/src/language/providers/elementCompletion.ts b/src/language/providers/elementCompletion.ts
index bb8335c..4d06297 100644
--- a/src/language/providers/elementCompletion.ts
+++ b/src/language/providers/elementCompletion.ts
@@ -18,6 +18,7 @@
 import * as vscode from 'vscode'
 import { checkBraceOpen } from './utils'
 import { elementCompletion } from './intellisense/elementItems'
+import { createCompletionItem } from './utils'
 
 export function getElementCompletionProvider(dfdlFormatString: string) {
   return vscode.languages.registerCompletionItemProvider('dfdl', {
@@ -40,14 +41,7 @@
 
       elementCompletion(definedVariables, dfdlFormatString).items.forEach(
         (e) => {
-          const completionItem = new vscode.CompletionItem(e.item)
-          completionItem.insertText = new vscode.SnippetString(e.snippetString)
-
-          if (e.markdownString) {
-            completionItem.documentation = new vscode.MarkdownString(
-              e.markdownString
-            )
-          }
+          const completionItem = createCompletionItem(e, '')
           compItems.push(completionItem)
         }
       )
diff --git a/src/language/providers/intellisense/attributeItems.ts b/src/language/providers/intellisense/attributeItems.ts
index 82a4209..63be28c 100644
--- a/src/language/providers/intellisense/attributeItems.ts
+++ b/src/language/providers/intellisense/attributeItems.ts
@@ -30,11 +30,6 @@
         markdownString: 'dfdl escape character definition',
       },
       {
-        item: 'type=',
-        snippetString: 'type="${1|xs:string,xs:decimal,xs:float,xs:double,xs:integer,xs:nonNegativeInteger,xs:int,xs:unsignedInt,xs:short,xs:unsignedShort,xs:long,xs:unsignedLong,xs:byte,xs:unsignedByte,xs:hexBinary,xs:boolean' + additionalItems + '|}"$0',
-        markdownString: 'attribute to specify a simple type element type',
-      },
-      {
         item: 'minOccurs=',
         snippetString: 'minOccurs="${1|0,1|}"$0',
         markdownString: 'mininum number of times element will occur',
diff --git a/src/language/providers/intellisense/commonItems.ts b/src/language/providers/intellisense/commonItems.ts
new file mode 100644
index 0000000..cf2cd78
--- /dev/null
+++ b/src/language/providers/intellisense/commonItems.ts
@@ -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.
+ */
+
+// prettier-ignore
+export const commonCompletion = (additionalItems) => {
+  return {
+    items: [
+      {
+        item: 'type=',
+        snippetString: 'type="${1|xs:string,xs:decimal,xs:float,xs:double,xs:integer,xs:nonNegativeInteger,xs:int,xs:unsignedInt,xs:short,xs:unsignedShort,xs:long,xs:unsignedLong,xs:byte,xs:unsignedByte,xs:hexBinary,xs:boolean' + additionalItems + '|}"$0',
+        markdownString: 'an attribute which specifies the type of a simply-typed element',
+      },
+    ],
+  }
+}
diff --git a/src/language/providers/utils.ts b/src/language/providers/utils.ts
index 6674f17..19979aa 100644
--- a/src/language/providers/utils.ts
+++ b/src/language/providers/utils.ts
@@ -330,3 +330,61 @@
   }
   return false
 }
+
+import { commonCompletion } from './intellisense/commonItems'
+
+export const noPreVals: string[] = [
+  'dfdl:choiceBranchKey=',
+  'dfdl:representation',
+  'dfdl:choiceDispatchKey=',
+  'dfdl:simpleType',
+  'xs:restriction',
+]
+
+export function createCompletionItem(
+  e:
+    | {
+        item: string
+        snippetString: string
+        markdownString: string
+      }
+    | {
+        item: string
+        snippetString: string
+        markdownString?: undefined
+      },
+  preVal: string
+) {
+  const completionItem = new vscode.CompletionItem(e.item)
+
+  if (preVal !== '' && !noPreVals.includes(e.item)) {
+    completionItem.insertText = new vscode.SnippetString(
+      preVal + e.snippetString
+    )
+  } else {
+    completionItem.insertText = new vscode.SnippetString(e.snippetString)
+  }
+
+  if (e.markdownString) {
+    completionItem.documentation = new vscode.MarkdownString(e.markdownString)
+  }
+
+  return completionItem
+}
+
+export function getCommonItems(
+  itemsToUse: string[],
+  preVal: string = '',
+  additionalItems: string = ''
+) {
+  let compItems: vscode.CompletionItem[] = []
+
+  commonCompletion(additionalItems).items.forEach((e) => {
+    if (itemsToUse.includes(e.item)) {
+      const completionItem = createCompletionItem(e, preVal)
+      compItems.push(completionItem)
+    }
+  })
+
+  return compItems
+}
diff --git a/src/omega_edit/client.ts b/src/omega_edit/client.ts
index 50d5fc0..42725e5 100644
--- a/src/omega_edit/client.ts
+++ b/src/omega_edit/client.ts
@@ -20,9 +20,10 @@
 import * as omegaEditSession from 'omega-edit/session'
 import * as omegaEditViewport from 'omega-edit/viewport'
 import * as omegaEditVersion from 'omega-edit/version'
-import { startServer, stopServer } from './server'
+import { getServer, stopServer } from './server'
 import { viewportSubscribe } from './utils'
 import { OmegaEdit } from './omega_edit'
+import { v4 as uuidv4 } from 'uuid'
 
 let serverRunning = false
 
@@ -37,6 +38,9 @@
   sessionId: string,
   viewportIds: Array<string>
 ) {
+  viewportIds.forEach(async (vid) => {
+    await omegaEditViewport.destroyViewport(vid)
+  })
   await omegaEditSession.destroySession(sessionId)
 }
 
@@ -46,119 +50,145 @@
   )
 
   ctx.subscriptions.push(
-    vscode.commands.registerCommand('omega_edit.version', async () => {
-      if (!serverRunning) {
-        await startServer(ctx, omegaEditPackageVersion)
-        serverRunning = true
+    vscode.commands.registerCommand(
+      'omega_edit.version',
+      async (startServer: boolean = true) => {
+        if (!serverRunning && startServer) {
+          await getServer(ctx, omegaEditPackageVersion)
+          serverRunning = true
+        }
+
+        return await omegaEditVersion.getVersion()
       }
-      let v = await omegaEditVersion.getVersion()
-      vscode.window.showInformationMessage(v)
-    })
+    )
   )
 
   ctx.subscriptions.push(
-    vscode.commands.registerCommand('data.edit', async () => {
-      if (!serverRunning) {
-        await startServer(ctx, omegaEditPackageVersion)
-        serverRunning = true
+    vscode.commands.registerCommand(
+      'data.edit',
+      async (
+        filePassed: string = '',
+        startServer: boolean = true,
+        subscribeToViewports: boolean = true
+      ) => {
+        if (!serverRunning && startServer) {
+          await getServer(ctx, omegaEditPackageVersion)
+          serverRunning = true
+        }
+
+        return await createOmegaEditWebviewPanel(
+          ctx,
+          filePassed,
+          subscribeToViewports
+        )
+      }
+    )
+  )
+}
+
+async function createOmegaEditWebviewPanel(
+  ctx: vscode.ExtensionContext,
+  filePassed: string,
+  subscribeToViewports: boolean
+) {
+  let panel = vscode.window.createWebviewPanel(
+    'viewport',
+    'Data Editor',
+    vscode.ViewColumn.One,
+    {
+      enableScripts: true,
+    }
+  )
+
+  let fileToEdit =
+    filePassed !== ''
+      ? filePassed
+      : await vscode.window
+          .showOpenDialog({
+            canSelectMany: false,
+            openLabel: 'Select',
+            canSelectFiles: true,
+            canSelectFolders: false,
+          })
+          .then((fileUri) => {
+            if (fileUri && fileUri[0]) {
+              return fileUri[0].fsPath
+            }
+          })
+
+  panel.webview.html = getWebviewContent(ctx)
+
+  let s = await omegaEditSession.createSession(fileToEdit, uuidv4())
+  panel.webview.postMessage({
+    command: 'setSessionFile',
+    filePath: fileToEdit,
+  })
+
+  let vpAll = await omegaEditViewport.createViewport('', s, 0, 1000, false)
+  let vp1 = await omegaEditViewport.createViewport('', s, 0, 64, false)
+  let vp2 = await omegaEditViewport.createViewport('', s, 64, 64, false)
+  let vp3 = await omegaEditViewport.createViewport('', s, 128, 64, false)
+
+  // This break CI so option was added to skip it during CI
+  if (subscribeToViewports) {
+    await viewportSubscribe(panel, vpAll, vpAll, 'vpAll', 'hexAll')
+    await viewportSubscribe(panel, vpAll, vp1, 'viewport1', null)
+    await viewportSubscribe(panel, vpAll, vp2, 'viewport2', null)
+    await viewportSubscribe(panel, vpAll, vp3, 'viewport3', null)
+  }
+
+  panel.webview.onDidReceiveMessage(
+    async (message) => {
+      if (message.command === 'printChangeCount') {
+        vscode.window.showInformationMessage(message.changeCount)
+        return
       }
 
-      let panel = vscode.window.createWebviewPanel(
-        'viewport',
-        'Data Editor',
-        vscode.ViewColumn.One,
-        {
-          enableScripts: true,
-        }
-      )
-
-      let fileToEdit = await vscode.window
-        .showOpenDialog({
-          canSelectMany: false,
-          openLabel: 'Select',
-          canSelectFiles: true,
-          canSelectFolders: false,
-        })
-        .then((fileUri) => {
-          if (fileUri && fileUri[0]) {
-            return fileUri[0].fsPath
-          }
-        })
-
-      panel.webview.html = getWebviewContent(ctx)
-
-      let s = await omegaEditSession.createSession(fileToEdit, '')
-      panel.webview.postMessage({
-        command: 'setSessionFile',
-        filePath: fileToEdit,
-      })
-
-      let fileSize = await omegaEditSession.getComputedFileSize(s)
-
-      let vpAll = await omegaEditViewport.createViewport(
-        '',
+      var omegaEdit = new OmegaEdit(
         s,
-        0,
+        message.offset,
+        message.data,
+        message.len,
+        panel
+      )
+
+      var fileSize = await omegaEditSession.getComputedFileSize(s)
+      var searchPattern = message.searchPattern ? message.searchPattern : ''
+
+      // If the search pattern exceeds the length of the file, matches are
+      // not possible.  Ωedit (as implemented currently) considers
+      // patterns that are longer than the length of the file to be an
+      // error (it will return a null pointer instead of an empty list).
+      if (searchPattern !== '' && fileSize < searchPattern.length) {
+        throw new Error("Search pattern can't be larger than file")
+      }
+
+      omegaEdit.execute(
+        message.command,
+        message.sessionFile ? message.sessionFile : '',
+        message.overwrite ? message.overwrite : false,
+        message.newFile ? message.newFile : false,
         fileSize,
-        false
+        searchPattern,
+        message.replaceText ? message.replaceText : '',
+        message.caseInsensitive ? message.caseInsensitive : false
       )
-
-      let vp1 = await omegaEditViewport.createViewport('', s, 0, 64, false)
-      let vp2 = await omegaEditViewport.createViewport('', s, 64, 64, false)
-      let vp3 = await omegaEditViewport.createViewport('', s, 128, 64, false)
-
-      await viewportSubscribe(panel, vpAll, vpAll, 'vpAll', 'hexAll')
-      await viewportSubscribe(panel, vpAll, vp1, 'viewport1', null)
-      await viewportSubscribe(panel, vpAll, vp2, 'viewport2', null)
-      await viewportSubscribe(panel, vpAll, vp3, 'viewport3', null)
-
-      panel.webview.onDidReceiveMessage(
-        async (message) => {
-          var omegaEdit = new OmegaEdit(
-            s,
-            message.offset,
-            message.data,
-            message.len,
-            panel
-          )
-
-          var fileSize = await omegaEditSession.getComputedFileSize(s)
-          var searchPattern = message.searchPattern ? message.searchPattern : ''
-
-          // If the search pattern exceeds the length of the file, matches are
-          // not possible.  Ωedit (as implemented currently) considers
-          // patterns that are longer than the length of the file to be an
-          // error (it will return a null pointer instead of an empty list).
-          if (searchPattern !== '' && fileSize < searchPattern.length) {
-            throw new Error("Search pattern can't be larger than file")
-          }
-
-          omegaEdit.execute(
-            message.command,
-            message.sessionFile ? message.sessionFile : '',
-            message.overwrite ? message.overwrite : false,
-            message.newFile ? message.newFile : false,
-            fileSize,
-            searchPattern,
-            message.replaceText ? message.replaceText : '',
-            message.caseInsensitive ? message.caseInsensitive : false
-          )
-        },
-        undefined,
-        ctx.subscriptions
-      )
-
-      panel.onDidDispose(
-        async () => {
-          await cleanupViewportSession(s, [vpAll, vp1, vp2, vp3])
-          panel.dispose()
-          serverRunning = !(await stopServer())
-        },
-        undefined,
-        ctx.subscriptions
-      )
-    })
+    },
+    undefined,
+    ctx.subscriptions
   )
+
+  panel.onDidDispose(
+    async () => {
+      await cleanupViewportSession(s, [vpAll, vp1, vp2, vp3])
+      panel.dispose()
+      serverRunning = !(await stopServer())
+    },
+    undefined,
+    ctx.subscriptions
+  )
+
+  return panel
 }
 
 function getWebviewContent(ctx: vscode.ExtensionContext) {
diff --git a/src/omega_edit/server.ts b/src/omega_edit/server.ts
index 43842e5..a2ea73e 100644
--- a/src/omega_edit/server.ts
+++ b/src/omega_edit/server.ts
@@ -17,16 +17,14 @@
 
 import * as vscode from 'vscode'
 import * as fs from 'fs'
-import * as unzip from 'unzip-stream'
-import * as child_process from 'child_process'
 import * as path from 'path'
-import * as os from 'os'
 import { Artifact } from '../classes/artifact'
 import XDGAppPaths from 'xdg-app-paths'
+import { runScript, unzipFile, killProcess } from '../utils'
 
 const xdgAppPaths = XDGAppPaths({ name: 'omega_edit' })
 
-export async function startServer(
+export async function getServer(
   ctx: vscode.ExtensionContext,
   omegaEditVersion: string
 ) {
@@ -36,7 +34,6 @@
     omegaEditVersion,
     'omega-edit-grpc-server'
   )
-  const delay = (ms: number) => new Promise((res) => setTimeout(res, ms))
 
   if (vscode.workspace.workspaceFolders) {
     let rootPath = xdgAppPaths.data()
@@ -54,67 +51,35 @@
       )
 
       // Unzip file and remove zip
-      await new Promise((resolve, reject) => {
-        let stream = fs
-          .createReadStream(filePath)
-          .pipe(unzip.Extract({ path: `${rootPath}` }))
-        stream.on('close', () => {
-          try {
-            resolve(filePath)
-          } catch (err) {
-            reject(err)
-          }
-        })
-      })
-      fs.unlinkSync(filePath)
+      await unzipFile(filePath, rootPath)
     }
 
-    let scriptPath = artifact.name
-
-    if (!os.platform().toLowerCase().startsWith('win')) {
-      child_process.execSync(
-        `chmod +x ${rootPath.replace(
-          ' ',
-          '\\ '
-        )}/${scriptPath}/bin/${artifact.scriptName.replace('./', '')}`
-      )
-    }
-
-    // Start server in terminal based on scriptName
-    let terminal = vscode.window.createTerminal({
-      name: artifact.scriptName,
-      cwd: `${rootPath}/${scriptPath}/bin`,
-      hideFromUser: false,
-      shellPath: artifact.scriptName,
-    })
-    terminal.show()
-
-    // Wait for 5000ms to make sure server is running before client tries to connect
-    await delay(5000)
+    await runScript(
+      `${rootPath}/omega-edit-scala-server-${omegaEditVersion}`,
+      artifact
+    )
   }
 }
 
 // Function for stopping debugging
-export async function stopServer() {
-  const action = await vscode.window.showInformationMessage(
-    'Stop Ωedit server?',
-    'Yes',
-    'No'
-  )
-
-  if (action === 'Yes') {
-    vscode.window.activeTerminal?.processId.then((id) => {
-      if (id) {
-        if (os.platform() === 'win32') {
-          child_process.exec(`taskkill /F /PID ${id}`)
-        } else {
-          child_process.exec(`kill -9 ${id}`)
-        }
-      }
-    })
-
+export async function stopServer(terminal: vscode.Terminal | null = null) {
+  if (terminal !== null) {
+    terminal.processId.then(async (id) => await killProcess(id))
     return true
-  }
+  } else {
+    const action = await vscode.window.showInformationMessage(
+      'Stop Ωedit server?',
+      'Yes',
+      'No'
+    )
 
-  return false
+    if (action === 'Yes') {
+      vscode.window.activeTerminal?.processId.then(
+        async (id) => await killProcess(id)
+      )
+      return true
+    }
+
+    return false
+  }
 }
diff --git a/src/tests/daffodil.test.ts b/src/tests/daffodil.test.ts
deleted file mode 100644
index a6a7e9a..0000000
--- a/src/tests/daffodil.test.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * 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.
- */
-
-import * as assert from 'assert'
-import * as daffodil from '../daffodil'
-import * as fs from 'fs'
-import * as path from 'path'
-import { before, after } from 'mocha'
-
-suite('Daffodfil', () => {
-  const PROJECT_ROOT = path.join(__dirname, '../../')
-  const packageFile = path.join(PROJECT_ROOT, 'package-test.json')
-
-  // Create test package.json before anything else happens
-  before(() => {
-    fs.writeFileSync(packageFile, JSON.stringify({ daffodilVersion: '0.0.0' }))
-  })
-
-  // Delete test package.json after all tests are done
-  after(() => {
-    fs.unlinkSync(packageFile)
-  })
-
-  // suite to test all functions work properly
-  suite('interfaces', () => {
-    test('DaffodilData functions properly', () => {
-      let daffodilData: daffodil.DaffodilData = {
-        bytePos1b: 100,
-      }
-
-      assert.strictEqual(100, daffodilData.bytePos1b)
-    })
-
-    test('InfosetEvent functions properly', () => {
-      let infosetEvent: daffodil.InfosetEvent = {
-        content: 'This is content',
-        mimeType: 'xml',
-      }
-
-      assert.strictEqual('This is content', infosetEvent.content)
-      assert.strictEqual('xml', infosetEvent.mimeType)
-    })
-
-    test('InfosetOutput functions properly', () => {
-      let infosetOutput: daffodil.InfosetOutput = {
-        type: 'console',
-      }
-
-      assert.strictEqual('console', infosetOutput.type)
-    })
-
-    test('BuildInfo functions properly', () => {
-      let allVersions = '1.0.0'
-      let buildInfo: daffodil.BuildInfo = {
-        version: allVersions,
-        daffodilVersion: allVersions,
-        scalaVersion: allVersions,
-      }
-
-      assert.strictEqual(allVersions, buildInfo.version)
-      assert.strictEqual(allVersions, buildInfo.daffodilVersion)
-      assert.strictEqual(allVersions, buildInfo.scalaVersion)
-    })
-
-    test('LaunchArgs functions properly', () => {
-      let infosetOutput: daffodil.InfosetOutput = {
-        type: 'console',
-      }
-
-      let launchArgs: daffodil.LaunchArgs = {
-        schemaPath: '/path/to/schema.xsd.xml',
-        dataPath: '/path/to/data.jpg',
-        stopOnEntry: true,
-        infosetOutput: infosetOutput,
-      }
-
-      assert.strictEqual('/path/to/schema.xsd.xml', launchArgs.schemaPath)
-      assert.strictEqual('/path/to/data.jpg', launchArgs.dataPath)
-      assert.strictEqual(true, launchArgs.stopOnEntry)
-      assert.strictEqual(infosetOutput, launchArgs.infosetOutput)
-    })
-
-    test('ConfigEvent functions properly', () => {
-      let allVersions = '1.0.0'
-      let infosetOutput: daffodil.InfosetOutput = {
-        type: 'console',
-      }
-      let buildInfo: daffodil.BuildInfo = {
-        version: allVersions,
-        daffodilVersion: allVersions,
-        scalaVersion: allVersions,
-      }
-      let launchArgs: daffodil.LaunchArgs = {
-        schemaPath: '/path/to/schema.xsd.xml',
-        dataPath: '/path/to/data.jpg',
-        stopOnEntry: true,
-        infosetOutput: infosetOutput,
-      }
-
-      let configEvent: daffodil.ConfigEvent = {
-        buildInfo: buildInfo,
-        launchArgs: launchArgs,
-      }
-
-      assert.strictEqual(buildInfo, configEvent.buildInfo)
-      assert.strictEqual(launchArgs, configEvent.launchArgs)
-    })
-  })
-
-  // suite to test all constants get set properly
-  suite('constants', () => {
-    test('dataEvent set properly', () => {
-      assert.strictEqual(daffodil.dataEvent, 'daffodil.data')
-    })
-
-    test('infosetEvent set properly', () => {
-      assert.strictEqual(daffodil.infosetEvent, 'daffodil.infoset')
-    })
-
-    test('configEvent set properly', () => {
-      assert.strictEqual(daffodil.configEvent, 'daffodil.config')
-    })
-  })
-
-  suite('getDaffodilVersion', () => {
-    test('getDaffodilVersion returns same version as file', () => {
-      var daffodilVersion = daffodil.getDaffodilVersion(packageFile)
-      assert.strictEqual(daffodilVersion, '0.0.0')
-    })
-  })
-})
diff --git a/src/tests/runTest.ts b/src/tests/runTest.ts
new file mode 100644
index 0000000..d018ab3
--- /dev/null
+++ b/src/tests/runTest.ts
@@ -0,0 +1,63 @@
+/*
+ * 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 ran here are ones that require the vscode API
+import * as path from 'path'
+import * as cp from 'child_process'
+import {
+  runTests,
+  resolveCliArgsFromVSCodeExecutablePath,
+  downloadAndUnzipVSCode,
+} from '@vscode/test-electron'
+
+async function main() {
+  try {
+    // The folder containing the Extension Manifest package.json
+    // Passed to `--extensionDevelopmentPath`
+    const extensionDevelopmentPath = path.resolve(__dirname, '../../../')
+
+    // The path to the extension test script
+    // Passed to --extensionTestsPath
+    const extensionTestsPath = path.resolve(__dirname, './suite/index')
+
+    const vscodeExecutablePath = await downloadAndUnzipVSCode('1.68.0')
+    const [cli, ...args] =
+      resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath)
+
+    // Install required extensions
+    cp.spawnSync(
+      cli,
+      [...args, '--install-extension', 'vincaslt.highlight-matching-tag'],
+      {
+        encoding: 'utf-8',
+        stdio: 'inherit',
+      }
+    )
+
+    // Download VS Code, unzip it and run the integration test
+    await runTests({
+      vscodeExecutablePath,
+      extensionDevelopmentPath,
+      extensionTestsPath,
+    })
+  } catch (err) {
+    console.error('Failed to run tests')
+    process.exit(1)
+  }
+}
+
+main()
diff --git a/src/tests/adapter.test.ts b/src/tests/suite/adapter.test.ts
similarity index 94%
rename from src/tests/adapter.test.ts
rename to src/tests/suite/adapter.test.ts
index aba081e..792f48c 100644
--- a/src/tests/adapter.test.ts
+++ b/src/tests/suite/adapter.test.ts
@@ -20,8 +20,11 @@
 import { DebugClient } from 'vscode-debugadapter-testsupport'
 
 suite('Daffodil Debug Adapter', () => {
-  const DEBUG_ADAPTER = './out/adapter/debugAdapter.js'
-  const PROJECT_ROOT = path.join(__dirname, '../../')
+  const DEBUG_ADAPTER = path.join(
+    __dirname,
+    '../../../out/adapter/debugAdapter.js'
+  )
+  const PROJECT_ROOT = path.join(__dirname, '../../../')
   const DATA_ROOT = path.join(PROJECT_ROOT, 'src/tests/data/')
 
   let client: DebugClient
diff --git a/src/tests/suite/daffodil.test.ts b/src/tests/suite/daffodil.test.ts
new file mode 100644
index 0000000..ec34609
--- /dev/null
+++ b/src/tests/suite/daffodil.test.ts
@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+
+import * as vscode from 'vscode'
+import * as assert from 'assert'
+import * as daffodil from '../../daffodil'
+import * as fs from 'fs'
+import * as path from 'path'
+import * as os from 'os'
+import { Artifact } from '../../classes/artifact'
+import { LIB_VERSION } from '../../version'
+import { before, after } from 'mocha'
+
+suite('Daffodfil', () => {
+  const PROJECT_ROOT = path.join(__dirname, '../../../')
+  const packageFile = path.join(PROJECT_ROOT, 'package-test.json')
+  const testDfdlFile = path.join(
+    __dirname,
+    '../../../src/tests/data/test.dfdl.xsd'
+  )
+
+  // Create test package.json before anything else happens
+  before(() => {
+    fs.writeFileSync(packageFile, JSON.stringify({ daffodilVersion: '0.0.0' }))
+  })
+
+  // Delete test package.json after all tests are done
+  after(() => {
+    fs.unlinkSync(packageFile)
+  })
+
+  // suite to test all functions work properly
+  suite('interfaces', () => {
+    test('DaffodilData functions properly', () => {
+      let daffodilData: daffodil.DaffodilData = {
+        bytePos1b: 100,
+      }
+
+      assert.strictEqual(100, daffodilData.bytePos1b)
+    })
+
+    test('InfosetEvent functions properly', () => {
+      let infosetEvent: daffodil.InfosetEvent = {
+        content: 'This is content',
+        mimeType: 'xml',
+      }
+
+      assert.strictEqual('This is content', infosetEvent.content)
+      assert.strictEqual('xml', infosetEvent.mimeType)
+    })
+
+    test('InfosetOutput functions properly', () => {
+      let infosetOutput: daffodil.InfosetOutput = {
+        type: 'console',
+      }
+
+      assert.strictEqual('console', infosetOutput.type)
+    })
+
+    test('BuildInfo functions properly', () => {
+      let allVersions = '1.0.0'
+      let buildInfo: daffodil.BuildInfo = {
+        version: allVersions,
+        daffodilVersion: allVersions,
+        scalaVersion: allVersions,
+      }
+
+      assert.strictEqual(allVersions, buildInfo.version)
+      assert.strictEqual(allVersions, buildInfo.daffodilVersion)
+      assert.strictEqual(allVersions, buildInfo.scalaVersion)
+    })
+
+    test('LaunchArgs functions properly', () => {
+      let infosetOutput: daffodil.InfosetOutput = {
+        type: 'console',
+      }
+
+      let launchArgs: daffodil.LaunchArgs = {
+        schemaPath: '/path/to/schema.xsd.xml',
+        dataPath: '/path/to/data.jpg',
+        stopOnEntry: true,
+        infosetOutput: infosetOutput,
+      }
+
+      assert.strictEqual('/path/to/schema.xsd.xml', launchArgs.schemaPath)
+      assert.strictEqual('/path/to/data.jpg', launchArgs.dataPath)
+      assert.strictEqual(true, launchArgs.stopOnEntry)
+      assert.strictEqual(infosetOutput, launchArgs.infosetOutput)
+    })
+
+    test('ConfigEvent functions properly', () => {
+      let allVersions = '1.0.0'
+      let infosetOutput: daffodil.InfosetOutput = {
+        type: 'console',
+      }
+      let buildInfo: daffodil.BuildInfo = {
+        version: allVersions,
+        daffodilVersion: allVersions,
+        scalaVersion: allVersions,
+      }
+      let launchArgs: daffodil.LaunchArgs = {
+        schemaPath: '/path/to/schema.xsd.xml',
+        dataPath: '/path/to/data.jpg',
+        stopOnEntry: true,
+        infosetOutput: infosetOutput,
+      }
+
+      let configEvent: daffodil.ConfigEvent = {
+        buildInfo: buildInfo,
+        launchArgs: launchArgs,
+      }
+
+      assert.strictEqual(buildInfo, configEvent.buildInfo)
+      assert.strictEqual(launchArgs, configEvent.launchArgs)
+    })
+  })
+
+  // suite to test all constants get set properly
+  suite('constants', () => {
+    test('dataEvent set properly', () => {
+      assert.strictEqual(daffodil.dataEvent, 'daffodil.data')
+    })
+
+    test('infosetEvent set properly', () => {
+      assert.strictEqual(daffodil.infosetEvent, 'daffodil.infoset')
+    })
+
+    test('configEvent set properly', () => {
+      assert.strictEqual(daffodil.configEvent, 'daffodil.config')
+    })
+  })
+
+  suite('getDaffodilVersion', () => {
+    test('getDaffodilVersion returns same version as file', () => {
+      var daffodilVersion = daffodil.getDaffodilVersion(packageFile)
+      assert.strictEqual(daffodilVersion, '0.0.0')
+    })
+  })
+
+  suite('non-debug specifc commands', () => {
+    const nonDebugSpecificCmds = [
+      'extension.dfdl-debug.debugEditorContents',
+      'extension.dfdl-debug.runEditorContents',
+      'launch.config',
+    ]
+
+    // This breaks when the omega-edit tests run for some reason
+    // test('Available by default', () => {
+    //   nonDebugSpecificCmds.forEach(async (cmd) => {
+    //     assert.strictEqual(
+    //       (await vscode.commands.getCommands()).includes(cmd),
+    //       true
+    //     )
+    //   })
+    // })
+
+    test('Not available when inDebugMode', () => {
+      vscode.commands.executeCommand('setContext', 'inDebugMode', true)
+
+      nonDebugSpecificCmds.forEach(async (cmd) => {
+        assert.strictEqual(
+          (await vscode.commands.getCommands()).includes(cmd),
+          false
+        )
+      })
+    })
+  })
+
+  suite('debug specifc commands', () => {
+    const debugSpecificCmds = [
+      'extension.dfdl-debug.toggleFormatting',
+      'hexview.display',
+      'infoset.display',
+      'infoset.diff',
+      'infoset.save',
+    ]
+
+    test('Not available by default', () => {
+      debugSpecificCmds.forEach(async (cmd) => {
+        assert.strictEqual(
+          (await vscode.commands.getCommands()).includes(cmd),
+          false
+        )
+      })
+    })
+
+    // This breaks when the omega-edit tests run for some reason
+    // test('Available when inDebugMode', () => {
+    //   vscode.commands.executeCommand('setContext', 'inDebugMode', true)
+
+    //   debugSpecificCmds.forEach(async (cmd) => {
+    //     assert.strictEqual(
+    //       (await vscode.commands.getCommands()).includes(cmd),
+    //       true
+    //     )
+    //   })
+    // })
+  })
+
+  suite('getCommands', () => {
+    test('getProgramName file exists', async () => {
+      assert.strictEqual(
+        await vscode.commands.executeCommand(
+          'extension.dfdl-debug.getProgramName',
+          testDfdlFile
+        ),
+        testDfdlFile
+      )
+    })
+
+    test('getProgramName file does not exists', async () => {
+      let file = path.join(__dirname, '../data/test.dfdl.xsd')
+
+      assert.notStrictEqual(
+        await vscode.commands.executeCommand(
+          'extension.dfdl-debug.getProgramName',
+          file
+        ),
+        file
+      )
+    })
+
+    test('getDataName file exists', async () => {
+      assert.strictEqual(
+        await vscode.commands.executeCommand(
+          'extension.dfdl-debug.getDataName',
+          testDfdlFile
+        ),
+        testDfdlFile
+      )
+    })
+
+    test('getDataName file does not exists', async () => {
+      let file = path.join(__dirname, '../data/test.dfdl.xsd')
+
+      assert.notStrictEqual(
+        await vscode.commands.executeCommand(
+          'extension.dfdl-debug.getDataName',
+          file
+        ),
+        file
+      )
+    })
+  })
+
+  suite('artifact attributes', () => {
+    const packageName = 'daffodil-debugger'
+    const packageVersion = '1.0.0'
+    const scriptName = 'daffodil-debugger'
+    const artifact = new Artifact(packageName, packageVersion, scriptName)
+
+    test('name set properly', () => {
+      assert.strictEqual(
+        artifact.name,
+        `${packageName}-${packageVersion}-${LIB_VERSION}`
+      )
+    })
+
+    test('archive set properly', () => {
+      assert.strictEqual(
+        artifact.archive,
+        `${packageName}-${packageVersion}-${LIB_VERSION}.zip`
+      )
+    })
+
+    test('scriptName set properly', () => {
+      assert.strictEqual(
+        artifact.scriptName,
+        os.platform() === 'win32' ? `${scriptName}.bat` : `./${scriptName}`
+      )
+    })
+  })
+})
diff --git a/src/tests/suite/index.ts b/src/tests/suite/index.ts
new file mode 100644
index 0000000..94efb89
--- /dev/null
+++ b/src/tests/suite/index.ts
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+import * as path from 'path'
+const Mocha = require('mocha')
+const glob = require('glob')
+
+export function run(): Promise<void> {
+  // Create the mocha test
+  const mocha = new Mocha({
+    ui: 'tdd',
+    color: true,
+    timeout: 999999,
+  })
+
+  const testsRoot = path.resolve(__dirname, '..')
+
+  return new Promise((c, e) => {
+    glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
+      if (err) {
+        return e(err)
+      }
+
+      // Add files to the test suite
+      files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f)))
+
+      try {
+        mocha.run((failures) => {
+          if (failures > 0) {
+            e(new Error(`${failures} tests failed.`))
+          } else {
+            c()
+          }
+        })
+      } catch (err) {
+        console.error(err)
+        e(err)
+      }
+    })
+  })
+}
diff --git a/src/tests/suite/language/activated.test.ts b/src/tests/suite/language/activated.test.ts
new file mode 100644
index 0000000..cf5b373
--- /dev/null
+++ b/src/tests/suite/language/activated.test.ts
@@ -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.
+ */
+
+import * as vscode from 'vscode'
+import * as assert from 'assert'
+
+suite('DFDL Language Test Suite', () => {
+  test('Test DFDL language configured', async () => {
+    assert.strictEqual(
+      (await vscode.languages.getLanguages()).includes('dfdl'),
+      true
+    )
+  })
+})
diff --git a/src/tests/suite/language/items.test.ts b/src/tests/suite/language/items.test.ts
new file mode 100644
index 0000000..5198439
--- /dev/null
+++ b/src/tests/suite/language/items.test.ts
@@ -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.
+ */
+
+import * as assert from 'assert'
+import { attributeCompletion } from '../../../language/providers/intellisense/attributeItems'
+import { commonCompletion } from '../../../language/providers/intellisense/commonItems'
+import { elementCompletion } from '../../../language/providers/intellisense/elementItems'
+
+suite('Items Test Suite', () => {
+  const expectedElementItems = [
+    'xml version',
+    'xs:schema',
+    'xs:element name',
+    'xs:element ref',
+    'xs:group name',
+    'xs:group ref',
+    'dfdl:assert',
+    'dfdL:discriminator',
+    'dfdl:hiddenGroupRef',
+    'dfdl:format',
+    'xs:annotation',
+    'xs:appinfo',
+    'xs:complexType',
+    'xs:complexType name=',
+    'xs:simpleType',
+    'xs:simpleType name=',
+    'xs:sequence',
+    'xs:choice',
+    'dfdl:defineVariable',
+    'dfdl:setVariable',
+  ]
+  const expectedAttributeItems = [
+    'dfdl:defineFormat',
+    'dfdl:defineEscapeScheme',
+    'type=',
+    'minOccurs=',
+    'maxOccurs=',
+    'dfdl:occursCount=',
+    'dfdl:byteOrder=',
+    'dfdl:occursCountKind=',
+    'dfdl:length=',
+    'dfdl:lengthKind=',
+    'dfdl:encoding=',
+    'dfdl:alignment=',
+    'dfdl:lengthUnits=',
+    'dfdl:lengthPattern=',
+    'dfdl:inputValueCalc=',
+    'dfdl:outputValueCalc=',
+    'dfdl:alignmentUnits=',
+    'dfdl:terminator=',
+    'dfdl:outputNewLine=',
+    'dfdl:choiceBranchKey=',
+    'dfdl:representation',
+    'dfdl:hiddenGroupRef=',
+    'dfdl:sequenceKind=',
+    'dfdl:separator=',
+    'dfdl:separatorPosition=',
+    'dfdl:separatorSuppressionPolicy',
+    'dfdl:choiceLengthKind=',
+    'dfdl:choiceLength=',
+    'dfdl:intiatedContent=',
+    'dfdl:choiceDispatchKey=',
+    'dfdl:simpleType',
+    'xs:restriction',
+  ]
+
+  test('all commonItems available', async () => {
+    var itemNames: string[] = []
+    commonCompletion('').items.forEach((r) => itemNames.push(r.item))
+    assert.strictEqual(itemNames.includes('type='), true)
+  })
+
+  test('all elementItems available', async () => {
+    elementCompletion('', '').items.forEach((item) => {
+      assert.strictEqual(expectedElementItems.includes(item.item), true)
+    })
+  })
+
+  test('all attributeItems available', async () => {
+    attributeCompletion('').items.forEach((item) => {
+      assert.strictEqual(expectedAttributeItems.includes(item.item), true)
+    })
+  })
+})
diff --git a/src/tests/suite/omegaEdit.test.ts b/src/tests/suite/omegaEdit.test.ts
new file mode 100644
index 0000000..5e3c335
--- /dev/null
+++ b/src/tests/suite/omegaEdit.test.ts
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ */
+
+import * as vscode from 'vscode'
+import * as assert from 'assert'
+import * as path from 'path'
+import * as os from 'os'
+import { Artifact, Backend } from '../../classes/artifact'
+import * as omegaEditClient from '../../omega_edit/client'
+import { unzipFile, runScript, killProcess } from '../../utils'
+import { before, after } from 'mocha'
+
+const wait_port = require('wait-port')
+const omegaEditPackagePath = path.join(__dirname, '../../../src/omega_edit')
+const localArtifact = new Artifact(
+  'omega-edit-scala-server',
+  omegaEditClient.getOmegaEditPackageVersion(
+    path.join(__dirname, '../../../package.json')
+  ),
+  'omega-edit-grpc-server'
+)
+const testDfdlFile = path.join(
+  __dirname,
+  '../../../src/tests/data/test.dfdl.xsd'
+)
+
+export async function runServerForTests() {
+  const extractedFolder = `${omegaEditPackagePath}/${localArtifact.name}`
+
+  await unzipFile(
+    `${omegaEditPackagePath}/${localArtifact.name}.zip`,
+    omegaEditPackagePath
+  )
+
+  return await runScript(`${extractedFolder}`, localArtifact)
+}
+
+suite('omega-edit Test Suite', () => {
+  let terminal: vscode.Terminal
+
+  before(async () => {
+    terminal = await runServerForTests()
+  })
+
+  after(async () => {
+    await terminal.processId.then(async (id) => await killProcess(id))
+  })
+
+  test('Test toggle.experimental', async () => {
+    // omega-edit related commands should be hidden
+    assert.strictEqual(
+      (await vscode.commands.getCommands()).includes('omega_edit.version'),
+      false
+    )
+    assert.strictEqual(
+      (await vscode.commands.getCommands()).includes('data.edit'),
+      false
+    )
+
+    // Toggle experimental features to be enabled
+    await vscode.commands.executeCommand('toggle.experimental', true)
+
+    // omega-edit related commands should not longer be hidden
+    assert.strictEqual(
+      (await vscode.commands.getCommands()).includes('omega_edit.version'),
+      true
+    )
+    assert.strictEqual(
+      (await vscode.commands.getCommands()).includes('data.edit'),
+      true
+    )
+  })
+
+  suite('artifact attributes', () => {
+    const packageName = 'omega-edit-scala-server'
+    const packageVersion = '1.0.0'
+    const scriptName = 'omega-edit-grpc-server'
+    const artifact = new Artifact(packageName, packageVersion, scriptName)
+    const backend = new Backend('ctc-oss', 'omega-edit')
+
+    test('name set properly', () => {
+      assert.strictEqual(artifact.name, `${packageName}-${packageVersion}`)
+    })
+
+    test('archive set properly', () => {
+      assert.strictEqual(
+        artifact.archive,
+        `${packageName}-${packageVersion}.zip`
+      )
+    })
+
+    test('scriptName set properly', () => {
+      assert.strictEqual(
+        artifact.scriptName,
+        os.platform() === 'win32' ? `${scriptName}.bat` : `./${scriptName}`
+      )
+    })
+
+    test('archiveUrl set properly', () => {
+      const url = artifact.archiveUrl(backend)
+
+      assert.strictEqual(url.includes('ctc-oss'), true)
+      assert.strictEqual(url.includes('omega-edit'), true)
+      assert.strictEqual(url.includes(`v${packageVersion}`), true)
+      assert.strictEqual(
+        url.includes(`${packageName}-${packageVersion}.zip`),
+        true
+      )
+    })
+  })
+
+  test('running omega-edit server', async () => {
+    assert.strictEqual(
+      await wait_port({ host: '127.0.0.1', port: 9000, output: 'silent' }),
+      true
+    )
+  })
+
+  suite('omega-edit commands', () => {
+    test('omega_edit.version returns correct version', async () => {
+      let version = await vscode.commands.executeCommand(
+        'omega_edit.version',
+        false
+      )
+
+      assert.strictEqual(
+        version,
+        'v' +
+          omegaEditClient.getOmegaEditPackageVersion(
+            path.join(__dirname, '../../../package.json')
+          )
+      )
+    })
+
+    test('data editor opens', async () => {
+      const panel: vscode.WebviewPanel = await vscode.commands.executeCommand(
+        'data.edit',
+        testDfdlFile,
+        false,
+        false
+      )
+
+      assert.strictEqual(panel.active, true)
+    })
+  })
+})
diff --git a/src/tests/suite/utils.test.ts b/src/tests/suite/utils.test.ts
new file mode 100644
index 0000000..fa590a0
--- /dev/null
+++ b/src/tests/suite/utils.test.ts
@@ -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.
+ */
+
+import * as assert from 'assert'
+import * as utils from '../../utils'
+
+suite('Utils Test Suite', () => {
+  var name = 'Default Config'
+  var request = 'launch'
+  var type = 'dfdl'
+
+  var defaultConfig = {
+    name: 'Default Config',
+    request: 'launch',
+    type: 'dfdl',
+    program: '${command:AskForProgramName}',
+    data: '${command:AskForDataName}',
+    debugServer: 4711,
+    infosetOutput: {
+      type: 'none',
+      path: '${workspaceFolder}/infoset.xml',
+    },
+    stopOnEntry: true,
+    useExistingServer: false,
+    trace: true,
+    openHexView: false,
+    openInfosetView: false,
+    openInfosetDiffView: false,
+    daffodilDebugClasspath: '',
+  }
+
+  test('Default config', async () => {
+    var config = await utils.getConfig(name, request, type)
+    assert.strictEqual(JSON.stringify(defaultConfig), JSON.stringify(config))
+  })
+
+  test('Get current config', async () => {
+    assert.strictEqual(undefined, utils.getCurrentConfig())
+  })
+
+  test('Setting current config', async () => {
+    // Check current config not set
+    assert.strictEqual(undefined, utils.getCurrentConfig())
+    utils.setCurrentConfig(defaultConfig)
+    // Check current config is now set
+    assert.notStrictEqual(undefined, utils.getCurrentConfig())
+    assert.strictEqual(
+      JSON.stringify(defaultConfig),
+      JSON.stringify(utils.getCurrentConfig())
+    )
+  })
+})
diff --git a/src/tests/version.test.ts b/src/tests/suite/version.test.ts
similarity index 96%
rename from src/tests/version.test.ts
rename to src/tests/suite/version.test.ts
index a2001ac..0e306fc 100644
--- a/src/tests/version.test.ts
+++ b/src/tests/suite/version.test.ts
@@ -20,7 +20,7 @@
 import * as path from 'path'
 
 suite('Daffodil Version', () => {
-  const PROJECT_ROOT = path.join(__dirname, '../../')
+  const PROJECT_ROOT = path.join(__dirname, '../../../')
   const versionFile = path.join(PROJECT_ROOT, 'src/version.ts')
   const packageMapped = JSON.parse(
     fs.readFileSync(path.join(PROJECT_ROOT, 'package.json')).toString()
diff --git a/src/utils.ts b/src/utils.ts
index 4b34a68..59b1a9e 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -16,6 +16,12 @@
  */
 
 import * as vscode from 'vscode'
+import * as fs from 'fs'
+import * as unzip from 'unzip-stream'
+import { Artifact } from './classes/artifact'
+import * as os from 'os'
+import * as child_process from 'child_process'
+const wait_port = require('wait-port')
 
 const defaultConf = vscode.workspace.getConfiguration()
 // const
@@ -78,8 +84,8 @@
   request,
   type,
   program: string = '',
-  data = false,
-  debugServer = false,
+  data: string | boolean = false,
+  debugServer: number | boolean = false,
   infosetOutput: object | null = null,
   stopOnEntry = false,
   useExistingServer = false,
@@ -130,3 +136,90 @@
       : defaultConf.get('daffodilDebugClasspath', ''),
   }
 }
+
+export async function unzipFile(zipFilePath: string, extractPath: string) {
+  return await new Promise((resolve, reject) => {
+    let stream = fs
+      .createReadStream(zipFilePath)
+      .pipe(unzip.Extract({ path: `${extractPath}` }))
+    stream.on('close', () => {
+      try {
+        resolve(zipFilePath)
+      } catch (err) {
+        reject(err)
+      }
+    })
+  })
+}
+
+export async function executeScript(
+  name: string,
+  cwd: string,
+  shellPath: string,
+  shellArgs: string[] = []
+) {
+  // Start server in terminal based on scriptName
+  let terminal = vscode.window.createTerminal({
+    name: name,
+    cwd: cwd,
+    hideFromUser: false,
+    shellPath: shellPath,
+    shellArgs: shellArgs,
+  })
+  terminal.show()
+
+  return terminal
+}
+
+export async function killProcess(id: number | undefined) {
+  if (id) {
+    if (os.platform() === 'win32') {
+      child_process.exec(`taskkill /F /PID ${id}`)
+    } else {
+      child_process.exec(`kill -9 ${id} 2>&1 || echo 0`)
+    }
+  }
+}
+
+export async function runScript(
+  scriptPath: string,
+  artifact: Artifact,
+  shellPath: string | null = null,
+  shellArgs: string[] = [],
+  env:
+    | {
+        [key: string]: string | null | undefined
+      }
+    | undefined = undefined,
+  type: string = '',
+  hideTerminal: boolean = false
+) {
+  const delay = (ms: number) => new Promise((res) => setTimeout(res, ms))
+
+  if (!os.platform().toLowerCase().startsWith('win')) {
+    child_process.execSync(
+      `chmod +x ${scriptPath.replace(
+        ' ',
+        '\\ '
+      )}/bin/${artifact.scriptName.replace('./', '')}`
+    )
+  }
+
+  // Start server in terminal based on scriptName
+  let terminal = vscode.window.createTerminal({
+    name: artifact.scriptName,
+    cwd: `${scriptPath}/bin`,
+    hideFromUser: false,
+    shellPath: shellPath !== null ? shellPath : artifact.scriptName,
+    shellArgs: shellArgs,
+    env: env,
+  })
+
+  if (!hideTerminal) terminal.show()
+
+  type.includes('daffodil')
+    ? await delay(5000).then(() => {})
+    : await wait_port({ host: '127.0.0.1', port: 9000, output: 'silent' })
+
+  return terminal
+}
diff --git a/yarn.lock b/yarn.lock
index a7e7cfd..e2767ef 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8,22 +8,22 @@
   integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
 
 "@grpc/grpc-js@^1.5.4":
-  version "1.6.7"
-  resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.6.7.tgz#4c4fa998ff719fe859ac19fe977fdef097bb99aa"
-  integrity sha512-eBM03pu9hd3VqDQG+kHahiG1x80RGkkqqRb1Pchcwqej/KkAH95gAvKs6laqaHCycYaPK+TKuNQnOz9UXYA8qw==
+  version "1.7.1"
+  resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.7.1.tgz#cfac092e61eac6fe0f80d22943f98e1ba45f02a2"
+  integrity sha512-GVtMU4oh/TeKkWGzXUEsyZtyvSUIT1z49RtGH1UnEGeL+sLuxKl8QH3KZTlSB329R1sWJmesm5hQ5CxXdYH9dg==
   dependencies:
-    "@grpc/proto-loader" "^0.6.4"
+    "@grpc/proto-loader" "^0.7.0"
     "@types/node" ">=12.12.47"
 
-"@grpc/proto-loader@^0.6.4":
-  version "0.6.13"
-  resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.6.13.tgz#008f989b72a40c60c96cd4088522f09b05ac66bc"
-  integrity sha512-FjxPYDRTn6Ec3V0arm1FtSpmP6V50wuph2yILpyvTKzjc76oDdoihXqM1DzOW5ubvCC8GivfCnNtfaRE8myJ7g==
+"@grpc/proto-loader@^0.7.0":
+  version "0.7.2"
+  resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.2.tgz#fa63178853afe1473c50cff89fe572f7c8b20154"
+  integrity sha512-jCdyLIT/tdQ1zhrbTQnJNK5nbDf0GoBpy5jVNywBzzMDF+Vs6uEaHnfz46dMtDxkvwrF2hzk5Z67goliceH0sA==
   dependencies:
     "@types/long" "^4.0.1"
     lodash.camelcase "^4.3.0"
     long "^4.0.0"
-    protobufjs "^6.11.3"
+    protobufjs "^7.0.0"
     yargs "^16.2.0"
 
 "@jridgewell/gen-mapping@^0.3.0":
@@ -58,10 +58,10 @@
   resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
   integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
 
-"@jridgewell/trace-mapping@^0.3.7", "@jridgewell/trace-mapping@^0.3.9":
-  version "0.3.14"
-  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
-  integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==
+"@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9":
+  version "0.3.15"
+  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774"
+  integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==
   dependencies:
     "@jridgewell/resolve-uri" "^3.0.3"
     "@jridgewell/sourcemap-codec" "^1.4.10"
@@ -119,6 +119,11 @@
   resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
   integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
 
+"@tootallnate/once@1":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
+  integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
+
 "@types/eslint-scope@^3.7.3":
   version "3.7.4"
   resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16"
@@ -128,17 +133,17 @@
     "@types/estree" "*"
 
 "@types/eslint@*":
-  version "8.4.5"
-  resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.5.tgz#acdfb7dd36b91cc5d812d7c093811a8f3d9b31e4"
-  integrity sha512-dhsC09y1gpJWnK+Ff4SGvCuSnk9DaU0BJZSzOwa6GVSg65XtTugLBITDAAzRU5duGBoXBHpdR/9jHGxJjNflJQ==
+  version "8.4.6"
+  resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.6.tgz#7976f054c1bccfcf514bff0564c0c41df5c08207"
+  integrity sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==
   dependencies:
     "@types/estree" "*"
     "@types/json-schema" "*"
 
 "@types/estree@*":
-  version "0.0.52"
-  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.52.tgz#7f1f57ad5b741f3d5b210d3b1f145640d89bf8fe"
-  integrity sha512-BZWrtCU0bMVAIliIV+HJO1f1PR41M7NKjfxrFJwwhKI1KwhwOxYw1SXg9ao+CIMt774nFuGiG6eU+udtbEI9oQ==
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
+  integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
 
 "@types/estree@^0.0.51":
   version "0.0.51"
@@ -164,35 +169,40 @@
   integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
 
 "@types/minimatch@*":
-  version "3.0.5"
-  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
-  integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca"
+  integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
 
 "@types/mocha@^9.1.1":
   version "9.1.1"
   resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4"
   integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==
 
-"@types/moo@^0.5.5":
-  version "0.5.5"
-  resolved "https://registry.yarnpkg.com/@types/moo/-/moo-0.5.5.tgz#83220b7349c59fd4bb1bc14b1d4ea0041899dc15"
-  integrity sha512-eXQpwnkI4Ntw5uJg6i2PINdRFWLr55dqjuYQaLHNjvqTzF14QdNWbCbml9sza0byyXNA0hZlHtcdN+VNDcgVHA==
-
 "@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@^18.0.0":
-  version "18.0.3"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.3.tgz#463fc47f13ec0688a33aec75d078a0541a447199"
-  integrity sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==
+  version "18.7.18"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.18.tgz#633184f55c322e4fb08612307c274ee6d5ed3154"
+  integrity sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==
 
 "@types/vscode@^1.55.0":
-  version "1.68.1"
-  resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.68.1.tgz#a9e5b33f825f715cae80593cb6d5d6d4cabbe998"
-  integrity sha512-fXlaq13NT5yHh6yZ3c+UxXloTSk34mIvsNFYyQCeO5Po2BLFAwz7EZT4kQ43B64/aPcnAenyWy3QasrTofBOnQ==
+  version "1.71.0"
+  resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.71.0.tgz#a8d9bb7aca49b0455060e6eb978711b510bdd2e2"
+  integrity sha512-nB50bBC9H/x2CpwW9FzRRRDrTZ7G0/POttJojvN/LiVfzTGfLyQIje1L1QRMdFXK9G41k5UJN/1B9S4of7CSzA==
 
 "@ungap/promise-all-settled@1.1.2":
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
   integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
 
+"@vscode/test-electron@^2.1.5":
+  version "2.1.5"
+  resolved "https://registry.yarnpkg.com/@vscode/test-electron/-/test-electron-2.1.5.tgz#ac98f8f445ea4590753f5fa0c7f6e4298f08c3b7"
+  integrity sha512-O/ioqFpV+RvKbRykX2ItYPnbcZ4Hk5V0rY4uhQjQTLhGL9WZUvS7exzuYQCCI+ilSqJpctvxq2llTfGXf9UnnA==
+  dependencies:
+    http-proxy-agent "^4.0.1"
+    https-proxy-agent "^5.0.0"
+    rimraf "^3.0.2"
+    unzipper "^0.10.11"
+
 "@webassemblyjs/ast@1.11.1":
   version "1.11.1"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7"
@@ -347,9 +357,16 @@
   integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==
 
 acorn@^8.4.1, acorn@^8.5.0:
-  version "8.7.1"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
-  integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
+  version "8.8.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
+  integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
+
+agent-base@6:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
+  integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
+  dependencies:
+    debug "4"
 
 ajv-keywords@^3.5.2:
   version "3.5.2"
@@ -409,9 +426,9 @@
   integrity sha512-eT6XN2ycPKvuiffzUNmU0dnGmmLw+TexMW7UKOyf5utdVrWx14PR2acRIfy6ZfFWRAv8twt1X74VUgd9RnDmfQ==
 
 azure-devops-node-api@^11.0.1:
-  version "11.1.1"
-  resolved "https://registry.yarnpkg.com/azure-devops-node-api/-/azure-devops-node-api-11.1.1.tgz#dd1356031fa4e334e016732594e8fee0f68268c4"
-  integrity sha512-XDG91XzLZ15reP12s3jFkKS8oiagSICjnLwxEYieme4+4h3ZveFOFRA4iYIG40RyHXsiI0mefFYYMFIJbMpWcg==
+  version "11.2.0"
+  resolved "https://registry.yarnpkg.com/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz#bf04edbef60313117a0507415eed4790a420ad6b"
+  integrity sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==
   dependencies:
     tunnel "0.0.6"
     typed-rest-client "^1.8.4"
@@ -426,6 +443,11 @@
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
   integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
 
+big-integer@^1.6.17:
+  version "1.6.51"
+  resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686"
+  integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==
+
 big.js@^5.2.2:
   version "5.2.2"
   resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
@@ -436,7 +458,7 @@
   resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
   integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
 
-binary@^0.3.0:
+binary@^0.3.0, binary@~0.3.0:
   version "0.3.0"
   resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79"
   integrity sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==
@@ -453,6 +475,11 @@
     inherits "^2.0.4"
     readable-stream "^3.4.0"
 
+bluebird@~3.4.1:
+  version "3.4.7"
+  resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3"
+  integrity sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==
+
 boolbase@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
@@ -486,14 +513,14 @@
   integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==
 
 browserslist@^4.14.5:
-  version "4.21.1"
-  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.1.tgz#c9b9b0a54c7607e8dc3e01a0d311727188011a00"
-  integrity sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==
+  version "4.21.4"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987"
+  integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==
   dependencies:
-    caniuse-lite "^1.0.30001359"
-    electron-to-chromium "^1.4.172"
-    node-releases "^2.0.5"
-    update-browserslist-db "^1.0.4"
+    caniuse-lite "^1.0.30001400"
+    electron-to-chromium "^1.4.251"
+    node-releases "^2.0.6"
+    update-browserslist-db "^1.0.9"
 
 buffer-crc32@~0.2.3:
   version "0.2.13"
@@ -505,6 +532,11 @@
   resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
   integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
 
+buffer-indexof-polyfill@~1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz#d2732135c5999c64b277fcf9b1abe3498254729c"
+  integrity sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==
+
 buffer@^5.5.0:
   version "5.7.1"
   resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
@@ -531,10 +563,10 @@
   resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
   integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
 
-caniuse-lite@^1.0.30001359:
-  version "1.0.30001363"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001363.tgz#26bec2d606924ba318235944e1193304ea7c4f15"
-  integrity sha512-HpQhpzTGGPVMnCjIomjt+jvyUu8vNFo3TaDiZ/RcoTrlOq/5+tC8zHdsbgFB6MxmaY+jCpsH09aD80Bb4Ow3Sg==
+caniuse-lite@^1.0.30001400:
+  version "1.0.30001407"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001407.tgz#92281a6ee67cb90bfd8a6a1201fcc2dc19b60a15"
+  integrity sha512-4ydV+t4P7X3zH83fQWNDX/mQEzYomossfpViCOx9zHBSMV+rIe3LFqglHHtVyvNl1FhTNxPxs3jei82iqOW04w==
 
 chainsaw@~0.1.0:
   version "0.1.0"
@@ -552,7 +584,7 @@
     escape-string-regexp "^1.0.5"
     supports-color "^5.3.0"
 
-chalk@^4.1.0:
+chalk@^4.1.0, chalk@^4.1.2:
   version "4.1.2"
   resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
   integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@@ -677,6 +709,11 @@
   resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
   integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
 
+commander@^9.3.0:
+  version "9.4.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.0.tgz#bc4a40918fefe52e22450c111ecd6b7acce6f11c"
+  integrity sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==
+
 concat-map@0.0.1:
   version "0.0.1"
   resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -712,7 +749,7 @@
   resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
   integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
 
-debug@4.3.4:
+debug@4, debug@4.3.4, debug@^4.3.4:
   version "4.3.4"
   resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
   integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@@ -776,10 +813,17 @@
     domelementtype "^2.3.0"
     domhandler "^5.0.1"
 
-electron-to-chromium@^1.4.172:
-  version "1.4.180"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.180.tgz#380b06037836055d12c7de181ee90b8ed911c3e7"
-  integrity sha512-7at5ash3FD9U5gPa3/wPr6OdiZd/zBjvDZaaHBpcqFOFUhZiWnb7stkqk8xUFL9H9nk7Yok5vCCNK8wyC/+f8A==
+duplexer2@~0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
+  integrity sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==
+  dependencies:
+    readable-stream "^2.0.2"
+
+electron-to-chromium@^1.4.251:
+  version "1.4.256"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz#c735032f412505e8e0482f147a8ff10cfca45bf4"
+  integrity sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw==
 
 emoji-regex@^8.0.0:
   version "8.0.0"
@@ -815,10 +859,10 @@
     graceful-fs "^4.2.4"
     tapable "^2.2.0"
 
-entities@^4.2.0, entities@^4.3.0:
-  version "4.3.1"
-  resolved "https://registry.yarnpkg.com/entities/-/entities-4.3.1.tgz#c34062a94c865c322f9d67b4384e4169bcede6a4"
-  integrity sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==
+entities@^4.2.0, entities@^4.3.0, entities@^4.4.0:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174"
+  integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==
 
 entities@~2.1.0:
   version "2.1.0"
@@ -903,9 +947,9 @@
   integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
 
 fastest-levenshtein@^1.0.12:
-  version "1.0.12"
-  resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2"
-  integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==
+  version "1.0.16"
+  resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5"
+  integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==
 
 fd-slicer@~1.1.0:
   version "1.1.0"
@@ -957,6 +1001,16 @@
   resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
   integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
 
+fstream@^1.0.12:
+  version "1.0.12"
+  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
+  integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
+  dependencies:
+    graceful-fs "^4.1.2"
+    inherits "~2.0.0"
+    mkdirp ">=0.5 0"
+    rimraf "2"
+
 function-bind@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
@@ -968,9 +1022,9 @@
   integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
 
 get-intrinsic@^1.0.2:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598"
-  integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385"
+  integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==
   dependencies:
     function-bind "^1.1.1"
     has "^1.0.3"
@@ -1033,7 +1087,7 @@
   resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.20.1.tgz#1b255c2b59bcda7c399df46c65206aa3c7a0ce8b"
   integrity sha512-XMf1+O32FjYIV3CYu6Tuh5PNbfNEU5Xu22X+Xkdb/DUexFlCzhvv7d5Iirm4AOwn8lv4al1YvIhzGrg2j9Zfzw==
 
-graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
+graceful-fs@^4.1.2, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
   version "4.2.10"
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
   integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
@@ -1087,6 +1141,23 @@
     domutils "^3.0.1"
     entities "^4.3.0"
 
+http-proxy-agent@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a"
+  integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==
+  dependencies:
+    "@tootallnate/once" "1"
+    agent-base "6"
+    debug "4"
+
+https-proxy-agent@^5.0.0:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
+  integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
+  dependencies:
+    agent-base "6"
+    debug "4"
+
 ieee754@^1.1.13:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
@@ -1108,7 +1179,7 @@
     once "^1.3.0"
     wrappy "1"
 
-inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
+inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3:
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
   integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -1131,9 +1202,9 @@
     binary-extensions "^2.0.0"
 
 is-core-module@^2.9.0:
-  version "2.9.0"
-  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69"
-  integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==
+  version "2.10.0"
+  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed"
+  integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==
   dependencies:
     has "^1.0.3"
 
@@ -1247,6 +1318,11 @@
   dependencies:
     uc.micro "^1.0.1"
 
+listenercount@~1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937"
+  integrity sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==
+
 loader-runner@^4.2.0:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
@@ -1293,6 +1369,11 @@
   resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
   integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
 
+long@^5.0.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/long/-/long-5.2.0.tgz#2696dadf4b4da2ce3f6f6b89186085d94d52fd61"
+  integrity sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w==
+
 lru-cache@^6.0.0:
   version "6.0.0"
   resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
@@ -1390,7 +1471,7 @@
   resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
   integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
 
-mkdirp@^0.5.1:
+"mkdirp@>=0.5 0", mkdirp@^0.5.1:
   version "0.5.6"
   resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
   integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
@@ -1430,11 +1511,6 @@
     yargs-parser "20.2.4"
     yargs-unparser "2.0.0"
 
-moo@0.5.1:
-  version "0.5.1"
-  resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4"
-  integrity sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==
-
 ms@2.1.2:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
@@ -1466,9 +1542,9 @@
   integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
 
 node-abi@^3.3.0:
-  version "3.22.0"
-  resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.22.0.tgz#00b8250e86a0816576258227edbce7bbe0039362"
-  integrity sha512-u4uAs/4Zzmp/jjsD9cyFYDXeISfUWaAVWshPmDZOFOv4Xl4SbzTXm53I04C2uRueYJ+0t5PEtLH/owbn2Npf/w==
+  version "3.24.0"
+  resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.24.0.tgz#b9d03393a49f2c7e147d0c99f180e680c27c1599"
+  integrity sha512-YPG3Co0luSu6GwOBsmIdGW6Wx0NyNDLg/hriIyDllVsNwnI6UeqaWShxC3lbH4LtEQUgoLP3XR1ndXiDAWvmRw==
   dependencies:
     semver "^7.3.5"
 
@@ -1477,10 +1553,10 @@
   resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f"
   integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==
 
-node-releases@^2.0.5:
-  version "2.0.5"
-  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666"
-  integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==
+node-releases@^2.0.6:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
+  integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
 
 normalize-path@^3.0.0, normalize-path@~3.0.0:
   version "3.0.0"
@@ -1568,11 +1644,11 @@
     parse5 "^7.0.0"
 
 parse5@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.0.0.tgz#51f74a5257f5fcc536389e8c2d0b3802e1bfa91a"
-  integrity sha512-y/t8IXSPWTuRZqXc0ajH/UwDj4mnqLEbSttNbThcFhGrZuOyoyvNBO85PBp2jQa55wY9d07PBNjsK8ZP3K5U6g==
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.1.tgz#4649f940ccfb95d8754f37f73078ea20afe0c746"
+  integrity sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==
   dependencies:
-    entities "^4.3.0"
+    entities "^4.4.0"
 
 path-exists@^4.0.0:
   version "4.0.0"
@@ -1644,10 +1720,10 @@
   resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
   integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
 
-protobufjs@^6.11.3:
-  version "6.11.3"
-  resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.3.tgz#637a527205a35caa4f3e2a9a4a13ddffe0e7af74"
-  integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==
+protobufjs@^7.0.0:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.1.1.tgz#0117befb4b0f5a49d028e93f2ca62c3c1f5e7c65"
+  integrity sha512-d0nMQqS/aT3lfV8bKi9Gbg73vPd2LcDdTDOu6RE/M+h9DY8g1EmDzk3ADPccthEWfTBjkR2oxNdx9Gs8YubT+g==
   dependencies:
     "@protobufjs/aspromise" "^1.1.2"
     "@protobufjs/base64" "^1.1.2"
@@ -1659,9 +1735,8 @@
     "@protobufjs/path" "^1.1.2"
     "@protobufjs/pool" "^1.1.0"
     "@protobufjs/utf8" "^1.1.0"
-    "@types/long" "^4.0.1"
     "@types/node" ">=13.7.0"
-    long "^4.0.0"
+    long "^5.0.0"
 
 prr@~1.0.1:
   version "1.0.1"
@@ -1712,7 +1787,7 @@
   dependencies:
     mute-stream "~0.0.4"
 
-readable-stream@^2.0.1:
+readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@~2.3.6:
   version "2.3.7"
   resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
   integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
@@ -1774,7 +1849,14 @@
     path-parse "^1.0.7"
     supports-preserve-symlinks-flag "^1.0.0"
 
-rimraf@^3.0.0:
+rimraf@2:
+  version "2.7.1"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
+  integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
+  dependencies:
+    glob "^7.1.3"
+
+rimraf@^3.0.0, rimraf@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
   integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
@@ -1829,6 +1911,11 @@
   dependencies:
     randombytes "^2.1.0"
 
+setimmediate@~1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+  integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
+
 shallow-clone@^3.0.0:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
@@ -1982,20 +2069,20 @@
     readable-stream "^3.1.1"
 
 terser-webpack-plugin@^5.1.3:
-  version "5.3.3"
-  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz#8033db876dd5875487213e87c627bca323e5ed90"
-  integrity sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==
+  version "5.3.6"
+  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz#5590aec31aa3c6f771ce1b1acca60639eab3195c"
+  integrity sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==
   dependencies:
-    "@jridgewell/trace-mapping" "^0.3.7"
+    "@jridgewell/trace-mapping" "^0.3.14"
     jest-worker "^27.4.5"
     schema-utils "^3.1.1"
     serialize-javascript "^6.0.0"
-    terser "^5.7.2"
+    terser "^5.14.1"
 
-terser@^5.7.2:
-  version "5.14.1"
-  resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.1.tgz#7c95eec36436cb11cf1902cc79ac564741d19eca"
-  integrity sha512-+ahUAE+iheqBTDxXhTisdA8hgvbEG1hHOQ9xmNjeUJSoi6DU/gMrKNcfZjHkyY6Alnuyc+ikYJaxxfHkT3+WuQ==
+terser@^5.14.1:
+  version "5.15.0"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.0.tgz#e16967894eeba6e1091509ec83f0c60e179f2425"
+  integrity sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==
   dependencies:
     "@jridgewell/source-map" "^0.3.2"
     acorn "^8.5.0"
@@ -2076,10 +2163,26 @@
     binary "^0.3.0"
     mkdirp "^0.5.1"
 
-update-browserslist-db@^1.0.4:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz#dbfc5a789caa26b1db8990796c2c8ebbce304824"
-  integrity sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==
+unzipper@^0.10.11:
+  version "0.10.11"
+  resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.11.tgz#0b4991446472cbdb92ee7403909f26c2419c782e"
+  integrity sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==
+  dependencies:
+    big-integer "^1.6.17"
+    binary "~0.3.0"
+    bluebird "~3.4.1"
+    buffer-indexof-polyfill "~1.0.0"
+    duplexer2 "~0.1.4"
+    fstream "^1.0.12"
+    graceful-fs "^4.2.2"
+    listenercount "~1.0.1"
+    readable-stream "~2.3.6"
+    setimmediate "~1.0.4"
+
+update-browserslist-db@^1.0.9:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz#2924d3927367a38d5c555413a7ce138fc95fcb18"
+  integrity sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==
   dependencies:
     escalade "^3.1.1"
     picocolors "^1.0.0"
@@ -2101,6 +2204,11 @@
   resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
   integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
 
+uuid@^8.3.2:
+  version "8.3.2"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
+  integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
+
 vsce@2.9.2:
   version "2.9.2"
   resolved "https://registry.yarnpkg.com/vsce/-/vsce-2.9.2.tgz#be5d2ca5899f31ba84225d6b19ea1376589df897"
@@ -2147,6 +2255,15 @@
   resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.51.0.tgz#c03168dac778b6c24ce17b3511cb61e89c11b2df"
   integrity sha512-dzKWTMMyebIMPF1VYMuuQj7gGFq7guR8AFya0mKacu+ayptJfaRuM0mdHCqiOth4FnRP8mPhEroFPx6Ift8wHA==
 
+wait-port@^0.3.0:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/wait-port/-/wait-port-0.3.1.tgz#d4309654b88a82333459eb264bc278e0be998d37"
+  integrity sha512-o8kW8xjslQDrbazXgXeDFt53l128J9xBAiG4aBmr9DcQA05jt0VBf2TE2vc9rxctgZjIuWpiXuO0gIYFo3pZSA==
+  dependencies:
+    chalk "^4.1.2"
+    commander "^9.3.0"
+    debug "^4.3.4"
+
 watchpack@^2.3.1:
   version "2.4.0"
   resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"