hmt 5 rokov pred
commit
607965ac14
49 zmenil súbory, kde vykonal 5262 pridanie a 0 odobranie
  1. 44 0
      .github/workflows/build.yml
  2. 11 0
      .gitignore
  3. 21 0
      LICENSE
  4. BIN
      build/fonts/Inter-Bold.woff2
  5. BIN
      build/fonts/Inter-Italic.woff2
  6. BIN
      build/fonts/Inter-Regular.woff2
  7. BIN
      build/fonts/MaterialIcons-Regular.woff2
  8. 147 0
      build/global.css
  9. BIN
      build/icons/mac/icon.icns
  10. BIN
      build/icons/png/1024x1024.png
  11. BIN
      build/icons/png/128x128.png
  12. BIN
      build/icons/png/16x16.png
  13. BIN
      build/icons/png/24x24.png
  14. BIN
      build/icons/png/256x256.png
  15. BIN
      build/icons/png/32x32.png
  16. BIN
      build/icons/png/48x48.png
  17. BIN
      build/icons/png/512x512.png
  18. BIN
      build/icons/png/64x64.png
  19. BIN
      build/icons/win/icon.ico
  20. 11 0
      build/index.html
  21. 3146 0
      package-lock.json
  22. 56 0
      package.json
  23. 33 0
      rollup.config.js
  24. 24 0
      src/components/App.svelte
  25. 134 0
      src/components/Autocomplete.svelte
  26. 175 0
      src/components/Einstellungen.svelte
  27. 130 0
      src/components/Kurs.svelte
  28. 45 0
      src/components/Main.svelte
  29. 201 0
      src/components/Medien.svelte
  30. 110 0
      src/components/Medium.svelte
  31. 60 0
      src/components/Messenger.svelte
  32. 75 0
      src/components/Navbar.svelte
  33. 109 0
      src/components/Nutzer.svelte
  34. 28 0
      src/components/Print.svelte
  35. 44 0
      src/components/Print/Kurs.svelte
  36. 39 0
      src/components/Print/Medien.svelte
  37. 44 0
      src/components/Print/Schueler.svelte
  38. 158 0
      src/components/Scanner.svelte
  39. 133 0
      src/components/Schueler.svelte
  40. 11 0
      src/configstore.js
  41. 39 0
      src/database.js
  42. 4 0
      src/exceptions.js
  43. 27 0
      src/getter.js
  44. 12 0
      src/helpers.js
  45. 7 0
      src/index.js
  46. 73 0
      src/main.js
  47. 75 0
      src/migrations/001-init.js
  48. 20 0
      src/notifier.js
  49. 16 0
      src/stores.js

+ 44 - 0
.github/workflows/build.yml

@@ -0,0 +1,44 @@
+name: Build and release bangbib
+on: push
+jobs:
+  release:
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        os: [windows-latest]
+    steps:
+      - name: Check out Git repository
+        uses: actions/checkout@v1
+      - name: Cache node modules
+        uses: actions/cache@v1
+        env:
+          cache-name: cache-node-modules
+        with:
+          path: node_modules
+          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
+          restore-keys: |
+            ${{ runner.os }}-build-${{ env.cache-name }}-
+            ${{ runner.os }}-build-
+            ${{ runner.os }}-
+      - name: Install Node.js, NPM
+        uses: actions/setup-node@v1
+        with:
+          node-version: 13
+      - name: Install Dependencies
+        run: npm install
+      - name: Build
+        run: npm run build -m
+      - name: Package
+        run: npm run dist
+      - name: show dir
+        run: ls dist
+      - uses: actions/upload-artifact@v1
+        with:
+          name: bangbib
+          path: "./dist"
+      - uses: ncipollo/release-action@v1
+        with:
+          artifact: "./dist/bangbib.msi"
+          allowUpdates: true
+          tag: v1.0.${{ github.run_number }}
+          token: ${{ secrets.GITHUB_TOKEN }}

+ 11 - 0
.gitignore

@@ -0,0 +1,11 @@
+node_modules/
+release/
+package-lock.jsonbuild
+build/bundle.*
+build/*.js
+build/*.map
+.DS_Store
+.vscode
+*.code-workspace
+*.sqlite
+dist

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) hmt
+
+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.

BIN
build/fonts/Inter-Bold.woff2


BIN
build/fonts/Inter-Italic.woff2


BIN
build/fonts/Inter-Regular.woff2


BIN
build/fonts/MaterialIcons-Regular.woff2


+ 147 - 0
build/global.css

@@ -0,0 +1,147 @@
+html {
+  font-size: 13px;
+}
+body {
+  font-family: 'Inter', sans-serif;
+}
+@font-face {
+  font-family: 'Inter';
+  font-style:  normal;
+  font-weight: 400;
+  font-display: swap;
+  src: url("fonts/Inter-Regular.woff2?v=3.9") format("woff2");
+}
+@font-face {
+  font-family: 'Inter';
+  font-style:  italic;
+  font-weight: 400;
+  font-display: swap;
+  src: url("fonts/Inter-Italic.woff2?v=3.9") format("woff2");
+}
+@font-face {
+  font-family: 'Inter';
+  font-style:  normal;
+  font-weight: 700;
+  font-display: swap;
+  src: url("fonts/Inter-Bold.woff2?v=3.9") format("woff2");
+}
+@font-face {
+  font-family: 'Material Icons';
+  font-style: normal;
+  font-weight: 400;
+  src: url("fonts/MaterialIcons-Regular.woff2") format('woff2')
+}
+/*
+  https://google.github.io/material-design-icons/
+*/
+.mdi {
+  font-family: 'Material Icons';
+  font-weight: normal;
+  font-style: normal;
+  font-size: 24px;  /* Preferred icon size */
+  display: inline-block;
+  line-height: 1;
+  text-transform: none;
+  letter-spacing: normal;
+  word-wrap: normal;
+  white-space: nowrap;
+  direction: ltr;
+  -webkit-font-smoothing: antialiased;
+  text-rendering: optimizeLegibility;
+}
+.mdi-36px {
+  font-size: 36px;  /* Preferred icon size */
+}
+.pointer {
+  cursor: pointer;
+}
+
+@media screen {
+  .page {
+    box-sizing: border-box;
+    background: rgba(255,255,255,0.9);
+    margin: 20px;
+    box-shadow: 0px 0px 30px 0px #888;
+  }
+}
+
+@media print {
+  * {
+    -webkit-print-color-adjust: exact;
+  }
+  .page {
+    page-break-after: always;
+    page-break-inside: avoid;
+    margin: 0;
+  }
+  .no-print, .no-print * {
+      display: none !important;
+  }
+}
+
+@page {
+  margin: 0;
+}
+
+.page {
+  line-height: 1.5;
+  font-weight: normal;
+  font-family: "Inter";
+  color: #333;
+  position: relative;
+  padding: 10mm 25mm 10mm 25mm;
+  display: block;
+}
+
+/*
+Da *named pages*, also z.B. @page a3landscape noch nicht von Chrome
+unterstützt werden, gilt vorerst die Standard-Einstellung von A4 Portrait.
+Um andere Formate zu erzeugen, muss die Größe in den svelte-Koponenten
+als setup-Einstellung hinterlegt werden. Oder man verwendet ein besonderes CSS
+mit der anderen Einstellung.
+Dazu bitte ein @import 'nicht_a4_portrait.css' verwenden. Svelte ignoriert sonst
+die in den <style> tags hinterlegten @... Anweisungen.
+Link: https://www.w3.org/TR/css3-page/#using-named-pages
+*/
+
+.page[size="A4"][orientation="portrait"] {
+  /* page: a4portrait; */
+  width: 210mm;
+  height: 296.8mm;
+}
+/* @page a4portrait {
+  margin: 0;
+  size: A4 portrait;
+} */
+
+.page[size="A4"][orientation="landscape"] {
+  /* page: a4landscape; */
+  width: 296.8mm;
+  height: 209mm;
+}
+/* @page a4landscape {
+  margin: 0;
+  size: A4 landscape;
+} */
+
+.grid {
+  display: grid;
+  grid-gap: 0;
+  gap: 0;
+  grid-template-columns: auto;
+  grid-template-rows: auto 1fr auto;
+  grid-template-areas: "header" "main" "footer";
+}
+
+.header {
+  grid-area: header;
+}
+
+.main {
+  grid-area: main;
+}
+
+.footer {
+  grid-area: footer;
+  align-self: end;
+}

BIN
build/icons/mac/icon.icns


BIN
build/icons/png/1024x1024.png


BIN
build/icons/png/128x128.png


BIN
build/icons/png/16x16.png


BIN
build/icons/png/24x24.png


BIN
build/icons/png/256x256.png


BIN
build/icons/png/32x32.png


BIN
build/icons/png/48x48.png


BIN
build/icons/png/512x512.png


BIN
build/icons/png/64x64.png


BIN
build/icons/win/icon.ico


+ 11 - 0
build/index.html

@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <link href="./bundle.css" rel="stylesheet" />
+    <link href="./global.css" rel="stylesheet" />
+  </head>
+  <body>
+    <script src="./index.js"></script>
+  </body>
+</html>

+ 3146 - 0
package-lock.json

@@ -0,0 +1,3146 @@
+{
+  "name": "bangbib",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "7zip-bin": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.0.3.tgz",
+      "integrity": "sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA==",
+      "dev": true
+    },
+    "@develar/schema-utils": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.1.0.tgz",
+      "integrity": "sha512-qjCqB4ctMig9Gz5bd6lkdFr3bO6arOdQqptdBSpF1ZpCnjofieCciEzkoS9ujY9cMGyllYSCSmBJ3x9OKHXzoA==",
+      "dev": true,
+      "requires": {
+        "ajv": "^6.1.0",
+        "ajv-keywords": "^3.1.0"
+      }
+    },
+    "@electron/get": {
+      "version": "1.7.6",
+      "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.7.6.tgz",
+      "integrity": "sha512-zlNikt6ziVLNcm4lly1L4y62fJd/eYpEBjF5DiV/VAQq2vdPjH4sbUphXt9upmHz86lAhAj8g9lTnWrxJ/KBZw==",
+      "dev": true,
+      "requires": {
+        "debug": "^4.1.1",
+        "env-paths": "^2.2.0",
+        "fs-extra": "^8.1.0",
+        "global-agent": "^2.0.2",
+        "global-tunnel-ng": "^2.7.1",
+        "got": "^9.6.0",
+        "sanitize-filename": "^1.6.2",
+        "sumchecker": "^3.0.1"
+      }
+    },
+    "@sindresorhus/is": {
+      "version": "0.14.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
+      "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==",
+      "dev": true
+    },
+    "@szmarczak/http-timer": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
+      "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==",
+      "dev": true,
+      "requires": {
+        "defer-to-connect": "^1.0.1"
+      }
+    },
+    "@types/color-name": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
+      "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
+      "dev": true
+    },
+    "@types/debug": {
+      "version": "4.1.5",
+      "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz",
+      "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==",
+      "dev": true
+    },
+    "@types/estree": {
+      "version": "0.0.42",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.42.tgz",
+      "integrity": "sha512-K1DPVvnBCPxzD+G51/cxVIoc2X8uUVl1zpJeE6iKcgHMj4+tbat5Xu4TjV7v2QSDbIeAfLi2hIk+u2+s0MlpUQ==",
+      "dev": true
+    },
+    "@types/node": {
+      "version": "12.12.26",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.26.tgz",
+      "integrity": "sha512-UmUm94/QZvU5xLcUlNR8hA7Ac+fGpO1EG/a8bcWVz0P0LqtxFmun9Y2bbtuckwGboWJIT70DoWq1r3hb56n3DA==",
+      "dev": true
+    },
+    "@types/resolve": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
+      "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
+    "acorn": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz",
+      "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==",
+      "dev": true
+    },
+    "ajv": {
+      "version": "6.11.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz",
+      "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==",
+      "requires": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      }
+    },
+    "ajv-keywords": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz",
+      "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==",
+      "dev": true
+    },
+    "ansi-align": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz",
+      "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==",
+      "dev": true,
+      "requires": {
+        "string-width": "^3.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+          "dev": true
+        },
+        "string-width": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^4.1.0"
+          }
+        }
+      }
+    },
+    "ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+    },
+    "ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "requires": {
+        "color-convert": "^1.9.0"
+      }
+    },
+    "app-builder-bin": {
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.5.2.tgz",
+      "integrity": "sha512-tYeNHp8js5c5MT+mzGEMsZhDBXRVAkCgrvz80rzNLlCojG6YrNLRSzfCWZiKJCv5W2faHjxTkKQoRAMY3RWaow==",
+      "dev": true
+    },
+    "app-builder-lib": {
+      "version": "22.3.2",
+      "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.3.2.tgz",
+      "integrity": "sha512-QHaDelJUP3R+HUmnQJzHvjlCCJGG6t0bcFSZTOtUx+44B42VxzKpxtoG55xRFbyrU5l2++n7dQqEZAGk8iL6Qg==",
+      "dev": true,
+      "requires": {
+        "7zip-bin": "~5.0.3",
+        "@develar/schema-utils": "~2.1.0",
+        "async-exit-hook": "^2.0.1",
+        "bluebird-lst": "^1.0.9",
+        "builder-util": "22.3.2",
+        "builder-util-runtime": "8.6.0",
+        "chromium-pickle-js": "^0.2.0",
+        "debug": "^4.1.1",
+        "ejs": "^3.0.1",
+        "electron-publish": "22.3.2",
+        "fs-extra": "^8.1.0",
+        "hosted-git-info": "^3.0.2",
+        "is-ci": "^2.0.0",
+        "isbinaryfile": "^4.0.4",
+        "js-yaml": "^3.13.1",
+        "lazy-val": "^1.0.4",
+        "minimatch": "^3.0.4",
+        "normalize-package-data": "^2.5.0",
+        "read-config-file": "5.0.1",
+        "sanitize-filename": "^1.6.3",
+        "semver": "^7.1.1",
+        "temp-file": "^3.3.6"
+      },
+      "dependencies": {
+        "hosted-git-info": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.2.tgz",
+          "integrity": "sha512-ezZMWtHXm7Eb7Rq4Mwnx2vs79WUx2QmRg3+ZqeGroKzfDO+EprOcgRPYghsOP9JuYBfK18VojmRTGCg8Ma+ktw==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^5.1.1"
+          }
+        },
+        "semver": {
+          "version": "7.1.2",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.2.tgz",
+          "integrity": "sha512-BJs9T/H8sEVHbeigqzIEo57Iu/3DG6c4QoqTfbQB3BPA4zgzAomh/Fk9E7QtjWQ8mx2dgA9YCfSF4y9k9bHNpQ==",
+          "dev": true
+        }
+      }
+    },
+    "aproba": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+      "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+    },
+    "are-we-there-yet": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+      "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+      "requires": {
+        "delegates": "^1.0.0",
+        "readable-stream": "^2.0.6"
+      }
+    },
+    "argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "requires": {
+        "sprintf-js": "~1.0.2"
+      },
+      "dependencies": {
+        "sprintf-js": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+          "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+          "dev": true
+        }
+      }
+    },
+    "async-exit-hook": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz",
+      "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==",
+      "dev": true
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "dev": true
+    },
+    "better-sqlite3": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-6.0.1.tgz",
+      "integrity": "sha512-4aV1zEknM9g1a6B0mVBx1oIlmYioEJ8gSS3J6EpN1b1bKYEE+N5lmpmXHKNKTi0qjHziSd7XrXwHl1kpqvEcHQ==",
+      "requires": {
+        "bindings": "^1.5.0",
+        "integer": "^3.0.1",
+        "prebuild-install": "^5.3.3",
+        "tar": "4.4.10"
+      }
+    },
+    "bindings": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+      "requires": {
+        "file-uri-to-path": "1.0.0"
+      }
+    },
+    "bl": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz",
+      "integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==",
+      "requires": {
+        "readable-stream": "^3.0.1"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
+    "bluebird": {
+      "version": "3.7.2",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+      "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+      "dev": true
+    },
+    "bluebird-lst": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz",
+      "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==",
+      "dev": true,
+      "requires": {
+        "bluebird": "^3.5.5"
+      }
+    },
+    "boolean": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.1.tgz",
+      "integrity": "sha512-HRZPIjPcbwAVQvOTxR4YE3o8Xs98NqbbL1iEZDCz7CL8ql0Lt5iOyJFxfnAB0oFs8Oh02F/lLlg30Mexv46LjA==",
+      "dev": true,
+      "optional": true
+    },
+    "boxen": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
+      "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==",
+      "dev": true,
+      "requires": {
+        "ansi-align": "^3.0.0",
+        "camelcase": "^5.3.1",
+        "chalk": "^3.0.0",
+        "cli-boxes": "^2.2.0",
+        "string-width": "^4.1.0",
+        "term-size": "^2.1.0",
+        "type-fest": "^0.8.1",
+        "widest-line": "^3.1.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+          "dev": true,
+          "requires": {
+            "@types/color-name": "^1.1.1",
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "7.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "type-fest": {
+          "version": "0.8.1",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+          "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+          "dev": true
+        }
+      }
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "buffer-from": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+      "dev": true
+    },
+    "builder-util": {
+      "version": "22.3.2",
+      "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.3.2.tgz",
+      "integrity": "sha512-jNeyA/AgyujE6NQLoEkERY/qrilFdCFAC6cBM1ylSnRuzlD1tQQCI3QJhuMJG/gLUCgyNsfFQhN0Mw6IqsDAqw==",
+      "dev": true,
+      "requires": {
+        "7zip-bin": "~5.0.3",
+        "@types/debug": "^4.1.5",
+        "app-builder-bin": "3.5.2",
+        "bluebird-lst": "^1.0.9",
+        "builder-util-runtime": "8.6.0",
+        "chalk": "^3.0.0",
+        "debug": "^4.1.1",
+        "fs-extra": "^8.1.0",
+        "is-ci": "^2.0.0",
+        "js-yaml": "^3.13.1",
+        "source-map-support": "^0.5.16",
+        "stat-mode": "^1.0.0",
+        "temp-file": "^3.3.6"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+          "dev": true,
+          "requires": {
+            "@types/color-name": "^1.1.1",
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "builder-util-runtime": {
+      "version": "8.6.0",
+      "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.6.0.tgz",
+      "integrity": "sha512-WTDhTUVrm7zkFyd6Qn7AXgmWifjpZ/fYnEdV3XCOIDMNNb/KPddBTbQ8bUlxxVeuOYlhGpcLUypG+4USdGL1ww==",
+      "dev": true,
+      "requires": {
+        "debug": "^4.1.1",
+        "sax": "^1.2.4"
+      }
+    },
+    "builtin-modules": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
+      "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
+      "dev": true
+    },
+    "bulma": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/bulma/-/bulma-0.8.0.tgz",
+      "integrity": "sha512-nhf3rGyiZh/VM7FrSJ/5KeLlfaFkXz0nYcXriynfPH4vVpnxnqyEwaNGdNCVzHyyCA3cHgkQAMpdF/SFbFGZfA=="
+    },
+    "cacheable-request": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz",
+      "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==",
+      "dev": true,
+      "requires": {
+        "clone-response": "^1.0.2",
+        "get-stream": "^5.1.0",
+        "http-cache-semantics": "^4.0.0",
+        "keyv": "^3.0.0",
+        "lowercase-keys": "^2.0.0",
+        "normalize-url": "^4.1.0",
+        "responselike": "^1.0.2"
+      },
+      "dependencies": {
+        "get-stream": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz",
+          "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==",
+          "dev": true,
+          "requires": {
+            "pump": "^3.0.0"
+          }
+        },
+        "lowercase-keys": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
+          "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
+          "dev": true
+        }
+      }
+    },
+    "camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "dev": true
+    },
+    "chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "dependencies": {
+        "escape-string-regexp": {
+          "version": "1.0.5",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+          "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+          "dev": true
+        }
+      }
+    },
+    "chownr": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+      "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
+    },
+    "chromium-pickle-js": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz",
+      "integrity": "sha1-BKEGZywYsIWrd02YPfo+oTjyIgU=",
+      "dev": true
+    },
+    "ci-info": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+      "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+      "dev": true
+    },
+    "cli-boxes": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz",
+      "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==",
+      "dev": true
+    },
+    "clone-response": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
+      "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
+      "dev": true,
+      "requires": {
+        "mimic-response": "^1.0.0"
+      }
+    },
+    "code-point-at": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+    },
+    "color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "requires": {
+        "color-name": "1.1.3"
+      }
+    },
+    "color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+      "dev": true
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "concat-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.2.2",
+        "typedarray": "^0.0.6"
+      }
+    },
+    "conf": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/conf/-/conf-6.2.1.tgz",
+      "integrity": "sha512-GbPshJUwZY8/+WXTLLyJplzCVAljX0vECBdUy1Es8npc8naGIEivexdhZP2zt8x/REzgtB9IONaB+ZNB9Ciz6w==",
+      "requires": {
+        "ajv": "^6.10.2",
+        "debounce-fn": "^3.0.1",
+        "dot-prop": "^5.0.0",
+        "env-paths": "^2.2.0",
+        "json-schema-typed": "^7.0.1",
+        "make-dir": "^3.0.0",
+        "onetime": "^5.1.0",
+        "pkg-up": "^3.0.1",
+        "semver": "^6.2.0",
+        "write-file-atomic": "^3.0.0"
+      }
+    },
+    "config-chain": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz",
+      "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "ini": "^1.3.4",
+        "proto-list": "~1.2.1"
+      }
+    },
+    "configstore": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.0.tgz",
+      "integrity": "sha512-eE/hvMs7qw7DlcB5JPRnthmrITuHMmACUJAp89v6PT6iOqzoLS7HRWhBtuHMlhNHo2AhUSA/3Dh1bKNJHcublQ==",
+      "dev": true,
+      "requires": {
+        "dot-prop": "^5.1.0",
+        "graceful-fs": "^4.1.2",
+        "make-dir": "^3.0.0",
+        "unique-string": "^2.0.0",
+        "write-file-atomic": "^3.0.0",
+        "xdg-basedir": "^4.0.0"
+      }
+    },
+    "console-control-strings": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+      "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+    },
+    "core-js": {
+      "version": "3.6.4",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz",
+      "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==",
+      "dev": true,
+      "optional": true
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+    },
+    "cross-spawn": {
+      "version": "6.0.5",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+      "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+      "dev": true,
+      "requires": {
+        "nice-try": "^1.0.4",
+        "path-key": "^2.0.1",
+        "semver": "^5.5.0",
+        "shebang-command": "^1.2.0",
+        "which": "^1.2.9"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        }
+      }
+    },
+    "crypto-random-string": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
+      "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
+      "dev": true
+    },
+    "debounce-fn": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-3.0.1.tgz",
+      "integrity": "sha512-aBoJh5AhpqlRoHZjHmOzZlRx+wz2xVwGL9rjs+Kj0EWUrL4/h4K7OD176thl2Tdoqui/AaA4xhHrNArGLAaI3Q==",
+      "requires": {
+        "mimic-fn": "^2.1.0"
+      }
+    },
+    "debug": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+      "dev": true,
+      "requires": {
+        "ms": "^2.1.1"
+      }
+    },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+      "dev": true
+    },
+    "decompress-response": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
+      "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
+      "dev": true,
+      "requires": {
+        "mimic-response": "^1.0.0"
+      }
+    },
+    "deep-extend": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+    },
+    "defer-to-connect": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz",
+      "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==",
+      "dev": true
+    },
+    "define-properties": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+      "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+      "dev": true,
+      "requires": {
+        "object-keys": "^1.0.12"
+      }
+    },
+    "delegates": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+      "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+    },
+    "detect-libc": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+      "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
+    },
+    "detect-node": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz",
+      "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==",
+      "dev": true,
+      "optional": true
+    },
+    "dmg-builder": {
+      "version": "22.3.2",
+      "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.3.2.tgz",
+      "integrity": "sha512-szx+nmCNjpfp2yy3zVCMQLj2nRHL3LfZyzvQECDGHr0ZHK7//48+MoJckkbOCB22ofBvx5Y2M1YqCjK8b2slYQ==",
+      "dev": true,
+      "requires": {
+        "app-builder-lib": "~22.3.2",
+        "bluebird-lst": "^1.0.9",
+        "builder-util": "~22.3.2",
+        "fs-extra": "^8.1.0",
+        "iconv-lite": "^0.5.1",
+        "js-yaml": "^3.13.1",
+        "sanitize-filename": "^1.6.3"
+      }
+    },
+    "dot-prop": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz",
+      "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==",
+      "requires": {
+        "is-obj": "^2.0.0"
+      }
+    },
+    "dotenv": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
+      "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
+      "dev": true
+    },
+    "dotenv-expand": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
+      "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
+      "dev": true
+    },
+    "duplexer3": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
+      "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
+      "dev": true
+    },
+    "ejs": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.0.1.tgz",
+      "integrity": "sha512-cuIMtJwxvzumSAkqaaoGY/L6Fc/t6YvoP9/VIaK0V/CyqKLEQ8sqODmYfy/cjXEdZ9+OOL8TecbJu+1RsofGDw==",
+      "dev": true
+    },
+    "electron": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/electron/-/electron-8.0.1.tgz",
+      "integrity": "sha512-kLZAQkbrAFNjQVpcHJUnjRYQNafuuWKnsdxzag5do1ewMqN0J4Pi/hPE27+5/1YAFMcbvCrPqhWIpcMsi8mKXQ==",
+      "dev": true,
+      "requires": {
+        "@electron/get": "^1.0.1",
+        "@types/node": "^12.0.12",
+        "extract-zip": "^1.0.3"
+      }
+    },
+    "electron-builder": {
+      "version": "22.3.2",
+      "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.3.2.tgz",
+      "integrity": "sha512-bDjHfKtA4DapI6qqy4FC18fzLsOJtlSVGBqjSjhrgv+gbcppp3tjR6ASsUX5K64/8L9MGjhRGdfQ7iP78OLx8g==",
+      "dev": true,
+      "requires": {
+        "app-builder-lib": "22.3.2",
+        "bluebird-lst": "^1.0.9",
+        "builder-util": "22.3.2",
+        "builder-util-runtime": "8.6.0",
+        "chalk": "^3.0.0",
+        "dmg-builder": "22.3.2",
+        "fs-extra": "^8.1.0",
+        "is-ci": "^2.0.0",
+        "lazy-val": "^1.0.4",
+        "read-config-file": "5.0.1",
+        "sanitize-filename": "^1.6.3",
+        "update-notifier": "^4.0.0",
+        "yargs": "^15.1.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+          "dev": true,
+          "requires": {
+            "@types/color-name": "^1.1.1",
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "cliui": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+          "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+          "dev": true,
+          "requires": {
+            "string-width": "^4.2.0",
+            "strip-ansi": "^6.0.0",
+            "wrap-ansi": "^6.2.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "find-up": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^5.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+          "dev": true
+        },
+        "locate-path": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^4.1.0"
+          }
+        },
+        "p-locate": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^2.2.0"
+          }
+        },
+        "path-exists": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "7.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "wrap-ansi": {
+          "version": "6.2.0",
+          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+          "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "string-width": "^4.1.0",
+            "strip-ansi": "^6.0.0"
+          }
+        },
+        "yargs": {
+          "version": "15.1.0",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.1.0.tgz",
+          "integrity": "sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg==",
+          "dev": true,
+          "requires": {
+            "cliui": "^6.0.0",
+            "decamelize": "^1.2.0",
+            "find-up": "^4.1.0",
+            "get-caller-file": "^2.0.1",
+            "require-directory": "^2.1.1",
+            "require-main-filename": "^2.0.0",
+            "set-blocking": "^2.0.0",
+            "string-width": "^4.2.0",
+            "which-module": "^2.0.0",
+            "y18n": "^4.0.0",
+            "yargs-parser": "^16.1.0"
+          }
+        }
+      }
+    },
+    "electron-is-dev": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.1.0.tgz",
+      "integrity": "sha512-Z1qA/1oHNowGtSBIcWk0pcLEqYT/j+13xUw/MYOrBUOL4X7VN0i0KCTf5SqyvMPmW5pSPKbo28wkxMxzZ20YnQ=="
+    },
+    "electron-publish": {
+      "version": "22.3.2",
+      "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.3.2.tgz",
+      "integrity": "sha512-nUGepzRtoGT8Tv83RHnnrR5szbw4+HpLLBdZU+aO5Kt3uoReTsp7NSm+agJfbI+H5rVpYCG8h6nPIejxGZ7LTg==",
+      "dev": true,
+      "requires": {
+        "bluebird-lst": "^1.0.9",
+        "builder-util": "~22.3.2",
+        "builder-util-runtime": "8.6.0",
+        "chalk": "^3.0.0",
+        "fs-extra": "^8.1.0",
+        "lazy-val": "^1.0.4",
+        "mime": "^2.4.4"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+          "dev": true,
+          "requires": {
+            "@types/color-name": "^1.1.1",
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "electron-store": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/electron-store/-/electron-store-5.1.1.tgz",
+      "integrity": "sha512-FLidOVE8JVCdJXHd7xY/JojKJ2r2WNmWt0O/LlX2LuSVV7dkG2RSy2/Gm2LFw8OKDfrNBd9c/s4X1ikMrJEUKg==",
+      "requires": {
+        "conf": "^6.2.1",
+        "type-fest": "^0.7.1"
+      }
+    },
+    "electron-util": {
+      "version": "0.14.0",
+      "resolved": "https://registry.npmjs.org/electron-util/-/electron-util-0.14.0.tgz",
+      "integrity": "sha512-f8DXlOLrI7aq2S1yRlgx8Dc+Zbq5hlKKyVUnc73HyLEijo8/0KT9Cqlcduy75qwwynVw+cvbuqtqgIlrHLijyw==",
+      "requires": {
+        "electron-is-dev": "^1.1.0",
+        "new-github-issue-url": "^0.2.1"
+      }
+    },
+    "emoji-regex": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+      "dev": true
+    },
+    "encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+      "dev": true,
+      "optional": true
+    },
+    "end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+      "requires": {
+        "once": "^1.4.0"
+      }
+    },
+    "env-paths": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz",
+      "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA=="
+    },
+    "error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dev": true,
+      "requires": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "es-abstract": {
+      "version": "1.17.4",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz",
+      "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==",
+      "dev": true,
+      "requires": {
+        "es-to-primitive": "^1.2.1",
+        "function-bind": "^1.1.1",
+        "has": "^1.0.3",
+        "has-symbols": "^1.0.1",
+        "is-callable": "^1.1.5",
+        "is-regex": "^1.0.5",
+        "object-inspect": "^1.7.0",
+        "object-keys": "^1.1.1",
+        "object.assign": "^4.1.0",
+        "string.prototype.trimleft": "^2.1.1",
+        "string.prototype.trimright": "^2.1.1"
+      }
+    },
+    "es-to-primitive": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+      "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+      "dev": true,
+      "requires": {
+        "is-callable": "^1.1.4",
+        "is-date-object": "^1.0.1",
+        "is-symbol": "^1.0.2"
+      }
+    },
+    "es6-error": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
+      "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
+      "dev": true,
+      "optional": true
+    },
+    "escape-string-regexp": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+      "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+      "dev": true,
+      "optional": true
+    },
+    "esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true
+    },
+    "estree-walker": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
+      "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
+      "dev": true
+    },
+    "expand-template": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+      "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="
+    },
+    "extract-zip": {
+      "version": "1.6.7",
+      "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz",
+      "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=",
+      "dev": true,
+      "requires": {
+        "concat-stream": "1.6.2",
+        "debug": "2.6.9",
+        "mkdirp": "0.5.1",
+        "yauzl": "2.4.1"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        }
+      }
+    },
+    "fast-deep-equal": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
+      "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
+    },
+    "fd-slicer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
+      "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
+      "dev": true,
+      "requires": {
+        "pend": "~1.2.0"
+      }
+    },
+    "file-uri-to-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
+    },
+    "find-up": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
+      "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
+      "requires": {
+        "locate-path": "^3.0.0"
+      }
+    },
+    "fs-constants": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+      "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
+    },
+    "fs-extra": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+      "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
+      }
+    },
+    "fs-minipass": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
+      "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
+      "requires": {
+        "minipass": "^2.6.0"
+      }
+    },
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
+    },
+    "gauge": {
+      "version": "2.7.4",
+      "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+      "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+      "requires": {
+        "aproba": "^1.0.3",
+        "console-control-strings": "^1.0.0",
+        "has-unicode": "^2.0.0",
+        "object-assign": "^4.1.0",
+        "signal-exit": "^3.0.0",
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1",
+        "wide-align": "^1.1.0"
+      }
+    },
+    "get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true
+    },
+    "get-stream": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+      "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+      "dev": true,
+      "requires": {
+        "pump": "^3.0.0"
+      }
+    },
+    "github-from-package": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+      "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4="
+    },
+    "global-agent": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.8.tgz",
+      "integrity": "sha512-VpBe/rhY6Rw2VDOTszAMNambg+4Qv8j0yiTNDYEXXXxkUNGWLHp8A3ztK4YDBbFNcWF4rgsec6/5gPyryya/+A==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "boolean": "^3.0.0",
+        "core-js": "^3.6.4",
+        "es6-error": "^4.1.1",
+        "matcher": "^2.1.0",
+        "roarr": "^2.15.2",
+        "semver": "^7.1.2",
+        "serialize-error": "^5.0.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "7.1.3",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.1.3.tgz",
+          "integrity": "sha512-ekM0zfiA9SCBlsKa2X1hxyxiI4L3B6EbVJkkdgQXnSEEaHlGdvyodMruTiulSRWMMB4NeIuYNMC9rTKTz97GxA==",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "global-dirs": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz",
+      "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==",
+      "dev": true,
+      "requires": {
+        "ini": "^1.3.5"
+      }
+    },
+    "global-tunnel-ng": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz",
+      "integrity": "sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "encodeurl": "^1.0.2",
+        "lodash": "^4.17.10",
+        "npm-conf": "^1.1.3",
+        "tunnel": "^0.0.6"
+      }
+    },
+    "globalthis": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.1.tgz",
+      "integrity": "sha512-mJPRTc/P39NH/iNG4mXa9aIhNymaQikTrnspeCa2ZuJ+mH2QN/rXwtX3XwKrHqWgUQFbNZKtHM105aHzJalElw==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "define-properties": "^1.1.3"
+      }
+    },
+    "got": {
+      "version": "9.6.0",
+      "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
+      "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==",
+      "dev": true,
+      "requires": {
+        "@sindresorhus/is": "^0.14.0",
+        "@szmarczak/http-timer": "^1.1.2",
+        "cacheable-request": "^6.0.0",
+        "decompress-response": "^3.3.0",
+        "duplexer3": "^0.1.4",
+        "get-stream": "^4.1.0",
+        "lowercase-keys": "^1.0.1",
+        "mimic-response": "^1.0.1",
+        "p-cancelable": "^1.0.0",
+        "to-readable-stream": "^1.0.0",
+        "url-parse-lax": "^3.0.0"
+      }
+    },
+    "graceful-fs": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
+      "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
+      "dev": true
+    },
+    "has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1"
+      }
+    },
+    "has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+      "dev": true
+    },
+    "has-symbols": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
+      "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
+      "dev": true
+    },
+    "has-unicode": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+      "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
+    },
+    "has-yarn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
+      "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==",
+      "dev": true
+    },
+    "hosted-git-info": {
+      "version": "2.8.5",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
+      "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==",
+      "dev": true
+    },
+    "http-cache-semantics": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz",
+      "integrity": "sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==",
+      "dev": true
+    },
+    "iconv-lite": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.1.tgz",
+      "integrity": "sha512-ONHr16SQvKZNSqjQT9gy5z24Jw+uqfO02/ngBSBoqChZ+W8qXX7GPRa1RoUnzGADw8K63R1BXUMzarCVQBpY8Q==",
+      "dev": true,
+      "requires": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      }
+    },
+    "import-lazy": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
+      "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=",
+      "dev": true
+    },
+    "imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
+    },
+    "inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "ini": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
+    },
+    "integer": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/integer/-/integer-3.0.1.tgz",
+      "integrity": "sha512-OqtER6W2GIJTIcnT5o2B/pWGgvurnVOYs4OZCgay40QEIbMTnNq4R0KSaIw1TZyFtPWjm5aNM+pBBMTfc3exmw==",
+      "requires": {
+        "bindings": "^1.5.0",
+        "prebuild-install": "^5.3.3"
+      }
+    },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+      "dev": true
+    },
+    "is-callable": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
+      "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==",
+      "dev": true
+    },
+    "is-ci": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+      "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+      "dev": true,
+      "requires": {
+        "ci-info": "^2.0.0"
+      }
+    },
+    "is-date-object": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
+      "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
+      "dev": true
+    },
+    "is-fullwidth-code-point": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+      "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+      "requires": {
+        "number-is-nan": "^1.0.0"
+      }
+    },
+    "is-installed-globally": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.1.tgz",
+      "integrity": "sha512-oiEcGoQbGc+3/iijAijrK2qFpkNoNjsHOm/5V5iaeydyrS/hnwaRCEgH5cpW0P3T1lSjV5piB7S5b5lEugNLhg==",
+      "dev": true,
+      "requires": {
+        "global-dirs": "^2.0.1",
+        "is-path-inside": "^3.0.1"
+      }
+    },
+    "is-module": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+      "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
+      "dev": true
+    },
+    "is-npm": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz",
+      "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==",
+      "dev": true
+    },
+    "is-obj": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+      "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="
+    },
+    "is-path-inside": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz",
+      "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==",
+      "dev": true
+    },
+    "is-reference": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz",
+      "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==",
+      "dev": true,
+      "requires": {
+        "@types/estree": "0.0.39"
+      },
+      "dependencies": {
+        "@types/estree": {
+          "version": "0.0.39",
+          "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
+          "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
+          "dev": true
+        }
+      }
+    },
+    "is-regex": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
+      "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
+      "dev": true,
+      "requires": {
+        "has": "^1.0.3"
+      }
+    },
+    "is-symbol": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
+      "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
+      "dev": true,
+      "requires": {
+        "has-symbols": "^1.0.1"
+      }
+    },
+    "is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+    },
+    "is-yarn-global": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz",
+      "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==",
+      "dev": true
+    },
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+    },
+    "isbinaryfile": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.4.tgz",
+      "integrity": "sha512-pEutbN134CzcjlLS1myKX/uxNjwU5eBVSprvkpv3+3dqhBHUZLIWJQowC40w5c0Zf19vBY8mrZl88y5J4RAPbQ==",
+      "dev": true
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+      "dev": true
+    },
+    "js-yaml": {
+      "version": "3.13.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+      "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+      "dev": true,
+      "requires": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      }
+    },
+    "json-buffer": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
+      "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=",
+      "dev": true
+    },
+    "json-parse-better-errors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+      "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+      "dev": true
+    },
+    "json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+    },
+    "json-schema-typed": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-7.0.3.tgz",
+      "integrity": "sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A=="
+    },
+    "json-stringify-safe": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+      "dev": true,
+      "optional": true
+    },
+    "json5": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz",
+      "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==",
+      "dev": true,
+      "requires": {
+        "minimist": "^1.2.0"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "dev": true
+        }
+      }
+    },
+    "jsonfile": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+      "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "keyv": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
+      "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==",
+      "dev": true,
+      "requires": {
+        "json-buffer": "3.0.0"
+      }
+    },
+    "kleur": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+      "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="
+    },
+    "latest-version": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz",
+      "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==",
+      "dev": true,
+      "requires": {
+        "package-json": "^6.3.0"
+      }
+    },
+    "lazy-val": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.4.tgz",
+      "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==",
+      "dev": true
+    },
+    "ley": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/ley/-/ley-0.4.1.tgz",
+      "integrity": "sha512-LiqtkogM5WWJ1nrVzRVsGoDBUUWlRfu3tl3Ad8YGAiac73h4ErOdy08HXWvEIfL5t81V7nx7oEPiGXCCnu2nrQ==",
+      "requires": {
+        "kleur": "^3.0.3",
+        "sade": "^1.7.0",
+        "totalist": "^1.0.1"
+      }
+    },
+    "locate-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
+      "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
+      "requires": {
+        "p-locate": "^3.0.0",
+        "path-exists": "^3.0.0"
+      }
+    },
+    "lodash": {
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+      "dev": true,
+      "optional": true
+    },
+    "lowercase-keys": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
+      "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
+      "dev": true
+    },
+    "lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "dev": true,
+      "requires": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "magic-string": {
+      "version": "0.25.6",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.6.tgz",
+      "integrity": "sha512-3a5LOMSGoCTH5rbqobC2HuDNRtE2glHZ8J7pK+QZYppyWA36yuNpsX994rIY2nCuyP7CZYy7lQq/X2jygiZ89g==",
+      "dev": true,
+      "requires": {
+        "sourcemap-codec": "^1.4.4"
+      }
+    },
+    "make-dir": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz",
+      "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==",
+      "requires": {
+        "semver": "^6.0.0"
+      }
+    },
+    "matcher": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/matcher/-/matcher-2.1.0.tgz",
+      "integrity": "sha512-o+nZr+vtJtgPNklyeUKkkH42OsK8WAfdgaJE2FNxcjLPg+5QbeEoT6vRj8Xq/iv18JlQ9cmKsEu0b94ixWf1YQ==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "escape-string-regexp": "^2.0.0"
+      }
+    },
+    "memorystream": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
+      "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
+      "dev": true
+    },
+    "mime": {
+      "version": "2.4.4",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
+      "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==",
+      "dev": true
+    },
+    "mimic-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+      "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
+    },
+    "mimic-response": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+      "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
+      "dev": true
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "minimist": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+    },
+    "minipass": {
+      "version": "2.9.0",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
+      "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
+      "requires": {
+        "safe-buffer": "^5.1.2",
+        "yallist": "^3.0.0"
+      }
+    },
+    "minizlib": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
+      "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
+      "requires": {
+        "minipass": "^2.9.0"
+      }
+    },
+    "mkdirp": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "requires": {
+        "minimist": "0.0.8"
+      }
+    },
+    "mri": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz",
+      "integrity": "sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w=="
+    },
+    "ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+      "dev": true
+    },
+    "napi-build-utils": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz",
+      "integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA=="
+    },
+    "new-github-issue-url": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/new-github-issue-url/-/new-github-issue-url-0.2.1.tgz",
+      "integrity": "sha512-md4cGoxuT4T4d/HDOXbrUHkTKrp/vp+m3aOA7XXVYwNsUNMK49g3SQicTSeV5GIz/5QVGAeYRAOlyp9OvlgsYA=="
+    },
+    "nice-try": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
+      "dev": true
+    },
+    "node-abi": {
+      "version": "2.15.0",
+      "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.15.0.tgz",
+      "integrity": "sha512-FeLpTS0F39U7hHZU1srAK4Vx+5AHNVOTP+hxBNQknR/54laTHSFIJkDWDqiquY1LeLUgTfPN7sLPhMubx0PLAg==",
+      "requires": {
+        "semver": "^5.4.1"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+        }
+      }
+    },
+    "noop-logger": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
+      "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI="
+    },
+    "normalize-package-data": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+      "dev": true,
+      "requires": {
+        "hosted-git-info": "^2.1.4",
+        "resolve": "^1.10.0",
+        "semver": "2 || 3 || 4 || 5",
+        "validate-npm-package-license": "^3.0.1"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        }
+      }
+    },
+    "normalize-url": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
+      "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==",
+      "dev": true
+    },
+    "npm-conf": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz",
+      "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "config-chain": "^1.1.11",
+        "pify": "^3.0.0"
+      }
+    },
+    "npm-run-all": {
+      "version": "4.1.5",
+      "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
+      "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^3.2.1",
+        "chalk": "^2.4.1",
+        "cross-spawn": "^6.0.5",
+        "memorystream": "^0.3.1",
+        "minimatch": "^3.0.4",
+        "pidtree": "^0.3.0",
+        "read-pkg": "^3.0.0",
+        "shell-quote": "^1.6.1",
+        "string.prototype.padend": "^3.0.0"
+      },
+      "dependencies": {
+        "load-json-file": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
+          "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
+          "dev": true,
+          "requires": {
+            "graceful-fs": "^4.1.2",
+            "parse-json": "^4.0.0",
+            "pify": "^3.0.0",
+            "strip-bom": "^3.0.0"
+          }
+        },
+        "parse-json": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+          "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+          "dev": true,
+          "requires": {
+            "error-ex": "^1.3.1",
+            "json-parse-better-errors": "^1.0.1"
+          }
+        },
+        "path-type": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+          "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+          "dev": true,
+          "requires": {
+            "pify": "^3.0.0"
+          }
+        },
+        "read-pkg": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
+          "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
+          "dev": true,
+          "requires": {
+            "load-json-file": "^4.0.0",
+            "normalize-package-data": "^2.3.2",
+            "path-type": "^3.0.0"
+          }
+        }
+      }
+    },
+    "npmlog": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+      "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+      "requires": {
+        "are-we-there-yet": "~1.1.2",
+        "console-control-strings": "~1.1.0",
+        "gauge": "~2.7.3",
+        "set-blocking": "~2.0.0"
+      }
+    },
+    "number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+    },
+    "object-inspect": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz",
+      "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==",
+      "dev": true
+    },
+    "object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "dev": true
+    },
+    "object.assign": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+      "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.2",
+        "function-bind": "^1.1.1",
+        "has-symbols": "^1.0.0",
+        "object-keys": "^1.0.11"
+      }
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "onetime": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
+      "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
+      "requires": {
+        "mimic-fn": "^2.1.0"
+      }
+    },
+    "p-cancelable": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz",
+      "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==",
+      "dev": true
+    },
+    "p-limit": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
+      "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
+      "requires": {
+        "p-try": "^2.0.0"
+      }
+    },
+    "p-locate": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
+      "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
+      "requires": {
+        "p-limit": "^2.0.0"
+      }
+    },
+    "p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
+    },
+    "package-json": {
+      "version": "6.5.0",
+      "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz",
+      "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==",
+      "dev": true,
+      "requires": {
+        "got": "^9.6.0",
+        "registry-auth-token": "^4.0.0",
+        "registry-url": "^5.0.0",
+        "semver": "^6.2.0"
+      }
+    },
+    "papaparse": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.1.1.tgz",
+      "integrity": "sha512-KPkW4GNQxunmYTeJIjHFrvilcNuHBWrfgbyvmagEmfGOA4hnP1WIkPbv4yABhj1Nam3as4w+7MBiI27BntwqVg=="
+    },
+    "path-exists": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
+      "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
+    },
+    "path-key": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+      "dev": true
+    },
+    "path-parse": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+      "dev": true
+    },
+    "pend": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+      "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+      "dev": true
+    },
+    "pidtree": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz",
+      "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==",
+      "dev": true
+    },
+    "pify": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+      "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+      "dev": true
+    },
+    "pkg-up": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
+      "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
+      "requires": {
+        "find-up": "^3.0.0"
+      }
+    },
+    "prebuild-install": {
+      "version": "5.3.3",
+      "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.3.tgz",
+      "integrity": "sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==",
+      "requires": {
+        "detect-libc": "^1.0.3",
+        "expand-template": "^2.0.3",
+        "github-from-package": "0.0.0",
+        "minimist": "^1.2.0",
+        "mkdirp": "^0.5.1",
+        "napi-build-utils": "^1.0.1",
+        "node-abi": "^2.7.0",
+        "noop-logger": "^0.1.1",
+        "npmlog": "^4.0.1",
+        "pump": "^3.0.0",
+        "rc": "^1.2.7",
+        "simple-get": "^3.0.3",
+        "tar-fs": "^2.0.0",
+        "tunnel-agent": "^0.6.0",
+        "which-pm-runs": "^1.0.0"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+        }
+      }
+    },
+    "prepend-http": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
+      "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=",
+      "dev": true
+    },
+    "prettier": {
+      "version": "1.19.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
+      "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
+      "dev": true
+    },
+    "prettier-plugin-svelte": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-0.7.0.tgz",
+      "integrity": "sha512-SuZSeMh48rx42kCFEpI/xE1XgjxQcS3r22Yo7jIhBYRhwbAa8laNxiIHsfeWWkX8BdyELkEayaTQp4ricckwTQ==",
+      "dev": true,
+      "requires": {
+        "tslib": "^1.9.3"
+      }
+    },
+    "process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+    },
+    "proto-list": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
+      "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=",
+      "dev": true,
+      "optional": true
+    },
+    "pump": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "punycode": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+    },
+    "rc": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+      "requires": {
+        "deep-extend": "^0.6.0",
+        "ini": "~1.3.0",
+        "minimist": "^1.2.0",
+        "strip-json-comments": "~2.0.1"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+        }
+      }
+    },
+    "read-config-file": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-5.0.1.tgz",
+      "integrity": "sha512-75zp4PDbvtBlECoZK1KEkNlesr9OWdMWL8oi4xq+HXAM+kKHKU+Cx2ksFt+ie2BkrmkLBOKSfONDuz+WIKWoXA==",
+      "dev": true,
+      "requires": {
+        "dotenv": "^8.2.0",
+        "dotenv-expand": "^5.1.0",
+        "fs-extra": "^8.1.0",
+        "js-yaml": "^3.13.1",
+        "json5": "^2.1.1",
+        "lazy-val": "^1.0.4"
+      }
+    },
+    "readable-stream": {
+      "version": "2.3.7",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+      "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+      "requires": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      },
+      "dependencies": {
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+        }
+      }
+    },
+    "registry-auth-token": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.1.1.tgz",
+      "integrity": "sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA==",
+      "dev": true,
+      "requires": {
+        "rc": "^1.2.8"
+      }
+    },
+    "registry-url": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz",
+      "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==",
+      "dev": true,
+      "requires": {
+        "rc": "^1.2.8"
+      }
+    },
+    "require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+      "dev": true
+    },
+    "require-main-filename": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+      "dev": true
+    },
+    "require-relative": {
+      "version": "0.8.7",
+      "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz",
+      "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=",
+      "dev": true
+    },
+    "resolve": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz",
+      "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==",
+      "dev": true,
+      "requires": {
+        "path-parse": "^1.0.6"
+      }
+    },
+    "responselike": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
+      "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=",
+      "dev": true,
+      "requires": {
+        "lowercase-keys": "^1.0.0"
+      }
+    },
+    "roarr": {
+      "version": "2.15.2",
+      "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.2.tgz",
+      "integrity": "sha512-jmaDhK9CO4YbQAV8zzCnq9vjAqeO489MS5ehZ+rXmFiPFFE6B+S9KYO6prjmLJ5A0zY3QxVlQdrIya7E/azz/Q==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "boolean": "^3.0.0",
+        "detect-node": "^2.0.4",
+        "globalthis": "^1.0.1",
+        "json-stringify-safe": "^5.0.1",
+        "semver-compare": "^1.0.0",
+        "sprintf-js": "^1.1.2"
+      }
+    },
+    "rollup": {
+      "version": "1.31.1",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.31.1.tgz",
+      "integrity": "sha512-2JREN1YdrS/kpPzEd33ZjtuNbOuBC3ePfuZBdKEybvqcEcszW1ckyVqzcEiEe0nE8sqHK+pbJg+PsAgRJ8+1dg==",
+      "dev": true,
+      "requires": {
+        "@types/estree": "*",
+        "@types/node": "*",
+        "acorn": "^7.1.0"
+      }
+    },
+    "rollup-plugin-commonjs": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz",
+      "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==",
+      "dev": true,
+      "requires": {
+        "estree-walker": "^0.6.1",
+        "is-reference": "^1.1.2",
+        "magic-string": "^0.25.2",
+        "resolve": "^1.11.0",
+        "rollup-pluginutils": "^2.8.1"
+      }
+    },
+    "rollup-plugin-json": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/rollup-plugin-json/-/rollup-plugin-json-4.0.0.tgz",
+      "integrity": "sha512-hgb8N7Cgfw5SZAkb3jf0QXii6QX/FOkiIq2M7BAQIEydjHvTyxXHQiIzZaTFgx1GK0cRCHOCBHIyEkkLdWKxow==",
+      "dev": true,
+      "requires": {
+        "rollup-pluginutils": "^2.5.0"
+      }
+    },
+    "rollup-plugin-node-externals": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/rollup-plugin-node-externals/-/rollup-plugin-node-externals-2.1.3.tgz",
+      "integrity": "sha512-un2kG0avWdPl/YuELzrCRFTSBYCjpoG02Bkooj3i73BSDu0zUzBu6kLbsuCNHtWhN1xEDtiVL2SxcmTCaAUa4Q==",
+      "dev": true
+    },
+    "rollup-plugin-node-resolve": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz",
+      "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==",
+      "dev": true,
+      "requires": {
+        "@types/resolve": "0.0.8",
+        "builtin-modules": "^3.1.0",
+        "is-module": "^1.0.0",
+        "resolve": "^1.11.1",
+        "rollup-pluginutils": "^2.8.1"
+      }
+    },
+    "rollup-plugin-svelte": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-5.1.1.tgz",
+      "integrity": "sha512-wP3CnKHjR4fZUgNm5Iey7eItnxwnH/nAw568WJ8dpMSchBxxZ/DmKSx8e6h8k/B6SwG1wfGvWehadFJHcuFFSw==",
+      "dev": true,
+      "requires": {
+        "require-relative": "^0.8.7",
+        "rollup-pluginutils": "^2.3.3",
+        "sourcemap-codec": "^1.4.4"
+      }
+    },
+    "rollup-pluginutils": {
+      "version": "2.8.2",
+      "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
+      "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
+      "dev": true,
+      "requires": {
+        "estree-walker": "^0.6.1"
+      }
+    },
+    "sade": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.3.tgz",
+      "integrity": "sha512-m4BctppMvJ60W1dXnHq7jMmFe3hPJZDAH85kQ3ACTo7XZNVUuTItCQ+2HfyaMeV5cKrbw7l4vD/6We3GBxvdJw==",
+      "requires": {
+        "mri": "^1.1.0"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
+      "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
+    },
+    "sanitize-filename": {
+      "version": "1.6.3",
+      "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz",
+      "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==",
+      "dev": true,
+      "requires": {
+        "truncate-utf8-bytes": "^1.0.0"
+      }
+    },
+    "sax": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+      "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+      "dev": true
+    },
+    "semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+    },
+    "semver-compare": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+      "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=",
+      "dev": true,
+      "optional": true
+    },
+    "semver-diff": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz",
+      "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==",
+      "dev": true,
+      "requires": {
+        "semver": "^6.3.0"
+      }
+    },
+    "serialize-error": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-5.0.0.tgz",
+      "integrity": "sha512-/VtpuyzYf82mHYTtI4QKtwHa79vAdU5OQpNPAmE/0UDdlGT0ZxHwC+J6gXkw29wwoVI8fMPsfcVHOwXtUQYYQA==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "type-fest": "^0.8.0"
+      },
+      "dependencies": {
+        "type-fest": {
+          "version": "0.8.1",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+          "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+    },
+    "shebang-command": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "dev": true,
+      "requires": {
+        "shebang-regex": "^1.0.0"
+      }
+    },
+    "shebang-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+      "dev": true
+    },
+    "shell-quote": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz",
+      "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==",
+      "dev": true
+    },
+    "signal-exit": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+    },
+    "simple-concat": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
+      "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY="
+    },
+    "simple-get": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
+      "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
+      "requires": {
+        "decompress-response": "^4.2.0",
+        "once": "^1.3.1",
+        "simple-concat": "^1.0.0"
+      },
+      "dependencies": {
+        "decompress-response": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
+          "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
+          "requires": {
+            "mimic-response": "^2.0.0"
+          }
+        },
+        "mimic-response": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
+          "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA=="
+        }
+      }
+    },
+    "source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true
+    },
+    "source-map-support": {
+      "version": "0.5.16",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
+      "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "sourcemap-codec": {
+      "version": "1.4.8",
+      "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+      "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+      "dev": true
+    },
+    "spdx-correct": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+      "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+      "dev": true,
+      "requires": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-exceptions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+      "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+      "dev": true
+    },
+    "spdx-expression-parse": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+      "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+      "dev": true,
+      "requires": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-license-ids": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
+      "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
+      "dev": true
+    },
+    "sprintf-js": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
+      "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
+      "dev": true,
+      "optional": true
+    },
+    "stat-mode": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz",
+      "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==",
+      "dev": true
+    },
+    "string-width": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+      "requires": {
+        "code-point-at": "^1.0.0",
+        "is-fullwidth-code-point": "^1.0.0",
+        "strip-ansi": "^3.0.0"
+      }
+    },
+    "string.prototype.padend": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz",
+      "integrity": "sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA==",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.3",
+        "es-abstract": "^1.17.0-next.1"
+      }
+    },
+    "string.prototype.trimleft": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
+      "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.3",
+        "function-bind": "^1.1.1"
+      }
+    },
+    "string.prototype.trimright": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz",
+      "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.3",
+        "function-bind": "^1.1.1"
+      }
+    },
+    "string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "requires": {
+        "safe-buffer": "~5.1.0"
+      },
+      "dependencies": {
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+        }
+      }
+    },
+    "strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+      "requires": {
+        "ansi-regex": "^2.0.0"
+      }
+    },
+    "strip-bom": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+      "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+      "dev": true
+    },
+    "strip-json-comments": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+    },
+    "sumchecker": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
+      "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==",
+      "dev": true,
+      "requires": {
+        "debug": "^4.1.0"
+      }
+    },
+    "supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "requires": {
+        "has-flag": "^3.0.0"
+      }
+    },
+    "svelte": {
+      "version": "3.19.1",
+      "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.19.1.tgz",
+      "integrity": "sha512-MGBh6LiWwwOfzlH9epQ8mP5DNWsuc6fWsZpLy47beqNG8wSkrQ/ez7TxaV+8VZ5KOwJJnfesj5gqgGjM2NcWVw=="
+    },
+    "tar": {
+      "version": "4.4.10",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz",
+      "integrity": "sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==",
+      "requires": {
+        "chownr": "^1.1.1",
+        "fs-minipass": "^1.2.5",
+        "minipass": "^2.3.5",
+        "minizlib": "^1.2.1",
+        "mkdirp": "^0.5.0",
+        "safe-buffer": "^5.1.2",
+        "yallist": "^3.0.3"
+      }
+    },
+    "tar-fs": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz",
+      "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==",
+      "requires": {
+        "chownr": "^1.1.1",
+        "mkdirp": "^0.5.1",
+        "pump": "^3.0.0",
+        "tar-stream": "^2.0.0"
+      }
+    },
+    "tar-stream": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz",
+      "integrity": "sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==",
+      "requires": {
+        "bl": "^3.0.0",
+        "end-of-stream": "^1.4.1",
+        "fs-constants": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^3.1.1"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
+    "temp-file": {
+      "version": "3.3.6",
+      "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.6.tgz",
+      "integrity": "sha512-7TPldi8QJqRlPIF/Y33mVvo8+xDfi6+aVTCK4CrCaLqCoaOnVtf3SA4hCU0T5nhYDdOC7erw7o2uWfvijlk4Ug==",
+      "dev": true,
+      "requires": {
+        "async-exit-hook": "^2.0.1",
+        "fs-extra": "^8.1.0"
+      }
+    },
+    "term-size": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz",
+      "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==",
+      "dev": true
+    },
+    "to-readable-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz",
+      "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==",
+      "dev": true
+    },
+    "totalist": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.0.1.tgz",
+      "integrity": "sha512-HuAt9bWDCdLkebrIQr+i63NgQSvjeD2VTNUIEBqof/4pG4Gb6omuBOMUX0vF371cbfImXQzmb4Ue/0c9MUWGew=="
+    },
+    "truncate-utf8-bytes": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
+      "integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=",
+      "dev": true,
+      "requires": {
+        "utf8-byte-length": "^1.0.1"
+      }
+    },
+    "tslib": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
+      "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
+      "dev": true
+    },
+    "tunnel": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+      "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+      "dev": true,
+      "optional": true
+    },
+    "tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "requires": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "type-fest": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz",
+      "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg=="
+    },
+    "typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+      "dev": true
+    },
+    "typedarray-to-buffer": {
+      "version": "3.1.5",
+      "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+      "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+      "requires": {
+        "is-typedarray": "^1.0.0"
+      }
+    },
+    "unique-string": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
+      "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==",
+      "dev": true,
+      "requires": {
+        "crypto-random-string": "^2.0.0"
+      }
+    },
+    "universalify": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+      "dev": true
+    },
+    "update-notifier": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.0.0.tgz",
+      "integrity": "sha512-p9zf71hWt5GVXM4iEBujpUgx8mK9AWiCCapEJm/O1z5ntCim83Z1ATqzZFBHFYqx03laMqv8LiDgs/7ikXjf/g==",
+      "dev": true,
+      "requires": {
+        "boxen": "^4.2.0",
+        "chalk": "^3.0.0",
+        "configstore": "^5.0.0",
+        "has-yarn": "^2.1.0",
+        "import-lazy": "^2.1.0",
+        "is-ci": "^2.0.0",
+        "is-installed-globally": "^0.3.1",
+        "is-npm": "^4.0.0",
+        "is-yarn-global": "^0.3.0",
+        "latest-version": "^5.0.0",
+        "semver-diff": "^3.1.1",
+        "xdg-basedir": "^4.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+          "dev": true,
+          "requires": {
+            "@types/color-name": "^1.1.1",
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "uri-js": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+      "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+      "requires": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "url-parse-lax": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
+      "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=",
+      "dev": true,
+      "requires": {
+        "prepend-http": "^2.0.0"
+      }
+    },
+    "utf8-byte-length": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",
+      "integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=",
+      "dev": true
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+    },
+    "validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "dev": true,
+      "requires": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
+    "which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "requires": {
+        "isexe": "^2.0.0"
+      }
+    },
+    "which-module": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+      "dev": true
+    },
+    "which-pm-runs": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
+      "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs="
+    },
+    "wide-align": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+      "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+      "requires": {
+        "string-width": "^1.0.2 || 2"
+      }
+    },
+    "widest-line": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
+      "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==",
+      "dev": true,
+      "requires": {
+        "string-width": "^4.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.0"
+          }
+        }
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+    },
+    "write-file-atomic": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.1.tgz",
+      "integrity": "sha512-JPStrIyyVJ6oCSz/691fAjFtefZ6q+fP6tm+OS4Qw6o+TGQxNp1ziY2PgS+X/m0V8OWhZiO/m4xSj+Pr4RrZvw==",
+      "requires": {
+        "imurmurhash": "^0.1.4",
+        "is-typedarray": "^1.0.0",
+        "signal-exit": "^3.0.2",
+        "typedarray-to-buffer": "^3.1.5"
+      }
+    },
+    "xdg-basedir": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
+      "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
+      "dev": true
+    },
+    "y18n": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+      "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+      "dev": true
+    },
+    "yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
+    },
+    "yargs-parser": {
+      "version": "16.1.0",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz",
+      "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==",
+      "dev": true,
+      "requires": {
+        "camelcase": "^5.0.0",
+        "decamelize": "^1.2.0"
+      }
+    },
+    "yauzl": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
+      "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
+      "dev": true,
+      "requires": {
+        "fd-slicer": "~1.0.1"
+      }
+    }
+  }
+}

+ 56 - 0
package.json

@@ -0,0 +1,56 @@
+{
+  "name": "bangbib",
+  "author": "hmt",
+  "description": "Schulbibliothek, bang, bang, bang",
+  "version": "1.0.0",
+  "main": "./build/main.js",
+  "private": true,
+  "scripts": {
+    "build": "rollup --config",
+    "start": "npm run build && run-s start:*",
+    "dev": "rollup -c && run-p dev:*",
+    "dist": "electron-builder",
+    "start:electron": "electron .",
+    "dev:development": "rollup --config --watch",
+    "dev:electron": "electron .",
+    "postinstall": "electron-builder install-app-deps"
+  },
+  "build": {
+    "appId": "im.hmt.bangbib",
+    "productName": "bangbib",
+    "artifactName": "bangbib.${ext}",
+    "files": [
+      "./build/**/*"
+    ],
+    "win": {
+      "icon": "icons/win/icon.ico",
+      "target": [
+        {
+          "target": "msi"
+        }
+      ]
+    }
+  },
+  "devDependencies": {
+    "electron": "^8.0.1",
+    "electron-builder": "^22.3.2",
+    "npm-run-all": "^4.1.5",
+    "prettier": "^1.19.1",
+    "prettier-plugin-svelte": "^0.7.0",
+    "rollup": "^1.31.1",
+    "rollup-plugin-commonjs": "^10.1.0",
+    "rollup-plugin-json": "^4.0.0",
+    "rollup-plugin-node-externals": "^2.1.3",
+    "rollup-plugin-node-resolve": "^5.2.0",
+    "rollup-plugin-svelte": "^5.1.1"
+  },
+  "dependencies": {
+    "better-sqlite3": "^6.0.1",
+    "bulma": "^0.8.0",
+    "electron-store": "^5.1.1",
+    "electron-util": "^0.14.0",
+    "ley": "^0.4.1",
+    "papaparse": "^5.1.1",
+    "svelte": "^3.19.1"
+  }
+}

+ 33 - 0
rollup.config.js

@@ -0,0 +1,33 @@
+import svelte from "rollup-plugin-svelte";
+import externals from 'rollup-plugin-node-externals'
+
+const production = process.env.NODE_ENV !== "development";
+
+export default [
+  {
+    input: [
+            "src/main.js",
+            "src/index.js"
+           ],
+    output: [
+      {
+        sourcemap: true,
+        dir: "build",
+        format: "cjs",
+      }
+    ],
+    plugins: [
+      svelte({
+        dev: !production,
+        css: css => {
+          css.write("build/bundle.css");
+        },
+      }),
+      externals({deps: true})
+    ],
+    onwarn (warning, warn) {
+      if (warning.code === 'CIRCULAR_DEPENDENCY') return;
+      warn(warning);
+    }
+  }
+];

+ 24 - 0
src/components/App.svelte

@@ -0,0 +1,24 @@
+<script>
+  import { print } from "./../stores.js";
+  import { db_check } from "./../database.js";
+  import Main from "./Main.svelte";
+  import Print from "./Print.svelte";
+</script>
+
+<style>
+  @import "../node_modules/bulma/css/bulma.css";
+</style>
+
+{#await db_check()} Öffne Datenbank …
+{:then connected}
+  {#if $print}
+    <Print />
+  {:else}
+    <Main />
+  {/if}
+{:catch e}
+  <br />
+  bangbib konnte nicht gestartet werden. Nicht gut. Datenbank ok?
+  <br>Diese Fehlermeldung gab es:
+  <pre>{e}</pre>
+{/await}

+ 134 - 0
src/components/Autocomplete.svelte

@@ -0,0 +1,134 @@
+<script>
+  import { view, schueler, db } from "./../stores.js";
+  import { get_kurs, get_schueler } from './../getter.js';
+  import Schueler from "./Schueler.svelte";
+  import Kurs from "./Kurs.svelte";
+
+  let input;
+  let term = "";
+  let res = [];
+  let selected = -1;
+  let items = [];
+  let show;
+
+  $: if (term.length > 1) {
+    selected = -1;
+    const schueler = $db
+      .prepare(
+        `SELECT *
+        FROM schueler
+        WHERE vorname || ' ' || name LIKE $term
+        OR name || ', ' || vorname LIKE $term`
+      )
+      .all({term: "%"+ term + "%"});
+    const kurse = $db
+      .prepare(
+        `SELECT DISTINCT k.kurs, s.klasse, s.jahr
+        FROM kurszugehoerigkeit AS k
+        JOIN schueler AS s ON (s.schild_id = k.schild_id)
+        WHERE kurs LIKE $term OR klasse LIKE $term`
+      )
+      .all({term: term + "%"});
+    const res_s = schueler.map(s => {
+      return { id: s.id, name: `${s.name}, ${s.vorname}`, schueler: true };
+    });
+    const res_k = kurse.map(k => {
+      return {
+        id: k.kurs,
+        name: `${k.kurs} – ${k.klasse}`,
+        klasse: k.klasse,
+        jahr: k.jahr
+      };
+    });
+    res = res_k.concat(res_s);
+  }
+  $: if (term.length < 2) res = [];
+  const key = e => {
+    if (e.key === "ArrowDown") selected += 1;
+    else if (e.key === "ArrowUp") selected -= 1;
+    else if (e.key === "Enter") {
+      show_selected(res[selected]);
+      return;
+    } else return;
+    if (selected > res.length - 1) selected = 0;
+    if (selected < 0) selected = res.length - 1;
+    e.preventDefault();
+    items[selected].scrollIntoView({ block: "center", inline: "nearest" });
+  };
+  const blur = _ => {
+    setTimeout(_ => (show = false), 500);
+  };
+
+  function show_selected(item) {
+    res = [];
+    selected = -1;
+    term = "";
+    input.blur();
+    // hole Schüler
+    if (item.schueler) {
+      get_schueler(item);
+      $view = Schueler;
+    }
+    // hole Kurs
+    else {
+      get_kurs(item);
+      $view = Kurs;
+    }
+  }
+</script>
+
+<style>
+  .wrapper {
+    position: relative;
+  }
+  .input {
+    width: 20rem;
+  }
+  .items {
+    position: absolute;
+    border: 1px solid #d4d4d4;
+    z-index: 99;
+    top: 100%;
+    left: 0;
+    right: 0;
+    max-height: 80vh;
+    overflow: auto;
+  }
+  .items div {
+    padding: 10px;
+    cursor: pointer;
+    background-color: #fff;
+    border-bottom: 1px solid #d4d4d4;
+  }
+  .items div:hover {
+    background-color: #e9e9e9;
+  }
+  .active {
+    background-color: DodgerBlue !important;
+    color: #ffffff;
+  }
+</style>
+
+<div class="wrapper">
+  <input
+    class="input"
+    type="text"
+    placeholder="suchen ..."
+    bind:this={input}
+    bind:value={term}
+    on:keydown={key}
+    on:blur={blur}
+    on:focus={() => (show = true)} />
+  {#if res.length && show}
+    <div class="items">
+      {#each res as r, i}
+        <div
+          on:click={() => show_selected(r)}
+          class:active={selected === i}
+          bind:this={items[i]}>
+          {r.name}
+        </div>
+      {/each}
+    </div>
+  {/if}
+</div>

+ 175 - 0
src/components/Einstellungen.svelte

@@ -0,0 +1,175 @@
+<script>
+  import { parse } from "papaparse";
+  import { configData, db } from "./../stores.js";
+  import * as notifier from './../notifier.js'
+
+  let datensatz_schueler = "",
+    datensatz_medien = "",
+    datensatz_sonstige = {nichtschueler: 1},
+    warten;
+
+  const update_sonstige = () => {
+    try {
+    $db.prepare(`
+      INSERT INTO schueler (name, vorname, nichtschueler, memo) VALUES(:name, :vorname, :nichtschueler, :memo)
+    `).run(datensatz_sonstige)
+    } catch (e) { console.log(e) }
+  }
+  const update_schueler = async () => {
+    warten = true;
+    const res = await parse(datensatz_schueler, {
+      comments: "#",
+      header: true
+    });
+    // id|name|vorname|jahr|klasse|kurs|kurs_lehrer
+    const values = res.data;
+    let schueler = {},
+      kurse = {};
+    values.forEach(v => {
+      schueler[v.id] = [
+        v.id,
+        v.jahr,
+        v.klasse,
+        v.name,
+        v.vorname
+      ];
+    });
+    const jahr = values[0].jahr
+    const schueler_values = Object.values(schueler)
+      .map(
+        a => `(${a[0]}, ${a[1]}, "${a[2]}", "${a[3]}", "${a[4]}")`
+      )
+      .join(",");
+    const kurszugehoerigkeit_values = values
+      .map(v => `(${v.id}, "${v.kurs_lehrer|''}", "${v.kurs||''}")`)
+      .join(",");
+    const query = [
+      `DELETE FROM schueler WHERE NOT EXISTS ( SELECT * FROM ausleihe WHERE ausleihe.schueler_id = schueler.id)`,
+      `INSERT INTO schueler (schild_id, jahr, klasse, name, vorname) VALUES ${schueler_values}
+        ON CONFLICT (schild_id) DO UPDATE SET jahr = ${jahr}`,
+      `DELETE FROM kurszugehoerigkeit`,
+      `INSERT INTO kurszugehoerigkeit (schild_id, kurs_lehrer, kurs) VALUES ${kurszugehoerigkeit_values}`
+    ];
+    try {
+      query.forEach(q => $db.prepare(q).run());
+      datensatz_schueler = ''
+      notifier.fertig('Schüler importiert')
+    } catch (e) {
+      notifier.fehler('Fehler beim Schülerimport:', e.message)
+      console.log(e)
+    }
+    warten = false;
+  };
+  const update_medien = async () => {
+    const res = await parse(datensatz_medien, { comments: "#" });
+    const values = res.data;
+    const medien = values.map(b => b[0]);
+    const insert = $db.prepare(
+      "INSERT INTO medienbezeichnung (name) VALUES (?)"
+    );
+    const insertMany = $db.transaction(medien => {
+      for (const medium of medien) insert.run(medium);
+    });
+    try {
+      insertMany(medien);
+      datensatz_medien = "";
+      notifier.fertig('Medientitel importiert')
+    } catch (e) {
+      notifier.fehler('Fehler beim Medienimport:', e.message)
+      console.log(e);
+    }
+  };
+</script>
+
+<div class="box">
+  <h3 class="title">Scan-Prefix</h3>
+  <div class="field">
+    <label class="label">
+      Scan-Prefix muss im Scanner einprogrammiert werden
+    </label>
+    <div class="control">
+      <input class="input" type="text" bind:value={$configData.scan_prefix} />
+    </div>
+  </div>
+</div>
+<div class="box">
+  <h3 class="title">Schüler, Kurse und Zugehörigkeiten importieren</h3>
+  <div class="field">
+    <label class="label">Achtung, die Nutzerdatenbank wird komplett geleert und mit den neuen Daten ersetzt. Ausgenommen sind säumige Nutzer und sonstige Nutzer.</label>
+    <div class="control">
+      <textarea
+        class="textarea"
+        bind:value={datensatz_schueler}
+        placeholder="Füge Daten mit Kopfzeile ein: id|name|vorname|jahr|klasse|kurs|kurs_lehrer"
+        rows="10"
+        cols="20" />
+    </div>
+  </div>
+  <div class="field is-grouped">
+    <div class="control">
+      <button
+        class="button is-{warten ? 'warning' : 'link'}"
+        class:is-loading={warten}
+        disabled={warten}
+        on:click={() => update_schueler()}>
+        Aktualisieren
+      </button>
+    </div>
+  </div>
+</div>
+<div class="box">
+  <h3 class="title">Sonstige Personen aufnehmen</h3>
+  <div class="field is-grouped">
+    <div class="control">
+      <input
+        class="input"
+        type="text"
+        placeholder="Name"
+        bind:value={datensatz_sonstige.name} />
+    </div>
+    <div class="control">
+      <input
+        class="input"
+        type="text"
+        placeholder="Vorname"
+        bind:value={datensatz_sonstige.vorname} />
+    </div>
+    <div class="control">
+      <input
+        class="input"
+        type="text"
+        placeholder="Bemerkungen"
+        bind:value={datensatz_sonstige.memo} />
+    </div>
+    <div class="control">
+      <button
+        class="button is-{warten ? 'warning' : 'link'}"
+        class:is-loading={warten}
+        disabled={warten}
+        on:click={() => update_sonstige()}>
+        Aktualisieren
+      </button>
+    </div>
+  </div>
+</div>
+<div class="box">
+  <h3 class="title">Medien importieren</h3>
+  <div class="field">
+    <label class="label">Medientitel importieren</label>
+    <div class="control">
+      <textarea
+        class="textarea"
+        bind:value={datensatz_medien}
+        placeholder="Je ein Titel pro Zeile"
+        rows="10"
+        cols="20" />
+    </div>
+  </div>
+  <div class="field is-grouped">
+    <div class="control">
+      <button class="button is-link" on:click={() => update_medien()}>
+        Aktualisieren
+      </button>
+    </div>
+  </div>
+</div>

+ 130 - 0
src/components/Kurs.svelte

@@ -0,0 +1,130 @@
+<script>
+  import Scanner from "./Scanner.svelte";
+  import { schueler, view, db, medien, titel, print } from "./../stores.js";
+  import * as notifier from "./../notifier.js";
+  import { DontBubbleException } from "./../exceptions.js";
+
+  function update() {
+    cur_schueler = iterator.next();
+    if (cur_schueler.done) {
+      notifier.fertig("Kurs vollständig versorgt");
+      $print = $view;
+    } else if (cur_schueler.value.gesperrt) {
+      console.log('Schüler gesperrt; nächster…')
+      update()
+    }
+  }
+
+  function zuordnung(barcode) {
+    if (!id) throw "Noch kein Titel festgelegt";
+    const res = $db
+      .prepare(
+        `
+      INSERT INTO medienexemplar (barcode, medienbezeichnung_id) VALUES (?,?)
+    `
+      )
+      .run(barcode, id);
+    if (res) {
+      notifier.zuordnung($titel, barcode);
+      ausleihe({ x_id: res.lastInsertRowid, barcode, m_id: id });
+    }
+  }
+
+  function rueckgabe(exemplar) {
+    const check = Object.values($medien).find(b => b === exemplar.barcode);
+    if (check) {
+      notifier.fehler("Kursbuchlöschung");
+      throw new DontBubbleException();
+    }
+    const res = $db
+      .prepare(
+        `
+      DELETE FROM ausleihe WHERE id = ?
+    `
+      )
+      .run(exemplar.ausleihe_id);
+    if (res) {
+      notifier.rueckgabe(exemplar.name, exemplar.barcode);
+      ausleihe(exemplar);
+    }
+  }
+
+  function ausleihe(exemplar) {
+    if (!check_referenz(exemplar)) throw new DontBubbleException();
+    const s = cur_schueler.value;
+    const data = {
+      jahr: s.jahr,
+      klasse: s.klasse,
+      schueler_id: s.id,
+      medienexemplar_id: exemplar.x_id,
+      kurs: s.kurs
+    };
+    const res = $db
+      .prepare(
+        `
+      INSERT INTO ausleihe
+      (jahr, klasse, schueler_id, medienexemplar_id, kurs)
+      VALUES (:jahr, :klasse, :schueler_id, :medienexemplar_id, :kurs)
+    `
+      )
+      .run(data);
+    if (res) {
+      $medien[s.id] = exemplar.barcode;
+      notifier.ausleihe(exemplar.name, exemplar.barcode);
+    }
+  }
+
+  let id,
+    cur_schueler = {};
+  let iterator = $schueler[Symbol.iterator]();
+  const scaninterface = { update, rueckgabe, ausleihe, zuordnung };
+
+  $: if ($schueler) {
+    console.log("Neue Schülergruppe");
+    $titel = null;
+    $medien = {};
+    iterator = $schueler[Symbol.iterator]();
+    update();
+  }
+
+  function check_referenz(e) {
+    if (!$titel) {
+      $titel = e.name;
+      id = e.m_id;
+    } else if (id !== e.m_id) {
+      notifier.fehler(`Falscher Titel: ${e.name}`, e.barcode);
+      return false;
+    }
+    return true;
+  }
+</script>
+
+{#if !$print}
+  <Scanner {scaninterface} />
+{/if}
+<h2 class="subtitle">
+  {$schueler[0].klasse} – {$schueler[0].kurs} - {$schueler[0].kurs_lehrer}
+</h2>
+<h2 class="subtitle">
+  {$titel || 'Lege einen Titel fest durch Scannen des ersten Buches'}
+</h2>
+<table class="table">
+  <thead>
+    <tr>
+      <th />
+      <th>Name</th>
+      <th>Vorame</th>
+      <th>Barcode</th>
+    </tr>
+  </thead>
+  <tbody>
+    {#each $schueler as s, i}
+      <tr>
+        <td>{i + 1}</td>
+        <td>{s.name}</td>
+        <td>{s.vorname}</td>
+        <td class:has-text-danger={s.gesperrt}>{s.gesperrt ? '– gesperrt –':''}{$medien[s.id] || ''}</td>
+      </tr>
+    {/each}
+  </tbody>
+</table>

+ 45 - 0
src/components/Main.svelte

@@ -0,0 +1,45 @@
+<script>
+  import { view } from './../stores.js';
+  import Navbar from "./Navbar.svelte";
+  import Medien from "./Medien.svelte";
+  import Messenger from "./Messenger.svelte";
+
+  $view = $view || Medien
+</script>
+
+<div class="grid-container">
+  <div class="main">
+    <section class="section">
+        <div class="columns">
+          <div class="column is-three-quarters">
+            <svelte:component this={$view}/>
+          </div>
+          <div class="column is-one-quarter" style="height:90vh; position: sticky; top: .2rem;">
+            <Messenger/>
+          </div>
+        </div>
+    </section>
+  </div>
+  <div class="header">
+    <Navbar />
+  </div>
+</div>
+
+<style>
+  .grid-container {
+    display: grid;
+    grid-template-columns: 250px 1fr;
+    grid-template-rows: 3.25rem calc(100vh - 3.25rem);
+    grid-template-areas: "header header" "main main";
+  }
+  .main {
+    grid-area: main;
+    overflow: auto;
+  }
+  .header {
+    grid-area: header;
+  }
+  ::-webkit-scrollbar {
+    display: none;
+  }
+</style>

+ 201 - 0
src/components/Medien.svelte

@@ -0,0 +1,201 @@
+<script>
+  import Scanner from "./Scanner.svelte";
+  import Medium from "./Medien.svelte";
+  import Schueler from "./Schueler.svelte";
+  import { view, db, print, medien } from "./../stores.js";
+  import { group_by } from "./../helpers.js";
+  import * as notifier from "./../notifier.js";
+  import { get_schueler } from "./../getter.js";
+
+  function update() {
+    $medien = $db
+      .prepare(
+        `
+      SELECT m.id AS medien_id,
+      m.name AS medien_name,
+      x.id AS exemplar_id,
+      x.barcode,
+      a.id AS verliehen,
+      s.name, s.vorname, s.klasse, s.jahr, s.id AS schueler_id
+      FROM medienbezeichnung AS m
+      LEFT JOIN medienexemplar AS x ON x.medienbezeichnung_id = m.id
+      LEFT JOIN ausleihe AS a ON a.medienexemplar_id = x.id
+      LEFT JOIN schueler AS s ON s.id = a.schueler_id
+    `
+      )
+      .all();
+  }
+  function rueckgabe(exemplar) {
+    console.log(exemplar);
+    const res = $db
+      .prepare(
+        `
+      DELETE FROM ausleihe WHERE id = ?
+    `
+      )
+      .run(exemplar.ausleihe_id);
+    if (res) {
+      notifier.rueckgabe(exemplar.name, exemplar.barcode);
+    }
+  }
+  function zuordnung(barcode) {
+    if (!modal) throw "Barcode unbekannt";
+    const res = $db
+      .prepare(
+        `
+      INSERT INTO medienexemplar (barcode, medienbezeichnung_id) VALUES (?,?)
+    `
+      )
+      .run(barcode, medien_filter[selected][0].medien_id);
+    console.log(res);
+    if (res) {
+      update();
+      notifier.zuordnung(medien_filter[selected][0].medien_name, barcode);
+    }
+  }
+  let selected,
+    suche = "",
+    modal = false,
+    neuer_titel = "",
+    add = false;
+
+  const add_medienbezeichnung = _ => {
+    const res = $db
+      .prepare(
+        `
+      INSERT INTO medienbezeichnung (name) VALUES (?)
+    `
+      )
+      .run(neuer_titel);
+    neuer_titel = "";
+    add = false;
+    update();
+  };
+  const schueler_action = s => {
+    if (s.verliehen) {
+      get_schueler({ id: s.schueler_id });
+      $view = Schueler;
+    }
+  };
+  const focus = node => node.focus();
+  update();
+
+  $: medien_filter = group_by(
+    $medien.filter(
+      m =>
+        m.medien_name.toLowerCase().includes(suche.toLowerCase()) ||
+        (m.barcode && m.barcode.toLowerCase().includes(suche.toLowerCase()))
+    ),
+    "medien_id"
+  );
+  $: Object.keys(medien_filter).length === 1 &&
+    (selected = Object.keys(medien_filter)[0]);
+  const scaninterface = { update, rueckgabe, zuordnung };
+</script>
+
+{#if !$print}
+  <Scanner {scaninterface} />
+{/if}
+<h2 class="title">Verfügbare Medien</h2>
+<div class="field">
+  <div class="control">
+    <input class="input" type="text" placeholder="Filter" bind:value={suche} />
+  </div>
+</div>
+<div class="columns">
+  <div class="column">
+    <button
+      class="button is-fullwidth is-primary"
+      on:click={() => (add = true)}>
+      Medium hinzufügen
+    </button>
+    {#if add}
+      <div class="field">
+        <label class="label">Medien-Titel</label>
+        <div class="control">
+          <input
+            class="input"
+            type="text"
+            bind:value={neuer_titel}
+            use:focus
+            on:keydown={e => e.key === 'Enter' && add_medienbezeichnung()} />
+        </div>
+      </div>
+    {/if}
+    {#if Object.keys(medien_filter).length}
+      <table class="table">
+        <thead>
+          <tr>
+            <th>ID</th>
+            <th>Titel</th>
+            <th>V/G</th>
+            <th />
+          </tr>
+        </thead>
+        <tbody>
+          {#each Object.entries(medien_filter) as [n, m], i}
+            <tr
+              class="pointer"
+              on:mouseover={() => (selected = n)}
+              on:click={() => (modal = true)}>
+              <td>{m[0].medien_id}</td>
+              <td>{m[0].medien_name}</td>
+              <td>
+                {m.filter(i => i.verliehen).length}/{m.filter(i => i.exemplar_id).length}
+              </td>
+              <td />
+            </tr>
+          {/each}
+        </tbody>
+      </table>
+    {:else}– Bibliothek? Es sind noch keine Medien eingetragen –
+    {/if}
+  </div>
+  <div class="column" style="height:90vh; position: sticky; top: .2rem;">
+    {#if selected && Object.keys(medien_filter).length && medien_filter[selected]}
+      <div class="card">
+        <header class="card-header">
+          <p class="card-header-title">
+            {medien_filter[selected][0].medien_name}
+          </p>
+        </header>
+        <div class="card-content">
+          <div class="content">
+            {#if medien_filter[selected].filter(i => i.exemplar_id).length}
+              <table class="table">
+                <thead>
+                  <tr>
+                    <th>Barcode</th>
+                    <th>Schüler</th>
+                    <th>Klasse</th>
+                    <th>Jahr</th>
+                  </tr>
+                </thead>
+                <tbody>
+                  {#each medien_filter[selected].sort((a, b) => b.jahr - a.jahr) as s}
+                    <tr
+                      class="pointer"
+                      class:has-background-success={medien_filter[selected].length === 1 && s.barcode && s.barcode.toLowerCase() === suche.toLowerCase()}
+                      on:click={() => schueler_action(s)}>
+                      <td>{s.barcode}</td>
+                      {#if s.verliehen}
+                        <td>{s.name}, {s.vorname}</td>
+                        <td>{s.klasse || '–'}</td>
+                        <td>{s.jahr || '–'}</td>
+                      {:else}
+                        <td colspan="4" />
+                      {/if}
+                    </tr>
+                  {/each}
+                </tbody>
+              </table>
+            {:else}Noch keine Exemplare vorhanden{/if}
+          </div>
+        </div>
+      </div>
+    {/if}
+  </div>
+</div>
+{#if modal}
+  <Medium medium={medien_filter[selected]} bind:modal {update} />
+{/if}

+ 110 - 0
src/components/Medium.svelte

@@ -0,0 +1,110 @@
+<script>
+  import { db } from "./../stores.js";
+  export let medium = [];
+  export let modal;
+  export let update
+  let suche = "";
+  let yes
+  $: medien_filter = medium.filter(m =>
+    m.barcode && m.barcode.toLowerCase().includes(suche.toLowerCase())
+  );
+  const edit = _ => {
+    const m = medium[0]
+    const res = $db.prepare(`
+      UPDATE medienbezeichnung SET name=? WHERE id = ?
+    `).run(m.medien_name, m.medien_id)
+    if (res) update()
+    else console.log('Es gabe einen Fehler beim Ändern der Medienbezeichnung')
+  };
+  const remove_medium = _ => {
+    const res = $db.prepare(`
+      DELETE FROM medienbezeichnung WHERE id = ?
+    `).run(medium[0].medien_id)
+    if (res) {
+      update()
+      modal = false
+    }
+    else console.log('Es gabe einen Fehler beim Löschen des Mediums')
+  };
+  const remove_exemplar = e => {
+    const res = $db.prepare(`
+      DELETE FROM medienexemplar WHERE id = ?
+    `).run(e.exemplar_id)
+    if (res) update()
+    else console.log('Es gabe einen Fehler beim Löschen des Exemplars')
+  };
+</script>
+
+<svelte:window on:keydown={e => (e.key === 'Escape') && (modal = false)}/>
+<div class="modal" class:is-active={modal}>
+  <div class="modal-background" on:click={()=>modal=false}/>
+  <button class="modal-close is-large" aria-label="close" on:click={()=>modal=false}></button>
+  <div class="modal-content">
+    <div class="box">
+      <div class="field">
+        <label class="label">Medien-Titel</label>
+        <div class="control">
+          <input
+            class="input"
+            type="text"
+            bind:value={medium[0].medien_name}
+            on:keydown={e => e.key === 'Enter' && edit()} />
+        </div>
+      </div>
+      {#if yes}
+        <button class="button is-small is-fullwidth is-danger" on:click={()=>remove_medium()}>Medium löschen</button>
+      {:else}
+        <div class="field">
+          <label class="checkbox is-danger">
+          <input type="checkbox" bind:checked={yes}> Entfernen aktivieren. Alle Exemplare und Leihgaben dieses Mediums werden gelöscht.</label>
+        </div>
+      {/if}
+      <hr />
+      Füge neue Exemplare durch einscannen neuer Barcodes diesem Titel hinzu. Bereits vergebene Barcodes müssen erst gelöscht werden.
+      <div class="field">
+        <div class="control">
+          <input
+            class="input"
+            type="text"
+            placeholder="Filter"
+            bind:value={suche} />
+        </div>
+      </div>
+      <table class="table is-striped is-hoverable" width="100%">
+        <thead>
+          <tr>
+            <th>Barcode</th>
+            <th>Schüler</th>
+            <th>Klasse</th>
+            <th>Jahr</th>
+            <th>Löschen</th>
+          </tr>
+        </thead>
+        <tbody>
+          {#each medien_filter.sort((a, b) => a.barcode - b.barcode) as e}
+            <tr>
+              <td>{e.barcode}</td>
+              {#if e.verliehen}
+                <td>{e.name}, {e.vorname}</td>
+                <td>{e.klasse}</td>
+                <td>{e.jahr}</td>
+              {:else}
+                <td colspan="3" />
+              {/if}
+              <td align="center">
+                <span class="icon has-text-danger pointer">
+                  <i
+                    class="mdi"
+                    alt="Exemplar löschen"
+                    on:click={() => remove_exemplar(e)}>
+                    delete_forever
+                  </i>
+                </span>
+              </td>
+            </tr>
+          {/each}
+        </tbody>
+      </table>
+    </div>
+  </div>
+</div>

+ 60 - 0
src/components/Messenger.svelte

@@ -0,0 +1,60 @@
+<script>
+  import { notification } from "./../stores.js";
+  import { onDestroy } from "svelte";
+  import { fade } from "svelte/transition";
+
+  export let timeout = 20000;
+  let count = 0;
+  let toasts = [];
+  let unsubscribe;
+
+  function createToast(icon, msg, theme, to, barcode) {
+    const background = theme || "";
+    toasts = [
+      {
+        id: count,
+        msg,
+        icon,
+        barcode,
+        background,
+        timeout: to || timeout,
+        width: "100%"
+      },
+      ...toasts
+    ];
+    count = count + 1;
+  }
+  function removeToast(id) {
+    setTimeout(_ => (toasts = toasts.filter(t => t.id != id)), 10000);
+  }
+
+  unsubscribe = notification.subscribe(value => {
+    if (!value) {
+      return;
+    }
+    createToast(
+      value.icon,
+      value.message,
+      value.type,
+      value.timeout,
+      value.barcode
+    );
+    notification.set();
+  });
+  onDestroy(unsubscribe);
+</script>
+
+{#each toasts as toast (toast.id)}
+  <article
+    class="message is-{toast.background}"
+    use={removeToast(toast.id)}
+    out:fade>
+    <div class="message-header">
+      <span class="icon">
+        <i class="mdi">{toast.icon}</i>
+      </span>
+      {toast.barcode || ''}
+    </div>
+    <div class="message-body">{toast.msg}</div>
+  </article>
+{/each}

+ 75 - 0
src/components/Navbar.svelte

@@ -0,0 +1,75 @@
+<script>
+  import Autocomplete from "./Autocomplete.svelte";
+  import Medien from "./Medien.svelte";
+  import Nutzer from "./Nutzer.svelte"
+  import Kurs from "./Kurs.svelte";
+  import Schueler from "./Schueler.svelte";
+  import Einstellungen from "./Einstellungen.svelte";
+  import { view, print, scan_status } from "./../stores.js";
+
+  const print_allowed = [Medien, Schueler, Kurs];
+</script>
+
+<style>
+  .brand {
+    text-transform: uppercase;
+    padding-right: 10px;
+    cursor: pointer;
+  }
+  .button {
+    margin-right: 0.4rem;
+    margin-left: 0.4rem;
+  }
+</style>
+
+<nav class="navbar is-link">
+  <div class="navbar-item">
+    <div
+      class="has-text-white-ter brand is-size-7"
+      on:click={() => ($view = Medien)}>
+      <b>Bangbib</b>
+    </div>
+    <Autocomplete />
+  </div>
+  <div class="navbar-item">
+    <button class="button is-link">
+      <span class="icon">
+        <i class="mdi" on:click={() => ($view = Medien)}>book</i>
+      </span>
+    </button>
+  </div>
+  <div class="navbar-item">
+    <button class="button is-link">
+      <span class="icon">
+        <i class="mdi" on:click={() => ($view = Nutzer)}>people</i>
+      </span>
+    </button>
+  </div>
+  <div class="navbar-item">
+    <button class="button is-link" disabled={!print_allowed.includes($view)}>
+      <span class="icon">
+        <i class="mdi" on:click={() => ($print = $view)}>print</i>
+      </span>
+    </button>
+  </div>
+  <div class="navbar-end">
+    <div class="navbar-item">
+      <span class="icon is-medium" class:has-background-grey={!$scan_status.rueckgabe} class:has-background-info={$scan_status.rueckgabe}>
+        <i class="mdi">arrow_back</i>
+      </span>
+      <span class="icon is-medium" class:has-background-grey={!$scan_status.ausleihe} class:has-background-warning={$scan_status.ausleihe}>
+        <i class="mdi">arrow_forward</i>
+      </span>
+      <span class="icon is-medium" class:has-background-grey={!$scan_status.zuordnung} class:has-background-success={$scan_status.zuordnung}>
+        <i class="mdi">plus_one</i>
+      </span>
+    </div>
+    <div class="navbar-item">
+      <button class="button is-link">
+        <span class="icon">
+          <i class="mdi" on:click={() => ($view = Einstellungen)}>settings</i>
+        </span>
+      </button>
+    </div>
+  </div>
+</nav>

+ 109 - 0
src/components/Nutzer.svelte

@@ -0,0 +1,109 @@
+<script>
+  import Schueler from "./Schueler.svelte";
+  import { view, db, print } from "./../stores.js";
+  import { group_by } from "./../helpers.js";
+  import { get_schueler } from "./../getter.js";
+
+  let active;
+  let klasse;
+  function ausleiher() {
+    const res = $db
+      .prepare(
+        `
+      SELECT DISTINCT s.name, s.vorname, s.klasse, s.id
+      FROM ausleihe AS a
+      LEFT JOIN medienexemplar AS x ON (x.id = a.medienexemplar_id)
+      LEFT JOIN medienbezeichnung AS m ON (m.id = x.medienbezeichnung_id)
+      LEFT JOIN schueler AS s ON (s.id = a.schueler_id)
+    `
+      )
+      .all();
+    active = 1;
+    return group_by(res, "klasse");
+  }
+  function ausleiher_vorjahr() {
+    const res = $db
+      .prepare(
+        `
+      SELECT DISTINCT s.name, s.vorname, s.klasse, s.id
+      FROM ausleihe AS a
+      LEFT JOIN medienexemplar AS x ON (x.id = a.medienexemplar_id)
+      LEFT JOIN medienbezeichnung AS m ON (m.id = x.medienbezeichnung_id)
+      LEFT JOIN schueler AS s ON (s.id = a.schueler_id)
+      WHERE a.jahr != s.jahr
+    `
+      )
+      .all();
+    active = 2;
+    return group_by(res, "klasse");
+  }
+  function nutzer_gesperrt() {
+    const res = $db
+      .prepare(
+        `
+      SELECT s.name, s.vorname, s.id, s.klasse
+      FROM schueler AS s
+      WHERE s.gesperrt = 1;
+    `
+      )
+      .all();
+    active = 3;
+    return group_by(res, "klasse");
+  }
+</script>
+
+<!-- svelte-ignore a11y-missing-attribute -->
+<div class="tabs is-boxed">
+  <ul>
+    <li class:is-active={active === 1} on:click={_ => (klasse = ausleiher())}>
+      <a>
+        <span>Nutzer mit Ausleihe</span>
+      </a>
+    </li>
+    <li
+      class:is-active={active === 2}
+      on:click={_ => (klasse = ausleiher_vorjahr())}>
+      <a>
+        <span>Nutzer mit Ausleihe aus Vorjahren</span>
+      </a>
+    </li>
+    <li
+      class:is-active={active === 3}
+      on:click={_ => (klasse = nutzer_gesperrt())}>
+      <a>
+        <span>Gesperrte Nutzer</span>
+      </a>
+    </li>
+  </ul>
+</div>
+{#if klasse}
+  <div class="box">
+    {#each Object.entries(klasse) as [k, schueler]}
+      <h2 class="title">{k}</h2>
+      <table class="table">
+        <thead>
+          <tr>
+            <th />
+            <th>Name</th>
+            <th>Vorame</th>
+          </tr>
+        </thead>
+        <tbody>
+          {#each schueler as s, i}
+            <tr
+              class="pointer"
+              on:click={_ => {
+                get_schueler({ id: s.id });
+                $view = Schueler;
+              }}>
+              <td>{i + 1}</td>
+              <td>{s.name}</td>
+              <td>{s.vorname}</td>
+            </tr>
+          {/each}
+        </tbody>
+      </table>
+    {:else} – Keine Nutzer eingetragen bisher –
+    {/each}
+  </div>
+{/if}

+ 28 - 0
src/components/Print.svelte

@@ -0,0 +1,28 @@
+<script>
+  import { schueler, medien, titel, print } from "./../stores.js";
+  import { ipcRenderer } from 'electron'
+  import PrintKurs from './Print/Kurs.svelte'
+  import PrintSchueler from './Print/Schueler.svelte'
+  import PrintMedien from './Print/Medien.svelte'
+
+  let c
+
+  ipcRenderer.on('asynchronous-reply', (event, arg) => {
+    console.log('Print: ', arg)
+  })
+
+  function handle_keydown(event) {
+    if (event.key === "Escape") $print = false;
+    if (event.key === 'p') ipcRenderer.send('print', 'print')
+  }
+
+  $: if ($print.name === 'Schueler') c = PrintSchueler
+     else if ($print.name === 'Kurs') c = PrintKurs;
+     else if ($print.name === 'Medien') c = PrintMedien;
+</script>
+
+<svelte:window on:keydown={handle_keydown} />
+
+{#if c}
+  <svelte:component this={c} />
+{/if}

+ 44 - 0
src/components/Print/Kurs.svelte

@@ -0,0 +1,44 @@
+<script>
+  import { schueler, medien, titel } from "./../../stores.js";
+  import { chunk } from "./../../helpers.js";
+
+  const anzahl = 30;
+</script>
+
+{#each chunk($schueler, anzahl) as slice, i}
+  <div class="page grid" orientation="portrait" size="A4">
+    <div class="main">
+      <h2 class="subtitle">
+        {$schueler[0].klasse} – {$schueler[0].kurs} – {$schueler[0].kurs_lehrer}
+        – {new Date().toLocaleDateString('de', {
+          day: '2-digit',
+          month: '2-digit',
+          year: 'numeric'
+        })}
+      </h2>
+      <h2 class="subtitle">{$titel || ''}</h2>
+      <table class="table">
+        <thead>
+          <tr>
+            <th />
+            <th>Name</th>
+            <th>Vorame</th>
+            <th>Barcode</th>
+            <th>Unterschrift</th>
+          </tr>
+        </thead>
+        <tbody>
+          {#each slice as s, ii}
+            <tr>
+              <td>{i * anzahl + ii + 1}</td>
+              <td>{s.name}</td>
+              <td>{s.vorname}</td>
+              <td>{s.gesperrt ? '– gesperrt –':''}{$medien[s.id] || ''}</td>
+              <td />
+            </tr>
+          {/each}
+        </tbody>
+      </table>
+    </div>
+  </div>
+{/each}

+ 39 - 0
src/components/Print/Medien.svelte

@@ -0,0 +1,39 @@
+<script>
+  import { medien } from "./../../stores.js";
+  import { group_by, chunk } from "./../../helpers.js";
+
+  const anzahl = 30;
+  $: medien_filter = group_by($medien, "medien_id");
+</script>
+
+{#each chunk(Object.entries(medien_filter), anzahl) as slice, i}
+  <div class="page grid" orientation="portrait" size="A4">
+    <div class="main">
+      <h2 class="subtitle">
+        Verfügbare Medien – {new Date().toLocaleDateString('de', { day: '2-digit', month: '2-digit', year: 'numeric' })}
+      </h2>
+      {#if $medien.length}
+        <table class="table">
+          <thead>
+            <tr>
+              <th />
+              <th>Titel</th>
+              <th>Verliehen/Gesamtbestand</th>
+            </tr>
+          </thead>
+          <tbody>
+            {#each slice as [n, m], ii}
+              <tr>
+                <td>{i * anzahl + ii + 1}</td>
+                <td>{m[0].medien_name}</td>
+                <td>
+                  {m.filter(i => i.verliehen).length}/{m.filter(i => i.exemplar_id).length}
+                </td>
+              </tr>
+            {/each}
+          </tbody>
+        </table>
+      {:else}– Bibliothek? Es sind noch keine Medien eingetragen –{/if}
+    </div>
+  </div>
+{/each}

+ 44 - 0
src/components/Print/Schueler.svelte

@@ -0,0 +1,44 @@
+<script>
+  import { schueler, medien, titel } from "./../../stores.js";
+  import { group_by, chunk } from "./../../helpers.js";
+  const s = $schueler[0];
+  const anzahl = 30;
+</script>
+
+{#each chunk($medien, anzahl) as slice, i}
+  <div class="page grid" orientation="portrait" size="A4">
+    <div class="main">
+      <h2 class="subtitle">
+        {`${s.name}, ${s.vorname}`}
+        {#if s.klasse}– {s.klasse}{/if}
+        <br />
+        {new Date().toLocaleDateString('de', {
+          day: '2-digit',
+          month: '2-digit',
+          year: 'numeric'
+        })}
+      </h2>
+      <i>{s.memo || ''}</i>
+      {#if $medien.length}
+        <table class="table">
+          <thead>
+            <tr>
+              <th />
+              <th>Titel</th>
+              <th>Barcode</th>
+            </tr>
+          </thead>
+          <tbody>
+            {#each slice as m, ii}
+              <tr>
+                <td>{i * anzahl + ii + 1}</td>
+                <td>{m.name}</td>
+                <td>{m.barcode}</td>
+              </tr>
+            {/each}
+          </tbody>
+        </table>
+      {:else}– Keine Medien geliehen –{/if}
+    </div>
+  </div>
+{/each}

+ 158 - 0
src/components/Scanner.svelte

@@ -0,0 +1,158 @@
+<script>
+  import { configData, db, scan_status } from "./../stores.js";
+  import { DontBubbleException } from './../exceptions.js'
+ 	import { onDestroy } from 'svelte';
+	onDestroy(() => $scan_status = {})
+
+  export let scaninterface
+  const { update, ausleihe, rueckgabe, zuordnung } = scaninterface
+  $scan_status = { ausleihe, rueckgabe, zuordnung }
+
+  const prefix_length = $configData.scan_prefix.length;
+  let buffer = [],
+    barcode,
+    registrieren,
+    lastKeyTime = Date.now(),
+    medium,
+    neuer_titel = "",
+    medium_selected;
+
+  function handle_keydown(event) {
+    if (registrieren) {
+      (event.key === 'Escape') && (registrieren = false)
+      return
+    }
+    if (
+      event.key === "Enter" &&
+      buffer.slice(0, prefix_length).join("") === $configData.scan_prefix
+    ) {
+      barcode = buffer.slice(prefix_length).join("");
+      buffer = [];
+      scan();
+    } else {
+      const charList = "abcdefghijklmnopqrstuvwxyz0123456789";
+      const key = event.key.toLowerCase();
+      if (charList.indexOf(key) === -1) return;
+      const currentTime = Date.now();
+      if (currentTime - lastKeyTime > 1000) buffer = [];
+      buffer.push(event.key);
+      lastKeyTime = currentTime;
+    }
+  }
+
+  function scan() {
+    const res = $db
+      .prepare(
+        `
+      SELECT x.barcode, x.id AS x_id, m.name, m.id AS m_id, x.medienbezeichnung_id, a.*, a.id AS ausleihe_id
+      FROM medienexemplar x
+      LEFT JOIN medienbezeichnung AS m ON (x.medienbezeichnung_id = m.id)
+      LEFT JOIN ausleihe AS a ON (a.medienexemplar_id = x.id)
+      WHERE barcode = ?
+    `
+      )
+      .get(barcode);
+    console.log(res);
+    if (!res) {
+      try {
+        zuordnung(barcode);
+      } catch (e) {
+        medium = $db.prepare(`SELECT * FROM medienbezeichnung`).all();
+        registrieren = true
+        console.log(e, "Zuordnung ist hier nicht möglich, Medium registrieren");
+        return
+      }
+    } else if (res.ausleihe_id) {
+      try {
+        rueckgabe(res);
+      } catch (e) {
+        if (e instanceof DontBubbleException) return
+        console.log(e, "Rückgabe ist hier nicht möglich");
+      }
+    } else {
+      try {
+        ausleihe(res);
+      } catch (e) {
+        if (e instanceof DontBubbleException) return
+        console.log("Ausleihe ist hier nicht möglich");
+      }
+    }
+    try {
+      update();
+    } catch (e) {
+      console.log("Ausgeliehene Medien konnten nicht aktualisiert werden");
+    }
+  }
+
+  function neu_anlegen() {
+    if (!neuer_titel.length) return
+    const res = $db
+      .prepare(
+        `
+      INSERT INTO medienbezeichnung (name) VALUES (?)
+    `
+      )
+      .run(neuer_titel);
+      neuer_titel = ''
+      zuordnen(res.lastInsertRowid)
+  }
+
+  function zuordnen(medien_id) {
+    if (!medien_id) return
+    const res = $db
+      .prepare(
+        `
+      INSERT INTO medienexemplar (barcode, medienbezeichnung_id) VALUES (?,?)
+    `
+      )
+      .run(barcode, medien_id);
+    registrieren = false;
+    scan()
+  }
+</script>
+
+<svelte:window on:keydown={handle_keydown} />
+
+{#if registrieren}
+  <div class="modal is-active">
+    <div class="modal-background" on:click={()=>registrieren=false}/>
+    <button class="modal-close is-large" aria-label="close" on:click={()=>registrieren=false}></button>
+    <div class="modal-content">
+      <div class="box">
+        Was machen wir mit dem Barcode?
+        <pre>{barcode}</pre>
+        <hr />
+        <label class="label">Das gehört zu</label>
+        <div class="field has-addons">
+          <div class="control is-expanded">
+            <div class="select is-fullwidth">
+              <select bind:value={medium_selected}>
+                <option>– nichts ausgewählt –</option>
+                {#each medium as m}
+                  <option value={m.id}>{m.name}</option>
+                {/each}
+              </select>
+            </div>
+          </div>
+          <div class="control">
+            <button
+              class="button is-primary"
+              on:click={() => zuordnen(medium_selected)}>
+              Titel verwenden
+            </button>
+          </div>
+        </div>
+        <div class="field">
+          <label class="label">Neu anlegen unter</label>
+          <div class="control">
+            <input
+              class="input"
+              type="text"
+              bind:value={neuer_titel}
+              on:keydown={e => e.key === 'Enter' && neu_anlegen()} />
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+{/if}

+ 133 - 0
src/components/Schueler.svelte

@@ -0,0 +1,133 @@
+<script>
+  import Medien from "./Medien.svelte";
+  import Scanner from "./Scanner.svelte";
+  import * as notifier from './../notifier.js'
+  import { view, schueler, db, medien, print } from './../stores.js';
+  import { group_by } from './../helpers.js'
+
+  function update () {
+    $medien = $db.prepare(`
+      SELECT a.*, x.*, m.*, a.id AS ausleihe_id
+      FROM ausleihe as a
+      LEFT JOIN medienexemplar AS x ON (x.id = a.medienexemplar_id)
+      LEFT JOIN medienbezeichnung AS m ON (m.id = x.medienbezeichnung_id)
+      WHERE a.schueler_id = ?`
+    ).all($schueler[0].id) || []
+  }
+
+  function rueckgabe (exemplar) {
+    const res = $db.prepare(`
+      DELETE FROM ausleihe WHERE id = ?
+    `).run(exemplar.ausleihe_id)
+    if (res) {
+      notifier.rueckgabe(exemplar.name, exemplar.barcode)
+      if (exemplar.schueler_id !== s.id) ausleihe(exemplar)
+    }
+    return res
+  }
+
+  function ausleihe (exemplar) {
+    if (s.gesperrt) throw 'Nutzer gesperrt'
+    const data = {
+      jahr: s.jahr,
+      klasse: s.klasse,
+      schueler_id: s.id,
+      medienexemplar_id: exemplar.x_id,
+      kurs: s.kurs
+    }
+    const res = $db.prepare(`
+      INSERT INTO ausleihe
+      (jahr, klasse, schueler_id, medienexemplar_id, kurs)
+      VALUES (:jahr, :klasse, :schueler_id, :medienexemplar_id, :kurs)
+    `).run(data)
+    if (res) {
+      notifier.ausleihe(exemplar.name, exemplar.barcode)
+    }
+  }
+  function zuordnung () {
+    throw 'Verwende Standardzuordnung'
+  }
+  const scaninterface = {update, rueckgabe, ausleihe, zuordnung}
+
+  $: s = $schueler[0]
+  $: s && update()
+  let yes
+
+  const remove_schueler = _ => {
+    const res = $db.prepare(`
+      DELETE FROM schueler WHERE id = ?
+    `).run(s.id)
+    if (res) { $view = Medien }
+  }
+  const suspend_schueler = _ => {
+    const res = $db.prepare(`
+      UPDATE schueler SET gesperrt=? WHERE id = ?
+    `).run(s.gesperrt ? 0 : 1, s.id)
+    if (res) s.gesperrt = s.gesperrt ? 0 : 1
+  }
+  const edit_memo = _ => {
+    const res = $db.prepare(`
+      UPDATE schueler SET memo=? WHERE id = ?
+    `).run(s.memo, s.id)
+  }
+</script>
+
+{#if !$print}
+  <Scanner {scaninterface} />
+{/if}
+<h2 class="title">{s.name}, {s.vorname}</h2>
+<h2 class="sub-title">{s.klasse || 'Sonstiger Nutzer'}</h2>
+<div class="field">
+  {#if yes}
+    <button class="button is-danger" on:click={()=>remove_schueler()}>Schüler aus Datenbank löschen</button>
+  {:else}
+    <label class="checkbox is-danger">
+    <input type="checkbox" bind:checked={yes}> Löschen aktivieren. Der Schüler und alle Leihgaben können aus der Datenbank gelöscht werden.</label>
+  {/if}
+</div>
+<div class="field">
+  <button class="button" class:is-warning={s.gesperrt} class:is-success={!s.gesperrt} on:click={()=>suspend_schueler()}>Schüler {s.gesperrt ? 'ent':''}sperren</button>
+</div>
+<div class="field">
+  <label class="label">Memo</label>
+  <div class="control">
+    <input
+      class="input"
+      type="text"
+      bind:value={s.memo}
+      on:keydown={e => e.key === 'Enter' && edit_memo()} />
+  </div>
+</div>
+
+{#if $medien.length}
+  <table class="table">
+    <thead>
+      <tr>
+        <th></th>
+        <th>Titel</th>
+        <th>Barcode</th>
+        <th>Rückgabe</th>
+      </tr>
+    </thead>
+    <tbody>
+      {#each $medien as m,i}
+        <tr>
+          <td>{i+1}</td>
+          <td>{m.name}</td>
+          <td>{m.barcode}</td>
+          <td align="center">
+            <span class="icon has-text-danger pointer">
+              <i
+                class="mdi"
+                alt="Exemplar löschen"
+                on:click={() => rueckgabe(m) && update()}>
+                delete_forever
+              </i>
+            </span>
+          </td>
+        </tr>
+      {/each}
+    </tbody>
+  </table>
+{:else} – Keine Medien geliehen –
+{/if}

+ 11 - 0
src/configstore.js

@@ -0,0 +1,11 @@
+import Store from 'electron-store'
+
+const configFile = new Store({
+  defaults: {
+    windowBounds: {
+      main: { width: 1800, height: 800 }
+    },
+    scan_prefix: 'AAA'
+  }
+});
+export default configFile

+ 39 - 0
src/database.js

@@ -0,0 +1,39 @@
+import { api } from "electron-util";
+import { ipcRenderer } from "electron";
+import { db } from "./stores.js";
+import { join } from "path";
+import { get } from "svelte/store";
+const Database = require("better-sqlite3");
+const ley = require("ley");
+
+const userData = api.app.getPath("userData");
+const db_file = join(userData, "datenbank.sqlite");
+const ley_opts = { config: { database: db_file }, dir: "src/migrations" };
+
+export async function db_check() {
+  try {
+    db.set(new Database(db_file, { fileMustExist: true }));
+  } catch (e) {
+    console.log("Datenbank existiert nicht, wird angelegt…");
+    try {
+      db.set(new Database(db_file));
+    } catch (e) {
+      console.log(e);
+      throw "Datenbank konnte nicht erstellt werden";
+    }
+  }
+  try {
+    const successes = await ley.up(ley_opts);
+    if (successes.length) console.log("Erfolgreich migriert: ", successes);
+  } catch (e) {
+    await ley.down(ley_opts);
+    console.log("Es gab einen Fehler bei der Migration: ", e);
+    throw e;
+  }
+  ipcRenderer.on("close_db", (event, message) => {
+    try {
+      get(db).close();
+      console.log("schließe Datenbank…");
+    } catch (e) { console.log('Datenbank konnte nicht geschlossen werden: ',e)}
+  });
+}

+ 4 - 0
src/exceptions.js

@@ -0,0 +1,4 @@
+  export function DontBubbleException () {
+    this.message = 'Kursbuchlöschung'
+  }
+

+ 27 - 0
src/getter.js

@@ -0,0 +1,27 @@
+import { get } from 'svelte/store';
+import { schueler, db } from "./stores.js";
+  export function get_schueler (item) {
+    const res = get(db)
+      .prepare(
+        `
+      SELECT s.*
+      FROM schueler AS s
+      WHERE s.id = ?
+    `
+      )
+      .all(item.id);
+    schueler.set(res)
+  };
+  export function get_kurs (item) {
+    const res = get(db)
+      .prepare(
+        `
+      SELECT s.*, k.kurs, k.kurs_lehrer
+      FROM kurszugehoerigkeit AS k
+      LEFT JOIN schueler AS s ON (k.schild_id = s.schild_id)
+      WHERE k.kurs = ? AND s.klasse = ? AND s.jahr = ?
+    `
+      )
+      .all(item.id, item.klasse, item.jahr);
+    schueler.set(res)
+  };

+ 12 - 0
src/helpers.js

@@ -0,0 +1,12 @@
+  export const group_by = (array, key) => {
+    return array.reduce((result, currentValue) => {
+      (result[currentValue[key]] = result[currentValue[key]] || []).push(
+        currentValue
+      );
+      return result;
+    }, {});
+  };
+  export const chunk = (arr, size) => arr.reduce((chunks, el, i) => (i % size
+    ? chunks[chunks.length - 1].push(el)
+    : chunks.push([el])) && chunks, []
+  )

+ 7 - 0
src/index.js

@@ -0,0 +1,7 @@
+import App from "./components/App.svelte";
+
+const app = new App({
+  target: document.body
+});
+
+export default app;

+ 73 - 0
src/main.js

@@ -0,0 +1,73 @@
+import { join } from 'path'
+import url from 'url'
+import { app, BrowserWindow, ipcMain } from 'electron'
+import { is } from 'electron-util'
+import Store from 'electron-store'
+
+const configFile = new Store({
+  defaults: {
+    windowBounds: {
+      main: { width: 1800, height: 800 }
+    },
+    scan_prefix: 'AAA'
+  }
+});
+const configData = configFile.store
+
+let mainWindow
+
+function createWindow() {
+  mainWindow = new BrowserWindow({
+    ...configData.windowBounds.main,
+    show: false,
+    useContentSize: true,
+    defaultEncoding: 'utf-8',
+    webPreferences: {
+      nodeIntegration: true,
+    },
+    title: `${app.name}`,
+    icon: join(__dirname, '../icons/icon.icns')
+  })
+  mainWindow.removeMenu()
+  mainWindow.loadURL(
+    url.format({
+      pathname: join(__dirname, "index.html"),
+      protocol: "file:",
+      slashes: true
+    }))
+  if (is.development || process.argv.some(a => a === '--devtools')) mainWindow.openDevTools()
+
+  mainWindow.on('close', async e => {
+    if (!configData.close) {
+      e.preventDefault()
+      configFile.set('windowBounds.main', mainWindow.getBounds())
+      mainWindow.webContents.send('close_db')
+      console.log('Konfigurationsdaten gespeichert, Datenbank geschlossen')
+      configData.close = true
+      mainWindow.close()
+    }
+  })
+  mainWindow.on('closed', () => {
+    mainWindow = null
+  })
+  mainWindow.once('ready-to-show', async () => {
+    mainWindow.show()
+  })
+}
+
+app.on('ready', createWindow)
+app.on('window-all-closed', function () {
+  if (process.platform !== 'darwin') app.quit()
+})
+app.on('activate', function () {
+  if (mainWindow === null) createWindow()
+})
+
+ipcMain.on('print', (event, arg) => {
+  const options = {
+    margins: 'none'
+  }
+  mainWindow.webContents.print(options, (success, errorType) => {
+    event.reply('asynchronous-reply', success)
+  })
+})

+ 75 - 0
src/migrations/001-init.js

@@ -0,0 +1,75 @@
+exports.up = DB => {
+  DB.prepare(
+    `
+    CREATE TABLE IF NOT EXISTS schueler (
+      id              INTEGER PRIMARY KEY,
+      schild_id       INTEGER UNIQUE,
+      jahr            INTEGER,
+      klasse          TEXT,
+      vorname         TEXT,
+      name            TEXT,
+      gesperrt        INTEGER,
+      nichtschueler   INTEGER,
+      memo            TEXT)
+  `
+  ).run();
+  DB.prepare(
+    `
+    CREATE TABLE IF NOT EXISTS kurszugehoerigkeit (
+      id           INTEGER PRIMARY KEY,
+      kurs_lehrer  TEXT,
+      kurs         TEXT,
+      schild_id    INTEGER,
+      CONSTRAINT fk_schueler
+        FOREIGN KEY (schild_id)
+        REFERENCES schueler(schild_id)
+        ON DELETE CASCADE)
+    `
+  ).run();
+  DB.prepare(
+    `
+    CREATE TABLE IF NOT EXISTS medienbezeichnung (
+      id   INTEGER PRIMARY KEY,
+      name TEXT)
+  `
+  ).run();
+  DB.prepare(
+    `
+    CREATE TABLE IF NOT EXISTS medienexemplar (
+      id                    INTEGER PRIMARY KEY,
+      barcode               TEXT UNIQUE,
+      medienbezeichnung_id  INTEGER,
+      CONSTRAINT fk_medienbezeichnung
+        FOREIGN KEY (medienbezeichnung_id)
+        REFERENCES medienbezeichnung(id)
+        ON DELETE CASCADE)
+  `
+  ).run();
+  DB.prepare(
+    `
+    CREATE TABLE IF NOT EXISTS ausleihe (
+      id                 INTEGER PRIMARY KEY,
+      jahr               INTEGER,
+      klasse             TEXT,
+      kurs               TEXT,
+      kurs_lehrer        TEXT,
+      schueler_id        INTEGER,
+      medienexemplar_id  INTEGER,
+      CONSTRAINT fk_schueler
+        FOREIGN KEY (schueler_id)
+        REFERENCES schueler(id)
+        ON DELETE CASCADE,
+      CONSTRAINT fk_medienexemplar
+        FOREIGN KEY (medienexemplar_id)
+        REFERENCES medienexemplar(id)
+        ON DELETE CASCADE)
+  `
+  ).run();
+}
+exports.down = DB => {
+  DB.prepare(`DROP TABLE IF EXISTS schueler;`).run();
+  DB.prepare(`DROP TABLE IF EXISTS kurszugehoerigkeit;`).run();
+  DB.prepare(`DROP TABLE IF EXISTS medienbezeichnung;`).run();
+  DB.prepare(`DROP TABLE IF EXISTS medienexemplar;`).run();
+  DB.prepare(`DROP TABLE IF EXISTS ausleihe;`).run();
+}

+ 20 - 0
src/notifier.js

@@ -0,0 +1,20 @@
+import { notification } from './stores.js'
+
+export function send (icon, message, type = 'default', timeout, barcode) {
+  notification.set({ icon, type, message, timeout, barcode })
+}
+export function fehler (msg, barcode, timeout) {
+  send('error', msg, 'danger', timeout, barcode)
+}
+export function ausleihe (msg, barcode, timeout) {
+  send('arrow_forward', msg, 'warning', timeout, barcode)
+}
+export function rueckgabe (msg, barcode, timeout) {
+  send('arrow_back', msg, 'link', timeout, barcode)
+}
+export function zuordnung (msg, barcode, timeout) {
+  send('plus_one', msg, 'success', timeout, barcode)
+}
+export function fertig (msg, barcode, timeout) {
+  send('done', msg, 'primary', timeout, barcode)
+}

+ 16 - 0
src/stores.js

@@ -0,0 +1,16 @@
+import { writable } from 'svelte/store';
+import configFile from './configstore';
+
+export const configData = writable(configFile.store);
+configData.subscribe(value => {
+  configFile.set(value)
+});
+
+export const schueler = writable([]);
+export const view = writable();
+export const notification = writable()
+export const db = writable()
+export const medien = writable()
+export const titel = writable()
+export const print = writable(false)
+export const scan_status = writable()