diff --git a/.drone.yml b/.drone.yml index 981c632..79b2835 100644 --- a/.drone.yml +++ b/.drone.yml @@ -6,40 +6,16 @@ steps: - name: build image: node:current-alpine3.12 commands: - - apk update - - apk add git - npm install -D - npm run rebuild - name: package image: fuww/alpine-zip - when: - event: - - push commands: - SHORTREV=`echo $DRONE_COMMIT | cut -b 1-8` - - echo NAME=`date +%Y%m%d%H%m`-$SHORTREV >> environment + - echo FILENAME=`date +%Y%m%d%H%m`-$SHORTREV.zip >> environment - source environment - - zip -r $NAME.zip build - - - name: dev.carbon.chat - image: drillster/drone-rsync - when: - event: - - push - settings: - hosts: - from_secret: SSH_HOST - port: - from_secret: SSH_PORT - user: - from_secret: SSH_USERNAME - key: - from_secret: SSH_KEY - source: ./build/* - target: ${DRONE_COMMIT_SHA:0:8} - recursive: true - + - zip -r $FILENAME build - name: b2 image: tianon/backblaze-b2:2 @@ -52,9 +28,8 @@ steps: from_secret: b2_account_id KEY: from_secret: b2_application_key - COMMIT: ${DRONE_COMMIT_SHA:0:8} commands: - source environment - b2 authorize-account $ACCOUNT $KEY - - b2 upload-file $BUCKET $NAME.zip $NAME.zip - - echo Build artifacts avaliable at `b2 make-friendly-url $BUCKET $NAME.zip` and at https://dev.carbon.chat/$COMMIT + - b2 upload-file $BUCKET $FILENAME $FILENAME + - echo Build artifacts avaliable at `b2 make-friendly-url $BUCKET $FILENAME` diff --git a/.gitignore b/.gitignore index 1d83ade..5cac20b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,297 +1,10 @@ -# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig - -# Created by https://www.toptal.com/developers/gitignore/api/node,vscode,webstorm,webstorm+all -# Edit at https://www.toptal.com/developers/gitignore?templates=node,vscode,webstorm,webstorm+all - -### Node ### -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test -.env*.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -### vscode ### -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -*.code-workspace - -### WebStorm ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - # Generated files -.idea/**/contentModel.xml +node_modules +build -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### WebStorm Patch ### -# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 - -# *.iml -# modules.xml -# .idea/misc.xml -# *.ipr - -# Sonarlint plugin -# https://plugins.jetbrains.com/plugin/7973-sonarlint -.idea/**/sonarlint/ - -# SonarQube Plugin -# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin -.idea/**/sonarIssues.xml - -# Markdown Navigator plugin -# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced -.idea/**/markdown-navigator.xml -.idea/**/markdown-navigator-enh.xml -.idea/**/markdown-navigator/ - -# Cache file creation bug -# See https://youtrack.jetbrains.com/issue/JBR-2257 -.idea/$CACHE_FILE$ - -# CodeStream plugin -# https://plugins.jetbrains.com/plugin/12206-codestream -.idea/codestream.xml - -### WebStorm+all ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff - -# Generated files - -# Sensitive or high-churn files - -# Gradle - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake - -# Mongo Explorer plugin - -# File-based project format - -# IntelliJ - -# mpeltonen/sbt-idea plugin - -# JIRA plugin - -# Cursive Clojure plugin - -# Crashlytics plugin (for Android Studio and IntelliJ) - -# Editor-based Rest Client - -# Android studio 3.1+ serialized cache file - -### WebStorm+all Patch ### -# Ignores the whole .idea folder and all .iml files -# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 - -.idea/ - -# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 - -*.iml -modules.xml -.idea/misc.xml -*.ipr - -# Sonarlint plugin -.idea/sonarlint - -# End of https://www.toptal.com/developers/gitignore/api/node,vscode,webstorm,webstorm+all - -# Emacs +# Editor artifacts +.vscode *~ \#*# - -# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) - -/build/ +.#* +._* diff --git a/README.md b/README.md index 77dabec..07ca920 100644 --- a/README.md +++ b/README.md @@ -2,35 +2,12 @@ Carbon is the Matrix client for Discord and Guilded refugees. -Visit the hosted instance on -[https://carbon.chat](https://carbon.chat). - -## Status - -Carbon is **abandoned** by its author, but it is still solid code to build on for anyone with the time and inclination to pick it up. - -## Report bugs and suggest features - -Please briefly check this README and the issues page first to make -sure that the issue/feature is not already known! - -- If you already have an account on Gitdab, use the issues page. -- If you don't have an account, and don't wish to create one, you can -send an email to the [mailing list]. - -If something in the interface isn't working as you think it should, -please provide a screenshot of any messages from the browser devtools -console. If using the mailing list, attachments aren't supported, so -you'll have to upload to some image host and post the link. - -[mailing list]: https://lists.sr.ht/~cadence/carbon-discuss - ## The dream Carbon's planned features, compared to Discord and Guilded: - End to end encryption -- Free of charge, per-account, custom emojis and custom emoji packs +- Free of charge per-account custom emojis and custom emoji packs - No limit to number of groups you can join at a time - Uses the open Matrix and Mumble systems - Much better IRC layout @@ -58,39 +35,25 @@ Carbon is currently _technically_ usable as a chat app, but is very early in development. These important features still need to be implemented: +- Login GUI +- Unreads +- Chat history +- Formatting - Emojis - Reactions -- Encryption - Groups v2 - Group management - Pinned channels - Mumble integration -For more information, see [issue -#10.](https://gitdab.com/cadence/Carbon/issues/10) - ## The code -### Downloading a CI build - -Visit [drone CI](https://drone.badat.dev/cadence/Carbon/branches), -select the branch you want to use, select `b2` on the left, scroll -down, and open the URL on the last line to download the build. - -### Building from source yourself - -Dependencies: - -- git -- node -- npm (bundled with node) - -Build: +### Building npm install -D npm run rebuild -### Hosting a build +### Hosting Send the files from the `build` folder to a static file server. Apply a long cache-control header to everything served under `/static`, and @@ -101,8 +64,3 @@ no cache-control header to everything else. npm run watch Files will be rebuilt as you save them. - -Use `python3 -m http.server -d build` to serve the build on -[http://localhost:8000](http://localhost:8000). - -(Avoid `npx http-server`, it caches too much stuff.) diff --git a/build.js b/build.js index 964af20..4932101 100644 --- a/build.js +++ b/build.js @@ -1,6 +1,6 @@ const pug = require("pug") const sass = require("sass") -const fs = require("fs") +const fs = require("fs").promises const os = require("os") const crypto = require("crypto") const path = require("path") @@ -9,8 +9,6 @@ const babel = require("@babel/core") const fetch = require("node-fetch") const chalk = require("chalk") const hint = require("jshint").JSHINT -const browserify = require("browserify") -const {Transform} = require("stream") process.chdir(pj(__dirname, "src")) @@ -18,10 +16,10 @@ const buildDir = "../build" const validationQueue = [] const validationHost = os.hostname() === "future" ? "http://localhost:8888/" : "http://validator.w3.org/nu/" -const staticFiles = new Map() +const static = new Map() const links = new Map() const sources = new Map() -const pugLocals = {static: staticFiles, links} +const pugLocals = {static, links} const spec = require("./spec.js") @@ -96,7 +94,6 @@ function runHint(filename, source) { globals: ["console", "URLSearchParams", "staticFiles"], browser: true, asi: true, - node: true }) const result = hint.data() let problems = 0 @@ -128,54 +125,26 @@ function runHint(filename, source) { } async function addFile(sourcePath, targetPath) { - const contents = await fs.promises.readFile(pj(".", sourcePath), {encoding: null}); - staticFiles.set(sourcePath, `${targetPath}?static=${hash(contents)}`) - await fs.promises.writeFile(pj(buildDir, targetPath), contents) + const contents = await fs.readFile(pj(".", sourcePath), {encoding: null}) + static.set(sourcePath, `${targetPath}?static=${hash(contents)}`) + fs.writeFile(pj(buildDir, targetPath), contents) } async function loadJS(sourcePath, targetPath) { - let content = await fs.promises.readFile(pj(".", sourcePath), {encoding: "utf8"}) + let content = await fs.readFile(pj(".", sourcePath), {encoding: "utf8"}) sources.set(sourcePath, content) - staticFiles.set(sourcePath, `${targetPath}?static=${hash(content)}`) + static.set(sourcePath, `${targetPath}?static=${hash(content)}`) } async function addJS(sourcePath, targetPath) { let content = sources.get(sourcePath) - runHint(sourcePath, content) - await fs.promises.writeFile(pj(buildDir, targetPath), content) -} - -async function addBundle(sourcePath, targetPath, module = false) { - let opts = {} - if (module) opts.standalone = sourcePath - const content = await new Promise(resolve => { - browserify([], opts) - .add(pj(".", sourcePath)) - .transform(file => { - let content = "" - const transform = new Transform({ - transform(chunk, encoding, callback) { - content += chunk.toString() - callback(null, chunk) - } - }) - transform.on("finish", () => { - const relativePath = path.relative(process.cwd(), file).replace(/^\/*/, "/") - runHint(relativePath, content) - }) - return transform - }) - .bundle((err, res) => { - if (err) { - delete err.stream - throw err // Quit; problem parsing file to bundle - } - resolve(res) - }) + // resolve imports to hashed paths + content = content.replace(/\$to_relative "([^"]+)"/g, function(_, file) { + if (!static.get(file)) throw new Error(`Tried to relative import ${file} from ${sourcePath}, but import not found`) + return '"' + getRelative(targetPath, static.get(file)) + '"' }) - const writer = fs.promises.writeFile(pj(buildDir, targetPath), content) - staticFiles.set(sourcePath, `${targetPath}?static=${hash(content)}`) - await writer + runHint(sourcePath, content) + fs.writeFile(pj(buildDir, targetPath), content) } async function addSass(sourcePath, targetPath) { @@ -189,7 +158,7 @@ async function addSass(sourcePath, targetPath) { if (!(name instanceof sass.types.String)) { throw "$name: expected a string" } - const result = getRelative(targetPath, staticFiles.get(name.getValue())) + const result = getRelative(targetPath, static.get(name.getValue())) if (typeof result === "string") { return new sass.types.String(result) } else { @@ -197,10 +166,10 @@ async function addSass(sourcePath, targetPath) { } } } - }).css; - staticFiles.set(sourcePath, `${targetPath}?static=${hash(renderedCSS)}`) + }).css + static.set(sourcePath, `${targetPath}?static=${hash(renderedCSS)}`) validate(sourcePath, renderedCSS, "css") - await fs.promises.writeFile(pj(buildDir, targetPath), renderedCSS) + await fs.writeFile(pj(buildDir, targetPath), renderedCSS) } async function addPug(sourcePath, targetPath) { @@ -208,10 +177,10 @@ async function addPug(sourcePath, targetPath) { return getRelative(targetPath, staticTarget) } function getStatic(target) { - return getRelativeHere(staticFiles.get(target)) + return getRelativeHere(static.get(target)) } function getStaticName(target) { - return getRelativeHere(staticFiles.get(target)).replace(/\?.*$/, "") + return getRelativeHere(static.get(target)).replace(/\?.*$/, "") } function getLink(target) { return getRelativeHere(links.get(target)) @@ -219,11 +188,11 @@ async function addPug(sourcePath, targetPath) { const renderedHTML = pug.compileFile(pj(".", sourcePath), {pretty: true})({getStatic, getStaticName, getLink, ...pugLocals}) let renderedWithoutPHP = renderedHTML.replace(/<\?(?:php|=).*?\?>/gsm, "") validate(sourcePath, renderedWithoutPHP, "html") - await fs.promises.writeFile(pj(buildDir, targetPath), renderedHTML) + await fs.writeFile(pj(buildDir, targetPath), renderedHTML) } async function addBabel(sourcePath, targetPath) { - const originalCode = await fs.promises.readFile(pj(".", sourcePath), "utf8") + const originalCode = await fs.readFile(pj(".", sourcePath), "utf8") const compiled = babel.transformSync(originalCode, { sourceMaps: false, @@ -244,14 +213,14 @@ async function addBabel(sourcePath, targetPath) { } }) - const filenameWithQuery = `${targetPath}?static=${hash(compiled.code)}`; + const filenameWithQuery = `${targetPath}?static=${hash(compiled.code)}` - staticFiles.set(sourcePath, filenameWithQuery) + static.set(sourcePath, filenameWithQuery) await Promise.all([ - fs.promises.writeFile(pj(buildDir, targetPath), originalCode), - fs.promises.writeFile(pj(buildDir, minFilename), compiled.code), - fs.promises.writeFile(pj(buildDir, mapFilename), JSON.stringify(compiled.map)) + fs.writeFile(pj(buildDir, targetPath), originalCode), + fs.writeFile(pj(buildDir, minFilename), compiled.code), + fs.writeFile(pj(buildDir, mapFilename), JSON.stringify(compiled.map)) ]) } @@ -272,7 +241,7 @@ async function addBabel(sourcePath, targetPath) { // Stage 3: Create dirs const dirs = [...new Set(spec.map(item => path.dirname(item.target))).values()] - await Promise.all(dirs.map(d => fs.promises.mkdir(pj(buildDir, d), {recursive: true}))) + await Promise.all(dirs.map(d => fs.mkdir(pj(buildDir, d), {recursive: true}))) // Stage 4: Build for (const item of spec) { @@ -286,11 +255,6 @@ async function addBabel(sourcePath, targetPath) { await addBabel(item.source, item.target) } else if (item.type === "pug") { await addPug(item.source, item.target) - } else if (item.type === "bundle") { - await addBundle(item.source, item.target) - } else if (item.type === "module") { - // Creates a standalone bundle that can be imported on runtime - await addBundle(item.source, item.target, true) } else { throw new Error("Unknown item type: "+item.type) } diff --git a/package-lock.json b/package-lock.json index 97b56a5..e5806d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "carbon", + "name": "cosc212-assignment-1", "version": "1.0.0", "lockfileVersion": 1, "requires": true, @@ -8,6 +8,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, "requires": { "@babel/highlight": "^7.10.4" } @@ -16,6 +17,7 @@ "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.11.0.tgz", "integrity": "sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ==", + "dev": true, "requires": { "browserslist": "^4.12.0", "invariant": "^2.2.4", @@ -26,6 +28,7 @@ "version": "7.11.1", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.1.tgz", "integrity": "sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ==", + "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/generator": "^7.11.0", @@ -48,12 +51,14 @@ "@babel/parser": { "version": "7.11.2", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.2.tgz", - "integrity": "sha512-Vuj/+7vLo6l1Vi7uuO+1ngCDNeVmNbTngcJFKCR/oEtz8tKz0CJxZEGmPt9KcIloZhOZ3Zit6xbpXT2MDlS9Vw==" + "integrity": "sha512-Vuj/+7vLo6l1Vi7uuO+1ngCDNeVmNbTngcJFKCR/oEtz8tKz0CJxZEGmPt9KcIloZhOZ3Zit6xbpXT2MDlS9Vw==", + "dev": true }, "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" } @@ -64,6 +69,7 @@ "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz", "integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==", + "dev": true, "requires": { "@babel/types": "^7.11.0", "jsesc": "^2.5.1", @@ -74,6 +80,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "dev": true, "requires": { "@babel/types": "^7.10.4" } @@ -82,6 +89,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "dev": true, "requires": { "@babel/helper-explode-assignable-expression": "^7.10.4", "@babel/types": "^7.10.4" @@ -91,6 +99,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz", "integrity": "sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ==", + "dev": true, "requires": { "@babel/compat-data": "^7.10.4", "browserslist": "^4.12.0", @@ -103,6 +112,7 @@ "version": "7.10.5", "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz", "integrity": "sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A==", + "dev": true, "requires": { "@babel/helper-function-name": "^7.10.4", "@babel/helper-member-expression-to-functions": "^7.10.5", @@ -116,6 +126,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz", "integrity": "sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==", + "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.10.4", "@babel/helper-regex": "^7.10.4", @@ -126,6 +137,7 @@ "version": "7.10.5", "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", + "dev": true, "requires": { "@babel/helper-function-name": "^7.10.4", "@babel/types": "^7.10.5", @@ -136,6 +148,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz", "integrity": "sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A==", + "dev": true, "requires": { "@babel/traverse": "^7.10.4", "@babel/types": "^7.10.4" @@ -145,6 +158,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, "requires": { "@babel/helper-get-function-arity": "^7.10.4", "@babel/template": "^7.10.4", @@ -155,6 +169,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, "requires": { "@babel/types": "^7.10.4" } @@ -163,6 +178,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "dev": true, "requires": { "@babel/types": "^7.10.4" } @@ -171,6 +187,7 @@ "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz", "integrity": "sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==", + "dev": true, "requires": { "@babel/types": "^7.11.0" } @@ -179,6 +196,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "dev": true, "requires": { "@babel/types": "^7.10.4" } @@ -187,6 +205,7 @@ "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz", "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==", + "dev": true, "requires": { "@babel/helper-module-imports": "^7.10.4", "@babel/helper-replace-supers": "^7.10.4", @@ -201,6 +220,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "dev": true, "requires": { "@babel/types": "^7.10.4" } @@ -208,12 +228,14 @@ "@babel/helper-plugin-utils": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==" + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true }, "@babel/helper-regex": { "version": "7.10.5", "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", + "dev": true, "requires": { "lodash": "^4.17.19" } @@ -222,6 +244,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz", "integrity": "sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg==", + "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.10.4", "@babel/helper-wrap-function": "^7.10.4", @@ -234,6 +257,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", + "dev": true, "requires": { "@babel/helper-member-expression-to-functions": "^7.10.4", "@babel/helper-optimise-call-expression": "^7.10.4", @@ -245,6 +269,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", + "dev": true, "requires": { "@babel/template": "^7.10.4", "@babel/types": "^7.10.4" @@ -254,6 +279,7 @@ "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz", "integrity": "sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q==", + "dev": true, "requires": { "@babel/types": "^7.11.0" } @@ -262,6 +288,7 @@ "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, "requires": { "@babel/types": "^7.11.0" } @@ -269,12 +296,14 @@ "@babel/helper-validator-identifier": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==" + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true }, "@babel/helper-wrap-function": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz", "integrity": "sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==", + "dev": true, "requires": { "@babel/helper-function-name": "^7.10.4", "@babel/template": "^7.10.4", @@ -286,6 +315,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", + "dev": true, "requires": { "@babel/template": "^7.10.4", "@babel/traverse": "^7.10.4", @@ -296,6 +326,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.10.4", "chalk": "^2.0.0", @@ -306,6 +337,7 @@ "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" } @@ -314,6 +346,7 @@ "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", @@ -324,6 +357,7 @@ "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" } @@ -331,17 +365,20 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true }, "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" } @@ -351,12 +388,14 @@ "@babel/parser": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.0.tgz", - "integrity": "sha512-qvRvi4oI8xii8NllyEc4MDJjuZiNaRzyb7Y7lup1NqJV8TZHF4O27CcP+72WPn/k1zkgJ6WJfnIbk4jTsVAZHw==" + "integrity": "sha512-qvRvi4oI8xii8NllyEc4MDJjuZiNaRzyb7Y7lup1NqJV8TZHF4O27CcP+72WPn/k1zkgJ6WJfnIbk4jTsVAZHw==", + "dev": true }, "@babel/plugin-proposal-async-generator-functions": { "version": "7.10.5", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz", "integrity": "sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/helper-remap-async-to-generator": "^7.10.4", @@ -367,6 +406,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz", "integrity": "sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==", + "dev": true, "requires": { "@babel/helper-create-class-features-plugin": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4" @@ -376,6 +416,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz", "integrity": "sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-dynamic-import": "^7.8.0" @@ -385,6 +426,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz", "integrity": "sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" @@ -394,6 +436,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz", "integrity": "sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.0" @@ -403,6 +446,7 @@ "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz", "integrity": "sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" @@ -412,6 +456,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz", "integrity": "sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" @@ -421,6 +466,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz", "integrity": "sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-numeric-separator": "^7.10.4" @@ -430,6 +476,7 @@ "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz", "integrity": "sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.0", @@ -440,6 +487,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz", "integrity": "sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" @@ -449,6 +497,7 @@ "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz", "integrity": "sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0", @@ -459,6 +508,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz", "integrity": "sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw==", + "dev": true, "requires": { "@babel/helper-create-class-features-plugin": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4" @@ -468,6 +518,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz", "integrity": "sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==", + "dev": true, "requires": { "@babel/helper-create-regexp-features-plugin": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4" @@ -477,6 +528,7 @@ "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -485,6 +537,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz", "integrity": "sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -493,6 +546,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -501,6 +555,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.3" } @@ -509,6 +564,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -517,6 +573,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -525,6 +582,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -533,6 +591,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -541,6 +600,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -549,6 +609,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -557,6 +618,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -565,6 +627,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz", "integrity": "sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -573,6 +636,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz", "integrity": "sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -581,6 +645,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz", "integrity": "sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==", + "dev": true, "requires": { "@babel/helper-module-imports": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4", @@ -591,6 +656,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz", "integrity": "sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -599,6 +665,7 @@ "version": "7.11.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz", "integrity": "sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -607,6 +674,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz", "integrity": "sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==", + "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.10.4", "@babel/helper-define-map": "^7.10.4", @@ -622,6 +690,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz", "integrity": "sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -630,6 +699,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz", "integrity": "sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -638,6 +708,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz", "integrity": "sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==", + "dev": true, "requires": { "@babel/helper-create-regexp-features-plugin": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4" @@ -647,6 +718,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz", "integrity": "sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -655,6 +727,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz", "integrity": "sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==", + "dev": true, "requires": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4" @@ -664,6 +737,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz", "integrity": "sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -672,6 +746,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz", "integrity": "sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==", + "dev": true, "requires": { "@babel/helper-function-name": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4" @@ -681,6 +756,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz", "integrity": "sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -689,6 +765,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz", "integrity": "sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -697,6 +774,7 @@ "version": "7.10.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz", "integrity": "sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw==", + "dev": true, "requires": { "@babel/helper-module-transforms": "^7.10.5", "@babel/helper-plugin-utils": "^7.10.4", @@ -707,6 +785,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz", "integrity": "sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==", + "dev": true, "requires": { "@babel/helper-module-transforms": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4", @@ -718,6 +797,7 @@ "version": "7.10.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz", "integrity": "sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw==", + "dev": true, "requires": { "@babel/helper-hoist-variables": "^7.10.4", "@babel/helper-module-transforms": "^7.10.5", @@ -729,6 +809,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz", "integrity": "sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==", + "dev": true, "requires": { "@babel/helper-module-transforms": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4" @@ -738,6 +819,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz", "integrity": "sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==", + "dev": true, "requires": { "@babel/helper-create-regexp-features-plugin": "^7.10.4" } @@ -746,6 +828,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz", "integrity": "sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -754,6 +837,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz", "integrity": "sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/helper-replace-supers": "^7.10.4" @@ -763,6 +847,7 @@ "version": "7.10.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz", "integrity": "sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw==", + "dev": true, "requires": { "@babel/helper-get-function-arity": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4" @@ -772,6 +857,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz", "integrity": "sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -780,6 +866,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz", "integrity": "sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==", + "dev": true, "requires": { "regenerator-transform": "^0.14.2" } @@ -788,6 +875,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz", "integrity": "sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -796,6 +884,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz", "integrity": "sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -804,6 +893,7 @@ "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz", "integrity": "sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0" @@ -813,6 +903,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz", "integrity": "sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4", "@babel/helper-regex": "^7.10.4" @@ -822,6 +913,7 @@ "version": "7.10.5", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz", "integrity": "sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw==", + "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4" @@ -831,6 +923,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz", "integrity": "sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -839,6 +932,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz", "integrity": "sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -847,6 +941,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz", "integrity": "sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==", + "dev": true, "requires": { "@babel/helper-create-regexp-features-plugin": "^7.10.4", "@babel/helper-plugin-utils": "^7.10.4" @@ -856,6 +951,7 @@ "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.0.tgz", "integrity": "sha512-2u1/k7rG/gTh02dylX2kL3S0IJNF+J6bfDSp4DI2Ma8QN6Y9x9pmAax59fsCk6QUQG0yqH47yJWA+u1I1LccAg==", + "dev": true, "requires": { "@babel/compat-data": "^7.11.0", "@babel/helper-compilation-targets": "^7.10.4", @@ -931,6 +1027,7 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.3.tgz", "integrity": "sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg==", + "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", @@ -943,6 +1040,7 @@ "version": "7.11.2", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz", "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==", + "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } @@ -951,6 +1049,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/parser": "^7.10.4", @@ -961,6 +1060,7 @@ "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz", "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==", + "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/generator": "^7.11.0", @@ -977,6 +1077,7 @@ "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" } @@ -987,6 +1088,7 @@ "version": "7.11.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", + "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.10.4", "lodash": "^4.17.19", @@ -996,55 +1098,20 @@ "@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==" - }, - "@types/prop-types": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" - }, - "@types/react": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.0.tgz", - "integrity": "sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==", - "requires": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "JSONStream": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", - "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true }, "acorn": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz", - "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==" - }, - "acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "requires": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" + "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==", + "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" @@ -1054,88 +1121,38 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, - "array-filter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", - "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=" - }, "asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" - }, - "asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" - } - } - }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "requires": { - "inherits": "2.0.1" - } - } - } + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true }, "assert-never": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz", - "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==" + "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==", + "dev": true }, "async": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, "requires": { "lodash": "^4.17.14" } }, - "available-typed-arrays": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", - "integrity": "sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==", - "requires": { - "array-filter": "^1.0.0" - } - }, "babel-plugin-dynamic-import-node": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, "requires": { "object.assign": "^4.1.0" } @@ -1144,6 +1161,7 @@ "version": "3.0.0-canary-5", "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "dev": true, "requires": { "@babel/types": "^7.9.6" } @@ -1151,32 +1169,26 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "basic-auth": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", - "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=" + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "dev": true }, "binary-extensions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" - }, - "bn.js": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", - "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==" + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "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" @@ -1186,240 +1198,16 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, "requires": { "fill-range": "^7.0.1" } }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "browser-pack": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", - "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", - "requires": { - "JSONStream": "^1.0.3", - "combine-source-map": "~0.8.0", - "defined": "^1.0.0", - "safe-buffer": "^5.1.1", - "through2": "^2.0.0", - "umd": "^3.0.0" - } - }, - "browser-resolve": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", - "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", - "requires": { - "resolve": "^1.17.0" - } - }, - "browserify": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.0.tgz", - "integrity": "sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w==", - "requires": { - "JSONStream": "^1.0.3", - "assert": "^1.4.0", - "browser-pack": "^6.0.1", - "browser-resolve": "^2.0.0", - "browserify-zlib": "~0.2.0", - "buffer": "~5.2.1", - "cached-path-relative": "^1.0.0", - "concat-stream": "^1.6.0", - "console-browserify": "^1.1.0", - "constants-browserify": "~1.0.0", - "crypto-browserify": "^3.0.0", - "defined": "^1.0.0", - "deps-sort": "^2.0.1", - "domain-browser": "^1.2.0", - "duplexer2": "~0.1.2", - "events": "^3.0.0", - "glob": "^7.1.0", - "has": "^1.0.0", - "htmlescape": "^1.1.0", - "https-browserify": "^1.0.0", - "inherits": "~2.0.1", - "insert-module-globals": "^7.2.1", - "labeled-stream-splicer": "^2.0.0", - "mkdirp-classic": "^0.5.2", - "module-deps": "^6.2.3", - "os-browserify": "~0.3.0", - "parents": "^1.0.1", - "path-browserify": "^1.0.0", - "process": "~0.11.0", - "punycode": "^1.3.2", - "querystring-es3": "~0.2.0", - "read-only-stream": "^2.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.1.4", - "shasum-object": "^1.0.0", - "shell-quote": "^1.6.1", - "stream-browserify": "^3.0.0", - "stream-http": "^3.0.0", - "string_decoder": "^1.1.1", - "subarg": "^1.0.0", - "syntax-error": "^1.1.1", - "through2": "^2.0.0", - "timers-browserify": "^1.0.1", - "tty-browserify": "0.0.1", - "url": "~0.11.0", - "util": "~0.12.0", - "vm-browserify": "^1.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "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": { - "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" - } - } - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } - } - } - } - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" - } - } - }, - "browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "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" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - } - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "requires": { - "pako": "~1.0.5" - } - }, "browserslist": { "version": "4.14.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.0.tgz", "integrity": "sha512-pUsXKAF2lVwhmtpeA3LJrZ76jXuusrNyhduuQs7CDFf9foT4Y38aQOserd2lMe5DSSrjf3fx34oHwryuvxAUgQ==", + "dev": true, "requires": { "caniuse-lite": "^1.0.30001111", "electron-to-chromium": "^1.3.523", @@ -1427,44 +1215,17 @@ "node-releases": "^1.1.60" } }, - "buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", - "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "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==" - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" - }, - "cached-path-relative": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz", - "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==" - }, "caniuse-lite": { "version": "1.0.30001112", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001112.tgz", - "integrity": "sha512-J05RTQlqsatidif/38aN3PGULCLrg8OYQOlJUKbeYVzC2mGZkZLIztwRlB3MtrfLmawUmjFlNJvy/uhwniIe1Q==" + "integrity": "sha512-J05RTQlqsatidif/38aN3PGULCLrg8OYQOlJUKbeYVzC2mGZkZLIztwRlB3MtrfLmawUmjFlNJvy/uhwniIe1Q==", + "dev": true }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1474,6 +1235,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=", + "dev": true, "requires": { "is-regex": "^1.0.3" } @@ -1482,6 +1244,7 @@ "version": "3.4.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.1.tgz", "integrity": "sha512-TQTJyr2stihpC4Sya9hs2Xh+O2wf+igjL36Y75xx2WdHuiICcn/XJza46Jwt0eT5hVpQOzo3FpY3cj3RVYLX0g==", + "dev": true, "requires": { "anymatch": "~3.1.1", "braces": "~3.0.2", @@ -1493,19 +1256,11 @@ "readdirp": "~3.4.0" } }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, "cli": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "dev": true, "requires": { "exit": "0.1.2", "glob": "^7.1.1" @@ -1515,6 +1270,7 @@ "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" } @@ -1522,80 +1278,26 @@ "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==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" - }, - "combine-source-map": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", - "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", - "requires": { - "convert-source-map": "~1.1.0", - "inline-source-map": "~0.6.0", - "lodash.memoize": "~3.0.3", - "source-map": "~0.5.3" - }, - "dependencies": { - "convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=" - } - } + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "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=" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "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" - } - }, - "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" - } - } - } + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, "requires": { "date-now": "^0.1.4" } @@ -1604,20 +1306,17 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "dev": true, "requires": { "@babel/parser": "^7.6.0", "@babel/types": "^7.6.1" } }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" - }, "convert-source-map": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, "requires": { "safe-buffer": "~5.1.1" } @@ -1626,6 +1325,7 @@ "version": "3.6.5", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", + "dev": true, "requires": { "browserslist": "^4.8.5", "semver": "7.0.0" @@ -1634,98 +1334,34 @@ "semver": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": 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=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, "corser": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", - "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=" - }, - "create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" - } - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "csstype": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz", - "integrity": "sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ==" - }, - "dash-ast": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", - "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==" + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "dev": true }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true }, "debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, "requires": { "ms": "^2.1.1" } @@ -1734,78 +1370,22 @@ "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" } }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" - }, - "deps-sort": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", - "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", - "requires": { - "JSONStream": "^1.0.3", - "shasum-object": "^1.0.0", - "subarg": "^1.0.0", - "through2": "^2.0.0" - } - }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "detective": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", - "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", - "requires": { - "acorn-node": "^1.6.1", - "defined": "^1.0.0", - "minimist": "^1.1.1" - } - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" - } - } - }, - "discord-markdown": { - "version": "git+https://git.sr.ht/~cadence/nodejs-discord-markdown#5ad8046d8d62a7fb8047e1a697c3848744d4e64d", - "from": "git+https://git.sr.ht/~cadence/nodejs-discord-markdown#5ad8046d8d62a7fb8047e1a697c3848744d4e64d", - "requires": { - "simple-markdown": "^0.7.2" - } - }, "doctypes": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", - "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=" + "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=", + "dev": true }, "dom-serializer": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, "requires": { "domelementtype": "^2.0.1", "entities": "^2.0.0" @@ -1814,88 +1394,47 @@ "domelementtype": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", - "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==" + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", + "dev": true }, "entities": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==" + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", + "dev": true } } }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" - }, "domelementtype": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true }, "domhandler": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "dev": true, "requires": { "domelementtype": "1" } }, - "dompurify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.2.0.tgz", - "integrity": "sha512-bqFOQ7XRmmozp0VsKdIEe8UwZYxj0yttz7l80GBtBqdVRY48cOpXH2J/CVO7AEkV51qY0EBVXfilec18mdmQ/w==" - }, "domutils": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, "requires": { "dom-serializer": "0", "domelementtype": "1" } }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "requires": { - "readable-stream": "^2.0.2" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "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" - } - }, - "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" - } - } - } - }, "ecstatic": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", + "dev": true, "requires": { "he": "^1.1.1", "mime": "^1.6.0", @@ -1906,171 +1445,50 @@ "electron-to-chromium": { "version": "1.3.524", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.524.tgz", - "integrity": "sha512-ZUvklIBkfXQyA6IeiEss1nfKRICcdB5afAGZAaPGaExdfrkpUu/WWVO+X7QpNnphaVMllXnAcvKnVPdyM+DCPQ==" - }, - "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", - "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" - } - } + "integrity": "sha512-ZUvklIBkfXQyA6IeiEss1nfKRICcdB5afAGZAaPGaExdfrkpUu/WWVO+X7QpNnphaVMllXnAcvKnVPdyM+DCPQ==", + "dev": true }, "entities": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=" - }, - "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "object.assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", - "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.0", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.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==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "dev": true }, "escalade": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz", - "integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==" + "integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==", + "dev": true }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true }, "eventemitter3": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", - "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" - }, - "events": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", - "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==" - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "dev": true }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" - }, - "fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -2078,43 +1496,39 @@ "follow-redirects": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.12.1.tgz", - "integrity": "sha512-tmRv0AVuR7ZyouUHLeNSiO6pqulF7dYa3s19c6t+wz9LD69/uSzdMxJ2S91nTI9U3rt/IldxpzMOFejp6f0hjg==" - }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + "integrity": "sha512-tmRv0AVuR7ZyouUHLeNSiO6pqulF7dYa3s19c6t+wz9LD69/uSzdMxJ2S91nTI9U3rt/IldxpzMOFejp6f0hjg==", + "dev": true }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "fsevents": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, "optional": true }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "gensync": { "version": "1.0.0-beta.1", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==" - }, - "get-assigned-identifiers": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", - "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==" + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2128,6 +1542,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -2135,99 +1550,32 @@ "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "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==" + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "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==" - }, - "hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "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" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - } - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - }, - "highlight.js": { - "version": "10.3.2", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.3.2.tgz", - "integrity": "sha512-3jRT7OUYsVsKvukNKZCtnvRcFyCJqSEIuIMsEybAXRiFSwpt65qjPd/Pr+UOdYt7WJlt+lj3+ypUsHiySBp/Jw==" - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "htmlescape": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", - "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=" + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true }, "htmlparser2": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "dev": true, "requires": { "domelementtype": "1", "domhandler": "2.3", @@ -2240,6 +1588,7 @@ "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, "requires": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -2250,6 +1599,7 @@ "version": "0.12.3", "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", + "dev": true, "requires": { "basic-auth": "^1.0.3", "colors": "^1.4.0", @@ -2263,20 +1613,11 @@ "union": "~0.5.0" } }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -2285,73 +1626,32 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "inline-source-map": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", - "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", - "requires": { - "source-map": "~0.5.3" - } - }, - "insert-module-globals": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.1.tgz", - "integrity": "sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==", - "requires": { - "JSONStream": "^1.0.3", - "acorn-node": "^1.5.2", - "combine-source-map": "^0.8.0", - "concat-stream": "^1.6.1", - "is-buffer": "^1.1.0", - "path-is-absolute": "^1.0.1", - "process": "~0.11.0", - "through2": "^2.0.0", - "undeclared-identifiers": "^1.1.2", - "xtend": "^4.0.0" - } + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, "requires": { "loose-envify": "^1.0.0" } }, - "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" - }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, "requires": { "binary-extensions": "^2.0.0" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-callable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==" - }, - "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==" - }, "is-expression": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "dev": true, "requires": { "acorn": "^7.1.1", "object-assign": "^4.1.1" @@ -2360,87 +1660,68 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-generator-function": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", - "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==" + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, "requires": { "is-extglob": "^2.1.1" } }, - "is-negative-zero": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", - "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" - }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true }, "is-promise": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true }, "is-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "dev": true, "requires": { "has-symbols": "^1.0.1" } }, - "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==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-typed-array": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.3.tgz", - "integrity": "sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ==", - "requires": { - "available-typed-arrays": "^1.0.0", - "es-abstract": "^1.17.4", - "foreach": "^2.0.5", - "has-symbols": "^1.0.1" - } - }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true }, "js-stringify": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", - "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=" + "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=", + "dev": true }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true }, "jshint": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.12.0.tgz", "integrity": "sha512-TwuuaUDmra0JMkuqvqy+WGo2xGHSNjv1BA1nTIgtH2K5z1jHuAEeAgp7laaR+hLRmajRjcrM71+vByBDanCyYA==", + "dev": true, "requires": { "cli": "~1.0.0", "console-browserify": "1.1.x", @@ -2456,42 +1737,32 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, "requires": { "minimist": "^1.2.5" } }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" - }, "jstransformer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=", + "dev": true, "requires": { "is-promise": "^2.0.0", "promise": "^7.0.1" } }, - "labeled-stream-splicer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", - "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", - "requires": { - "inherits": "^2.0.1", - "stream-splicer": "^2.0.0" - } - }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true }, "levenary": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, "requires": { "leven": "^3.1.0" } @@ -2499,66 +1770,29 @@ "lodash": { "version": "4.17.19", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" - }, - "lodash.memoize": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", - "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=" + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" - } - } - }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "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" } @@ -2566,111 +1800,59 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, "requires": { "minimist": "^1.2.5" } }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, - "module-deps": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz", - "integrity": "sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==", - "requires": { - "JSONStream": "^1.0.3", - "browser-resolve": "^2.0.0", - "cached-path-relative": "^1.0.2", - "concat-stream": "~1.6.0", - "defined": "^1.0.0", - "detective": "^5.2.0", - "duplexer2": "^0.1.2", - "inherits": "^2.0.1", - "parents": "^1.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.4.0", - "stream-combiner2": "^1.1.1", - "subarg": "^1.0.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "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" - } - }, - "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" - } - } - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node-fetch": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", + "dev": true }, "node-releases": { "version": "1.1.60", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz", - "integrity": "sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA==" + "integrity": "sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA==", + "dev": true }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, "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.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "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==" + "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", @@ -2682,6 +1864,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } @@ -2689,127 +1872,52 @@ "opener": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", - "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==" - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" - }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "parents": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", - "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", - "requires": { - "path-platform": "~0.11.15" - } - }, - "parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "path-browserify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==", + "dev": true }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "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==" - }, - "path-platform": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", - "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=" - }, - "pbkdf2": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", - "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true }, "portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, "requires": { "async": "^2.6.2", "debug": "^3.1.1", "mkdirp": "^0.5.5" } }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" - }, - "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==" - }, "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, "requires": { "asap": "~2.0.3" } }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" - } - } - }, "pug": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.0.tgz", "integrity": "sha512-inmsJyFBSHZaiGLaguoFgJGViX0If6AcfcElimvwj9perqjDpUpw79UIEDZbWFmoGVidh08aoE+e8tVkjVJPCw==", + "dev": true, "requires": { "pug-code-gen": "^3.0.0", "pug-filters": "^4.0.0", @@ -2825,6 +1933,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "dev": true, "requires": { "constantinople": "^4.0.1", "js-stringify": "^1.0.2", @@ -2835,6 +1944,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.1.tgz", "integrity": "sha512-xJIGvmXTQlkJllq6hqxxjRWcay2F9CU69TuAuiVZgHK0afOhG5txrQOcZyaPHBvSWCU/QQOqEp5XCH94rRZpBQ==", + "dev": true, "requires": { "constantinople": "^4.0.1", "doctypes": "^1.1.0", @@ -2849,12 +1959,14 @@ "pug-error": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz", - "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==" + "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==", + "dev": true }, "pug-filters": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "dev": true, "requires": { "constantinople": "^4.0.1", "jstransformer": "1.0.0", @@ -2867,6 +1979,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.0.tgz", "integrity": "sha512-52xMk8nNpuyQ/M2wjZBN5gXQLIylaGkAoTk5Y1pBhVqaopaoj8Z0iVzpbFZAqitL4RHNVDZRnJDsqEYe99Ti0A==", + "dev": true, "requires": { "character-parser": "^2.2.0", "is-expression": "^4.0.0", @@ -2877,6 +1990,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "dev": true, "requires": { "pug-error": "^2.0.0", "pug-walk": "^2.0.0" @@ -2886,6 +2000,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "dev": true, "requires": { "object-assign": "^4.1.1", "pug-walk": "^2.0.0" @@ -2895,6 +2010,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "dev": true, "requires": { "pug-error": "^2.0.0", "token-stream": "1.0.0" @@ -2903,12 +2019,14 @@ "pug-runtime": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.0.tgz", - "integrity": "sha512-GoEPcmQNnaTsePEdVA05bDpY+Op5VLHKayg08AQiqJBWU/yIaywEYv7TetC5dEQS3fzBBoyb2InDcZEg3mPTIA==" + "integrity": "sha512-GoEPcmQNnaTsePEdVA05bDpY+Op5VLHKayg08AQiqJBWU/yIaywEYv7TetC5dEQS3fzBBoyb2InDcZEg3mPTIA==", + "dev": true }, "pug-strip-comments": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "dev": true, "requires": { "pug-error": "^2.0.0" } @@ -2916,86 +2034,20 @@ "pug-walk": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", - "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==" - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", + "dev": true }, "qs": { "version": "6.9.4", "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", - "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "read-only-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", - "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", - "requires": { - "readable-stream": "^2.0.2" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "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" - } - }, - "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" - } - } - } + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", + "dev": true }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -3007,6 +2059,7 @@ "version": "3.4.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "dev": true, "requires": { "picomatch": "^2.2.1" } @@ -3014,12 +2067,14 @@ "regenerate": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", - "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==" + "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==", + "dev": true }, "regenerate-unicode-properties": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, "requires": { "regenerate": "^1.4.0" } @@ -3027,12 +2082,14 @@ "regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true }, "regenerator-transform": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "dev": true, "requires": { "@babel/runtime": "^7.8.4" } @@ -3041,6 +2098,7 @@ "version": "4.7.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz", "integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==", + "dev": true, "requires": { "regenerate": "^1.4.0", "regenerate-unicode-properties": "^8.2.0", @@ -3053,12 +2111,14 @@ "regjsgen": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true }, "regjsparser": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "dev": true, "requires": { "jsesc": "~0.5.0" }, @@ -3066,46 +2126,37 @@ "jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true } } }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true }, "resolve": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, "requires": { "path-parse": "^1.0.6" } }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, "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==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "sass": { "version": "1.26.10", "resolved": "https://registry.npmjs.org/sass/-/sass-1.26.10.tgz", "integrity": "sha512-bzN0uvmzfsTvjz0qwccN1sPm2HxxpNI/Xa+7PlUEMS+nQvbyuEK7Y0qFqxlPHhiNHb1Ze8WQJtU31olMObkAMw==", + "dev": true, "requires": { "chokidar": ">=2.0.0 <4.0.0" } @@ -3113,396 +2164,59 @@ "secure-compare": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", - "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=" + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", + "dev": true }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shasum-object": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz", - "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==", - "requires": { - "fast-safe-stringify": "^2.0.7" - } - }, - "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==" + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true }, "shelljs": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=" - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" - }, - "simple-markdown": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/simple-markdown/-/simple-markdown-0.7.2.tgz", - "integrity": "sha512-XfCvqqzMyzRj4L7eIxJgGaQ2Gaxr20GhTFMB+1yuY8q3xffjzmOg4Q5tC0kcaJPV42NNUHCQDaRK6jzi3/RhrA==", - "requires": { - "@types/react": ">=16.0.0" - } + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "requires": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - }, - "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" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - } - } - }, - "stream-combiner2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", - "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", - "requires": { - "duplexer2": "~0.1.0", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "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" - } - }, - "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" - } - } - } - }, - "stream-http": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.1.1.tgz", - "integrity": "sha512-S7OqaYu0EkFpgeGFb/NPOoPLxFko7TPqtEeFg5DXPB4v/KETHG0Ln6fRFrNezoelpaDKmycEmmZ81cC9DAwgYg==", - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "xtend": "^4.0.2" - }, - "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" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - } - } - }, - "stream-splicer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", - "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "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" - } - }, - "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" - } - } - } - }, - "string.prototype.trimend": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz", - "integrity": "sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "object.assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", - "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.0", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - } - } - }, - "string.prototype.trimstart": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz", - "integrity": "sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "object.assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", - "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.0", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - } - } + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true }, "strip-json-comments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=" - }, - "subarg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", - "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", - "requires": { - "minimist": "^1.1.0" - } + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "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" } }, - "syntax-error": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", - "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", - "requires": { - "acorn-node": "^1.2.0" - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "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" - } - }, - "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" - } - } - } - }, - "timers-browserify": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", - "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", - "requires": { - "process": "~0.11.0" - } - }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "requires": { "is-number": "^7.0.0" } @@ -3510,44 +2224,20 @@ "token-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", - "integrity": "sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ=" - }, - "tty-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "umd": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", - "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==" - }, - "undeclared-identifiers": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", - "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", - "requires": { - "acorn-node": "^1.3.0", - "dash-ast": "^1.0.0", - "get-assigned-identifiers": "^1.2.0", - "simple-concat": "^1.0.0", - "xtend": "^4.0.1" - } + "integrity": "sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ=", + "dev": true }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==" + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true }, "unicode-match-property-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, "requires": { "unicode-canonical-property-names-ecmascript": "^1.0.4", "unicode-property-aliases-ecmascript": "^1.0.4" @@ -3556,87 +2246,41 @@ "unicode-match-property-value-ecmascript": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==" + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true }, "unicode-property-aliases-ecmascript": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==" + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true }, "union": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, "requires": { "qs": "^6.4.0" } }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - } - } - }, "url-join": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", - "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=" - }, - "util": { - "version": "0.12.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.3.tgz", - "integrity": "sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog==", - "requires": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", - "which-typed-array": "^1.1.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", + "dev": true }, "void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", - "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=" - }, - "which-typed-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.2.tgz", - "integrity": "sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ==", - "requires": { - "available-typed-arrays": "^1.0.2", - "es-abstract": "^1.17.5", - "foreach": "^2.0.5", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.1", - "is-typed-array": "^1.1.3" - } + "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=", + "dev": true }, "with": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "dev": true, "requires": { "@babel/parser": "^7.9.6", "@babel/types": "^7.9.6", @@ -3647,12 +2291,8 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } } diff --git a/package.json b/package.json index f63bf03..4d32107 100644 --- a/package.json +++ b/package.json @@ -5,25 +5,21 @@ "main": "build.js", "scripts": { "build": "node build.js", - "watch": "sh -c 'while true; do echo -n \"Build started at \"; date; npm run build; inotifywait $(find src -type f) build.js spec.js package.json -e close_write -qq; done'", + "watch": "fish -c 'while true; echo -n \"Build started at \"; date; npm run build; inotifywait (find src -type f) build.js -e close_write -qq; end'", "rebuild": "rm build -rf && node build.js" }, "keywords": [], "author": "", "license": "AGPL-3.0-only", - "dependencies": { + "dependencies": {}, + "devDependencies": { "@babel/core": "^7.11.1", "@babel/preset-env": "^7.11.0", - "browserify": "^17.0.0", "chalk": "^4.1.0", - "discord-markdown": "git+https://git.sr.ht/~cadence/nodejs-discord-markdown#5ad8046d8d62a7fb8047e1a697c3848744d4e64d", - "dompurify": "^2.2.0", - "highlight.js": "^10.3.2", "http-server": "^0.12.3", "jshint": "^2.12.0", "node-fetch": "^2.6.0", "pug": "^3.0.0", "sass": "^1.26.10" - }, - "devDependencies": {} + } } diff --git a/spec.js b/spec.js index 4244cdf..38bb96e 100644 --- a/spec.js +++ b/spec.js @@ -2,96 +2,121 @@ module.exports = [ { type: "file", source: "/assets/fonts/whitney-500.woff", - target: "/static/whitney-500.woff", + target: "/static/whitney-500.woff" }, { type: "file", source: "/assets/fonts/whitney-400.woff", - target: "/static/whitney-400.woff", + target: "/static/whitney-400.woff" }, { - type: "bundle", - source: "/js/login.js", - target: "/static/login.js", + type: "js", + source: "/js/basic.js", + target: "/static/basic.js" }, { - type: "bundle", - source: "/js/main.js", - target: "/static/bundle.js" + type: "js", + source: "/js/groups.js", + target: "/static/groups.js" + }, + { + type: "js", + source: "/js/chat-input.js", + target: "/static/chat-input.js" + }, + { + type: "js", + source: "/js/room-picker.js", + target: "/static/room-picker.js" + }, + { + type: "js", + source: "/js/store/store.js", + target: "/static/store/store.js" + }, + { + type: "js", + source: "/js/store/Subscribable.js", + target: "/static/store/Subscribable.js" + }, + { + type: "js", + source: "/js/store/SubscribeValue.js", + target: "/static/store/SubscribeValue.js" + }, + { + type: "js", + source: "/js/store/SubscribeMapList.js", + target: "/static/store/SubscribeMapList.js" + }, + { + type: "js", + source: "/js/store/SubscribeSet.js", + target: "/static/store/SubscribeSet.js" + }, + { + type: "js", + source: "/js/sync/sync.js", + target: "/static/sync/sync.js" + }, + { + type: "js", + source: "/js/lsm.js", + target: "/static/lsm.js" + }, + { + type: "js", + source: "/js/Timeline.js", + target: "/static/Timeline.js" + }, + { + type: "js", + source: "/js/Anchor.js", + target: "/static/Anchor.js" + }, + { + type: "js", + source: "/js/chat.js", + target: "/static/chat.js" + }, + { + type: "js", + source: "/js/functions.js", + target: "/static/functions.js" }, { type: "file", source: "/assets/fonts/whitney-500.woff", - target: "/static/whitney-500.woff", + target: "/static/whitney-500.woff" }, { type: "file", source: "/assets/icons/directs.svg", - target: "/static/directs.svg", + target: "/static/directs.svg" }, { type: "file", source: "/assets/icons/channels.svg", - target: "/static/channels.svg", + target: "/static/channels.svg" }, { type: "file", source: "/assets/icons/join-event.svg", - target: "/static/join-event.svg", - }, - { - type: "file", - source: "/assets/icons/leave-event.svg", - target: "/static/leave-event.svg", - }, - { - type: "file", - source: "/assets/icons/invite-event.svg", - target: "/static/invite-event.svg", - }, - { - type: "file", - source: "/assets/icons/profile-event.svg", - target: "/static/profile-event.svg", - }, - { - type: "file", - source: "/assets/icons/call-out.svg", - target: "/static/call-out.svg", - }, - { - type: "file", - source: "/assets/icons/call-in.svg", - target: "/static/call-in.svg", - }, - { - type: "file", - source: "/assets/icons/call-accepted.svg", - target: "/static/call-accepted.svg", - }, - { - type: "file", - source: "/assets/icons/call-rejected.svg", - target: "/static/call-rejected.svg", + target: "/static/join-event.svg" }, { type: "sass", source: "/sass/main.sass", - target: "/static/main.css", - }, - { - type: "sass", - source: "/sass/login.sass", - target: "/static/login.css", + target: "/static/main.css" }, { type: "pug", source: "/home.pug", - target: "/index.html", + target: "/index.html" }, { type: "pug", source: "/login.pug", - target: "/login/index.html", - }, -]; + target: "/login.html" + } +] diff --git a/src/assets/icons/call-accepted.svg b/src/assets/icons/call-accepted.svg deleted file mode 100644 index fea7031..0000000 --- a/src/assets/icons/call-accepted.svg +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - image/svg+xml - - free-icons-solid - - - - - - - - - - free-icons-solid - - - - diff --git a/src/assets/icons/call-in.svg b/src/assets/icons/call-in.svg deleted file mode 100644 index 484fe5c..0000000 --- a/src/assets/icons/call-in.svg +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - image/svg+xml - - free-icons-solid - - - - - - - - - - free-icons-solid - - - - - - diff --git a/src/assets/icons/call-out.svg b/src/assets/icons/call-out.svg deleted file mode 100644 index 877bad4..0000000 --- a/src/assets/icons/call-out.svg +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - image/svg+xml - - free-icons-solid - - - - - - - - - - free-icons-solid - - - - - - diff --git a/src/assets/icons/call-rejected.svg b/src/assets/icons/call-rejected.svg deleted file mode 100644 index 55b3994..0000000 --- a/src/assets/icons/call-rejected.svg +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - image/svg+xml - - free-icons-solid - - - - - - - - - - free-icons-solid - - - - - - diff --git a/src/assets/icons/invite-event.svg b/src/assets/icons/invite-event.svg deleted file mode 100644 index fa44732..0000000 --- a/src/assets/icons/invite-event.svg +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/src/assets/icons/join-event.svg b/src/assets/icons/join-event.svg index 2b6b901..042e3bd 100644 --- a/src/assets/icons/join-event.svg +++ b/src/assets/icons/join-event.svg @@ -25,9 +25,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="11.313708" - inkscape:cx="-4.2728481" - inkscape:cy="-2.1951295" + inkscape:zoom="1" + inkscape:cx="15.649008" + inkscape:cy="8.3751893" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" diff --git a/src/assets/icons/leave-event.svg b/src/assets/icons/leave-event.svg deleted file mode 100644 index f836616..0000000 --- a/src/assets/icons/leave-event.svg +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/src/assets/icons/profile-event.svg b/src/assets/icons/profile-event.svg deleted file mode 100644 index 6fcdadf..0000000 --- a/src/assets/icons/profile-event.svg +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/src/home.pug b/src/home.pug index a9450f3..68bbd21 100644 --- a/src/home.pug +++ b/src/home.pug @@ -33,15 +33,19 @@ doctype html html head meta(charset="utf-8") - title Carbon // var static = !{JSON.stringify([...static.entries()].reduce((a, c) => (a[c[0]] = getRelative(c[1]), a), {}))} script | var staticFiles = new Map( != JSON.stringify([...static.keys()].map(k => [k, getStatic(k)])) | ) link(rel="stylesheet" type="text/css" href=getStatic("/sass/main.sass")) - script(type="module" src=getStatic("/js/main.js")) - body.show-focus + script(type="module" src=getStatic("/js/groups.js")) + script(type="module" src=getStatic("/js/chat-input.js")) + script(type="module" src=getStatic("/js/room-picker.js")) + script(type="module" src=getStatic("/js/sync/sync.js")) + script(type="module" src=getStatic("/js/chat.js")) + title Carbon + body main.main .c-groups .c-groups__display#c-groups-display @@ -49,9 +53,7 @@ html .c-groups__container#c-groups-list .c-rooms#c-rooms .c-chat - .c-chat-banner#c-chat-banner .c-chat__messages#c-chat-messages .c-chat__inner#c-chat .c-chat-input - textarea(placeholder="Send a message..." autocomplete="off").c-chat-input__textarea#c-chat-textarea - .c-typing#c-typing + textarea(placeholder="Send a message..." autocomplete="off").c-chat-input__textarea#c-chat-textarea \ No newline at end of file diff --git a/src/js/anchor.js b/src/js/Anchor.js similarity index 74% rename from src/js/anchor.js rename to src/js/Anchor.js index 498a287..2adbe5f 100644 --- a/src/js/anchor.js +++ b/src/js/Anchor.js @@ -1,4 +1,4 @@ -const {ElemJS} = require("./basic.js") +import {ElemJS} from $to_relative "/js/basic.js" class Anchor extends ElemJS { constructor() { @@ -12,4 +12,4 @@ class Anchor extends ElemJS { } } -module.exports = {Anchor} +export {Anchor} diff --git a/src/js/Timeline.js b/src/js/Timeline.js new file mode 100644 index 0000000..94e77bf --- /dev/null +++ b/src/js/Timeline.js @@ -0,0 +1,366 @@ +import {ElemJS, ejs} from $to_relative "/js/basic.js" +import {Subscribable} from $to_relative "/js/store/Subscribable.js" +import {store} from $to_relative "/js/store/store.js" +import {Anchor} from $to_relative "/js/Anchor.js" +import * as lsm from $to_relative "/js/lsm.js" +import {resolveMxc} from $to_relative "/js/functions.js" + +const dateFormatter = Intl.DateTimeFormat("default", {hour: "numeric", minute: "numeric", day: "numeric", month: "short", year: "numeric"}) + +let sentIndex = 0 + +function getTxnId() { + return Date.now() + (sentIndex++) +} + +function eventSearch(list, event, min = 0, max = -1) { + if (list.length === 0) return {success: false, i: 0} + + if (max === -1) max = list.length - 1 + let mid = Math.floor((max + min) / 2) + // success condition + if (list[mid] && list[mid].data.event_id === event.data.event_id) return {success: true, i: mid} + // failed condition + if (min >= max) { + while (mid !== -1 && (!list[mid] || list[mid].data.origin_server_ts > event.data.origin_server_ts)) mid-- + return { + success: false, + i: mid + 1 + } + } + // recurse (below) + if (list[mid].data.origin_server_ts > event.data.origin_server_ts) return eventSearch(list, event, min, mid-1) + // recurse (above) + else return eventSearch(list, event, mid+1, max) +} + +class Event extends ElemJS { + constructor(data) { + super("div") + this.class("c-message") + this.data = null + this.group = null + this.editedAt = null + this.update(data) + } + + // predicates + + canGroup() { + return this.data.type === "m.room.message" + } + + // operations + + setGroup(group) { + this.group = group + } + + setEdited(time) { + this.editedAt = time + this.render() + } + + update(data) { + this.data = data + this.render() + } + + removeEvent() { + if (this.group) this.group.removeEvent(this) + else this.remove() + } + + render() { + this.element.classList[this.data.pending ? "add" : "remove"]("c-message--pending") + if (this.data.type === "m.room.message") { + this.text(this.data.content.body) + } else if (this.data.type === "m.room.member") { + if (this.data.content.membership === "join") { + this.child(ejs("i").text("joined the room")) + } else { + this.child(ejs("i").text("left the room")) + } + } else { + this.child(ejs("i").text(`Unsupported event type ${this.data.type}`)) + } + if (this.editedAt) { + this.child(ejs("span").class("c-message__edited").text("(edited)").attribute("title", "at " + dateFormatter.format(this.editedAt))) + } + } +} + +class Sender { + constructor(roomID, mxid) { + this.sender = store.rooms.get(roomID).value().members.get(mxid) + this.sender.subscribe("changeSelf", this.update.bind(this)) + this.name = new ElemJS("div").class("c-message-group__name") + this.avatar = new ElemJS("div").class("c-message-group__avatar") + this.displayingGoodData = false + this.update() + } + + update() { + if (this.sender.exists()) { + // name + if (this.sender.value().content.displayname) { + this.name.text(this.sender.value().content.displayname) + this.displayingGoodData = true + } else if (!this.displayingGoodData) { + this.name.text(this.sender.value().state_key) + } + + // avatar + this.avatar.clearChildren() + if (this.sender.value().content.avatar_url) { + this.avatar.child( + ejs("img").class("c-message-group__icon").attribute("src", resolveMxc(this.sender.value().content.avatar_url, 96, "crop")) + ) + } else { + this.avatar.child( + ejs("div").class("c-message-group__icon", "c-message-group__icon--no-icon") + ) + } + } + } +} + +class EventGroup extends ElemJS { + constructor(reactive, list) { + super("div") + this.class("c-message-group") + this.reactive = reactive + this.list = list + this.data = { + sender: list[0].data.sender, + origin_server_ts: list[0].data.origin_server_ts + } + this.sender = new Sender(this.reactive.id, this.data.sender) + this.child( + this.sender.avatar, + this.messages = ejs("div").class("c-message-group__messages").child( + ejs("div").class("c-message-group__intro").child( + this.sender.name, + ejs("div").class("c-message-group__date").text(dateFormatter.format(this.data.origin_server_ts)) + ), + ...this.list + ) + ) + } + + addEvent(event) { + const index = eventSearch(this.list, event).i + event.setGroup(this) + this.list.splice(index, 0, event) + this.messages.childAt(index + 1, event) + } + + removeEvent(event) { + const search = eventSearch(this.list, event) + if (!search.success) throw new Error(`Event ${event.data.event_id} not found in this group`) + const index = search.i + // actually remove the event + this.list.splice(index, 1) + event.remove() // should get everything else + if (this.list.length === 0) this.reactive.removeGroup(this) + } +} + +class ReactiveTimeline extends ElemJS { + constructor(id, list) { + super("div") + this.class("c-event-groups") + this.id = id + this.list = list + this.render() + } + + addEvent(event) { + const search = eventSearch(this.list, event) + // console.log(search, this.list.map(l => l.data.sender), event.data) + if (!search.success && search.i >= 1) this.tryAddGroups(event, [search.i-1, search.i]) + else this.tryAddGroups(event, [search.i]) + } + + tryAddGroups(event, indices) { + const success = indices.some(i => { + if (!this.list[i]) { + // if (printed++ < 100) console.log("tryadd success, created group") + const group = new EventGroup(this, [event]) + this.list.splice(i, 0, group) + this.childAt(i, group) + event.setGroup(group) + return true + } else if (this.list[i] && this.list[i].data.sender === event.data.sender) { + // if (printed++ < 100) console.log("tryadd success, using existing group") + this.list[i].addEvent(event) + return true + } + }) + if (!success) console.log("tryadd failure", indices, this.list.map(l => l.data.sender), event.data) + } + + removeGroup(group) { + const index = this.list.indexOf(group) + this.list.splice(index, 1) + group.remove() // should get everything else + } + + render() { + this.clearChildren() + this.list.forEach(group => this.child(group)) + this.anchor = new Anchor() + this.child(this.anchor) + } +} + +class Timeline extends Subscribable { + constructor(room) { + super() + Object.assign(this.events, { + beforeChange: [], + afterChange: [] + }) + Object.assign(this.eventDeps, { + beforeChange: [], + afterChange: [] + }) + this.room = room + this.id = this.room.id + this.list = [] + this.map = new Map() + this.reactiveTimeline = new ReactiveTimeline(this.id, []) + this.latest = 0 + this.pending = new Set() + } + + updateStateEvents(events) { + for (const eventData of events) { + let id = eventData.event_id + if (eventData.type === "m.room.member") { + // update members + if (eventData.membership !== "leave") { + this.room.members.get(eventData.state_key).set(eventData) + } + } + } + } + + updateEvents(events) { + this.broadcast("beforeChange") + // handle state events + this.updateStateEvents(events) + for (const eventData of events) { + // set variables + this.latest = Math.max(this.latest, eventData.origin_server_ts) + let id = eventData.event_id + // handle local echoes + if (eventData.sender === lsm.get("mx_user_id") && eventData.content && this.pending.has(eventData.content["chat.carbon.message.pending_id"])) { + const target = this.map.get(eventData.content["chat.carbon.message.pending_id"]) + this.map.set(id, target) + this.map.delete(eventData.content["chat.carbon.message.pending_id"]) + } + // handle timeline events + if (this.map.has(id)) { + // update existing event + this.map.get(id).update(eventData) + } else { + // skip displaying events that we don't know how to + if (eventData.type === "m.reaction") { + continue + } + // skip redacted events + if (eventData.unsigned && eventData.unsigned.redacted_by) { + continue + } + // handle redactions + if (eventData.type === "m.room.redaction") { + if (this.map.has(eventData.redacts)) this.map.get(eventData.redacts).removeEvent() + continue + } + // handle edits + if (eventData.type === "m.room.message" && eventData.content["m.relates_to"] && eventData.content["m.relates_to"].rel_type === "m.replace") { + const replaces = eventData.content["m.relates_to"].event_id + if (this.map.has(replaces)) { + const event = this.map.get(replaces) + event.data.content = eventData.content["m.new_content"] + event.setEdited(eventData.origin_server_ts) + event.update(event.data) + continue + } else { + // uhhhhhhh + console.error(`want to replace event ${replaces} with ${eventData.id} but replaced event not found`) + } + } + // add new event + const event = new Event(eventData) + this.map.set(id, event) + this.reactiveTimeline.addEvent(event) + } + } + this.broadcast("afterChange") + } + + removeEvent(id) { + if (!this.map.has(id)) throw new Error(`Tried to delete event ID ${id} which does not exist`) + this.map.get(id).removeEvent() + this.map.delete(id) + } + + getTimeline() { + return this.reactiveTimeline + } + + send(body) { + const tx = getTxnId() + const id = `pending$${tx}` + this.pending.add(id) + const content = { + msgtype: "m.text", + body, + "chat.carbon.message.pending_id": id + } + const fakeEvent = { + type: "m.room.message", + origin_server_ts: Date.now(), + event_id: id, + sender: lsm.get("mx_user_id"), + content, + pending: true + } + this.updateEvents([fakeEvent]) + return fetch(`${lsm.get("domain")}/_matrix/client/r0/rooms/${this.id}/send/m.room.message/${tx}?access_token=${lsm.get("access_token")}`, { + method: "PUT", + body: JSON.stringify(content), + headers: { + "Content-Type": "application/json" + } + })/*.then(() => { + const subscription = () => { + this.removeEvent(id) + this.unsubscribe("afterChange", subscription) + } + this.subscribe("afterChange", subscription) + })*/ + } +/* + getGroupedEvents() { + let currentSender = Symbol("N/A") + let groups = [] + let currentGroup = [] + for (const event of this.list) { + if (event.sender === currentSender) { + currentGroup.push(event) + } else { + if (currentGroup.length) groups.push(currentGroup) + currentGroup = [event] + currentSender = event.sender + } + } + if (currentGroup.length) groups.push(currentGroup) + return groups + } + */ +} + +export {Timeline} diff --git a/src/js/basic.js b/src/js/basic.js index 38d413c..1f3e695 100644 --- a/src/js/basic.js +++ b/src/js/basic.js @@ -19,12 +19,12 @@ const qa = s => document.querySelectorAll(s); */ class ElemJS { constructor(type) { - if (typeof type === "string") { - // Passed a tag name; create an element to bind to - this.bind(document.createElement(type)); - } else { - // Passed an existing element; bind to it + if (type instanceof HTMLElement) { + // If passed an existing element, bind to it this.bind(type); + } else { + // Otherwise, create a new detached element to bind to + this.bind(document.createElement(type)); } this.children = []; } @@ -157,4 +157,4 @@ function ejs(tag) { return new ElemJS(tag); } -module.exports = {q, qa, ElemJS, ejs} +export {q, qa, ElemJS, ejs} diff --git a/src/js/chat-input.js b/src/js/chat-input.js index a2fa323..de0eec7 100644 --- a/src/js/chat-input.js +++ b/src/js/chat-input.js @@ -1,93 +1,28 @@ -const {q} = require("./basic.js") -const {store} = require("./store/store.js") -const lsm = require("./lsm.js") -const {chat} = require("./chat.js") -const {toHTML} = require("discord-markdown") +import {q} from $to_relative "/js/basic.js" +import {store} from $to_relative "/js/store/store.js" +import * as lsm from $to_relative "/js/lsm.js" +import {chat} from $to_relative "/js/chat.js" const input = q("#c-chat-textarea") -class TypingManager { - constructor() { - /** How long to appear to type for. */ - this.time = 20000 - /** How long before the end of the timeout to send the request again. */ - this.margin = 5000 - /** The room that we're typing in. We can semantically only type in one room at a time. */ - this.typingRoom = null - this.timeout = null - } - - request(id, typing) { - const url = new URL(`${lsm.get("domain")}/_matrix/client/r0/rooms/${id}/typing/${lsm.get("mx_user_id")}`) - url.searchParams.set("access_token", lsm.get("access_token")) - const body = {typing} - if (typing) body.timeout = this.time - fetch(url.toString(), { - method: "PUT", - body: JSON.stringify(body) - }) - } - - schedule(id) { - this.request(id, true) - this.timeout = setTimeout(() => { - this.schedule(id) - }, this.time - this.margin) - } - - update(id) { - if (id) { // typing somewhere - if (this.typingRoom === id) return // already typing, don't do anything - // state - this.typingRoom = id - // mark and schedule - this.schedule(id) - // add self to typing list now instead of waiting a round trip - const typing = store.rooms.get(id).value().timeline.typing - typing.edit(list => list.concat(lsm.get("mx_user_id"))) - } else { // stopped typing - if (this.typingRoom) { - clearTimeout(this.timeout) - this.request(this.typingRoom, false) - } - this.typingRoom = null - } - } -} - -const typingManager = new TypingManager() - store.activeRoom.subscribe("changeSelf", () => { - // stop typing. you semantically can't type in a room you're not in. - typingManager.update(null) - // focus input box if (store.activeRoom.exists()) { input.focus() } }) input.addEventListener("keydown", event => { - if (!store.activeRoom.exists()) return - // send message? if (event.key === "Enter" && !event.shiftKey && !event.ctrlKey) { event.preventDefault() const body = input.value send(input.value) - typingManager.update(null) // stop typing input.value = "" fixHeight() - return } }) input.addEventListener("input", () => { fixHeight() - // set typing - if (input.value) { - typingManager.update(store.activeRoom.value().id) - } else { - typingManager.update(null) - } }) function fixHeight() { @@ -98,13 +33,5 @@ function fixHeight() { function send(body) { if (!store.activeRoom.exists()) return - if (!body.trim().length) return - const content = { - msgtype: "m.text", - format: "org.matrix.custom.html", - body, - formatted_body: toHTML(body), - "chat.carbon.message.input_body": body - } - return store.activeRoom.value().timeline.send("m.room.message", content) + return store.activeRoom.value().timeline.send(body) } diff --git a/src/js/chat.js b/src/js/chat.js index 6695c3a..e3df0eb 100644 --- a/src/js/chat.js +++ b/src/js/chat.js @@ -1,5 +1,5 @@ -const {ElemJS, q, ejs} = require("./basic.js") -const {store} = require("./store/store.js") +import {ElemJS, q, ejs} from $to_relative "/js/basic.js" +import {store} from $to_relative "/js/store/store.js" const chatMessages = q("#c-chat-messages") @@ -27,7 +27,7 @@ class Chat extends ElemJS { // connect to the new room's timeline updater if (store.activeRoom.exists()) { const timeline = store.activeRoom.value().timeline - const beforeChangeSubscription = () => { + const subscription = () => { // scroll anchor does not work if the timeline is scrolled to the top. // at the start, when there are not enough messages for a full screen, this is the case. // once there are enough messages that scrolling is necessary, we initiate a scroll down to activate the scroll anchor. @@ -40,29 +40,12 @@ class Chat extends ElemJS { } }, 0) } - this.addSubscription("beforeChange", timeline, beforeChangeSubscription) - - // Make sure after loading scrollback we don't move the scroll position - const beforeScrollbackLoadSubscription = () => { - const lastScrollHeight = chatMessages.scrollHeight; - - const afterScrollbackLoadSub = () => { - const scrollDiff = chatMessages.scrollHeight - lastScrollHeight; - chatMessages.scrollTop += scrollDiff; - - timeline.unsubscribe("afterScrollbackLoad", afterScrollbackLoadSub) - } - - timeline.subscribe("afterScrollbackLoad", afterScrollbackLoadSub) - } - this.addSubscription("beforeScrollbackLoad", timeline, beforeScrollbackLoadSubscription) + const name = "beforeChange" + this.removableSubscriptions.push({name, target: timeline, subscription}) + timeline.subscribe(name, subscription) } this.render() } - addSubscription(name, target, subscription) { - this.removableSubscriptions.push({name, target, subscription}) - target.subscribe(name, subscription) - } render() { this.clearChildren() @@ -79,4 +62,4 @@ class Chat extends ElemJS { const chat = new Chat() -module.exports = {chat} +export {chat} diff --git a/src/js/date-formatter.js b/src/js/date-formatter.js deleted file mode 100644 index c161d76..0000000 --- a/src/js/date-formatter.js +++ /dev/null @@ -1,3 +0,0 @@ -const dateFormatter = Intl.DateTimeFormat("default", {hour: "numeric", minute: "numeric", day: "numeric", month: "short", year: "numeric"}) - -module.exports = {dateFormatter} diff --git a/src/js/events/call.js b/src/js/events/call.js deleted file mode 100644 index a918a48..0000000 --- a/src/js/events/call.js +++ /dev/null @@ -1,67 +0,0 @@ -const {UngroupableEvent} = require("./event") -const {ejs} = require("../basic") -const lsm = require("../lsm") -const {extractDisplayName, resolveMxc, extractLocalpart} = require("../functions") - -class CallEvent extends UngroupableEvent { - constructor(data) { - super(data) - this.class("c-message-event") - this.senderName = extractLocalpart(this.data.sender) - this.render() - } - - renderInner(iconURL, elements) { - this.clearChildren() - this.child( - ejs("div").class("c-message-event__inner").child( - iconURL ? ejs("img").class("c-message-event__icon").attribute("width", "20").attribute("height", "20").attribute("src", iconURL) : "", - ...elements - ) - ) - super.render() - } -} - -class CallInviteEvent extends CallEvent { - static canRender(eventData) { - return eventData.type === "m.call.invite" - } - - render() { - const icon = this.data.sender === lsm.get("mx_user_id") ? "static/call-out.svg" : "static/call-in.svg" - this.renderInner(icon, [ - this.senderName, - " started a VOIP call, but Carbon doesn't support VOIP calls" - ]) - } -} - -class CallAnswerEvent extends CallEvent { - static canRender(eventData) { - return eventData.type === "m.call.answer" - } - - render() { - this.renderInner("static/call-accepted.svg", [ - this.senderName, - " answered the call" - ]) - } -} - -class CallHangupEvent extends CallEvent { - static canRender(eventData) { - return eventData.type === "m.call.hangup" - } - - render() { - const reason = this.data.content.reason === "invite_timeout" ? "missed the call" : "hung up the call" - this.renderInner("static/call-rejected.svg", [ - this.senderName, - " " + reason - ]) - } -} - -module.exports = [CallInviteEvent, CallAnswerEvent, CallHangupEvent] diff --git a/src/js/events/components.js b/src/js/events/components.js deleted file mode 100644 index 1de9d91..0000000 --- a/src/js/events/components.js +++ /dev/null @@ -1,36 +0,0 @@ -const {ElemJS} = require("../basic") -const {lazyLoad} = require("../lazy-load-module") - -class HighlightedCode extends ElemJS { - constructor(element) { - super(element) - if (this.element.tagName === "PRE" && this.element.children.length === 1 && this.element.children[0].tagName === "CODE") { - // we shouldn't nest inside
. put the text in 
 directly.
-			const code = this.element.children[0]
-			this.clearChildren()
-			while (code.firstChild) {
-				this.element.appendChild(code.firstChild)
-			}
-		}
-		let shouldHighlight = (
-			// if there are child _elements_, it's already formatted, we shouldn't mess that up
-			this.element.children.length === 0
-			/*
-			  no need to highlight very short code blocks:
-			  - content inside might not be code, some users still use code blocks
-			  for plaintext quotes
-			  - language detection will almost certainly be incorrect
-			  - even if it's code and the language is detected, the user will
-			  be able to mentally format small amounts of code themselves
-
-			  feel free to change the threshold number
-			*/
-				&& this.element.textContent.length > 80
-		)
-		if (shouldHighlight) {
-			lazyLoad("https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@10/build/highlight.min.js").then(hljs => hljs.highlightBlock(this.element))
-		}
-	}
-}
-
-module.exports = {HighlightedCode}
diff --git a/src/js/events/encrypted.js b/src/js/events/encrypted.js
deleted file mode 100644
index efc3ccf..0000000
--- a/src/js/events/encrypted.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const {GroupableEvent} = require("./event")
-const {ejs} = require("../basic")
-
-class EncryptedMessage extends GroupableEvent {
-	render() {
-		this.clearChildren()
-		this.child(
-			ejs("i").text("Carbon cannot render encrypted messages yet")
-		)
-		super.render()
-	}
-
-	static canRender(eventData) {
-		return eventData.type === "m.room.encrypted"
-	}
-}
-
-module.exports = [EncryptedMessage]
diff --git a/src/js/events/event.js b/src/js/events/event.js
deleted file mode 100644
index 040d94e..0000000
--- a/src/js/events/event.js
+++ /dev/null
@@ -1,72 +0,0 @@
-const {ElemJS, ejs} = require("../basic")
-const {dateFormatter} = require("../date-formatter")
-const {SubscribeSet} = require("../store/subscribe_set.js")
-
-class MatrixEvent extends ElemJS {
-	constructor(data) {
-		super("div")
-		this.data = null
-		this.group = null
-		this.editedAt = null
-		this.readBy = new SubscribeSet()
-		this.update(data)
-	}
-
-	// predicates
-
-	canGroup() {
-		return false
-	}
-
-	// operations
-
-	setGroup(group) {
-		this.group = group
-	}
-
-	setEdited(time) {
-		this.editedAt = time
-		this.render()
-	}
-
-	update(data) {
-		this.data = data
-		this.render()
-	}
-
-	removeEvent() {
-		if (this.group) this.group.removeEvent(this)
-		else this.remove()
-	}
-
-	render() {
-		this.element.classList[this.data.pending ? "add" : "remove"]("c-message--pending")
-		if (this.editedAt) {
-			this.child(ejs("span").class("c-message__edited").text("(edited)").attribute("title", "at " + dateFormatter.format(this.editedAt)))
-		}
-		return this
-	}
-
-	static canRender(eventData) {
-		return false
-	}
-}
-
-class GroupableEvent extends MatrixEvent {
-	constructor(data) {
-		super(data)
-		this.class("c-message")
-	}
-
-	canGroup() {
-		return true
-	}
-}
-
-class UngroupableEvent extends MatrixEvent {
-}
-
-module.exports = {
-	GroupableEvent,
-	UngroupableEvent
-}
diff --git a/src/js/events/hidden.js b/src/js/events/hidden.js
deleted file mode 100644
index 372bb72..0000000
--- a/src/js/events/hidden.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const {UngroupableEvent} = require("./event")
-
-class HiddenEvent extends UngroupableEvent {
-	constructor(data) {
-		super(data)
-		this.class("c-hidden-event")
-		this.clearChildren()
-	}
-
-	static canRender(eventData) {
-		return ["m.reaction", "m.call.candidates"].includes(eventData.type)
-	}
-
-	render() {
-	}
-}
-
-module.exports = [HiddenEvent]
diff --git a/src/js/events/image.js b/src/js/events/image.js
deleted file mode 100644
index 1a32bcf..0000000
--- a/src/js/events/image.js
+++ /dev/null
@@ -1,48 +0,0 @@
-const {ejs, ElemJS} = require("../basic")
-const {resolveMxc} = require("../functions")
-const {GroupableEvent} = require("./event")
-
-class Image extends GroupableEvent {
-	render() {
-		this.clearChildren()
-		this.class("c-message--media")
-		const image = (
-			ejs("img")
-				.class("c-message__image")
-				.attribute("src", resolveMxc(this.data.content.url))
-		)
-		const info = this.data.content.info
-		if (info && info.w && info.h) {
-			image.attribute("width", info.w)
-			image.attribute("height", info.h)
-		}
-		const wrapper = ejs("div").class("c-media__wrapper").child(
-			image
-		)
-		if (this.data.content.body && this.data.content.body.startsWith("SPOILER")) {
-			wrapper.attribute("tabindex", 0)
-			wrapper.class("c-media--spoiler")
-			const wall = ejs("div").class("c-media__spoiler").text("Spoiler")
-			wrapper.child(wall)
-			const toggle = () => {
-				wrapper.element.classList.toggle("c-media--shown")
-			}
-			wrapper.on("click", toggle)
-			wrapper.on("keydown", event => {
-				if (event.key === "Enter") toggle()
-			})
-		}
-		this.child(wrapper)
-		super.render()
-	}
-
-	static canRender(event) {
-		return event.type === "m.room.message" && event.content.msgtype === "m.image"
-	}
-
-	canGroup() {
-		return true
-	}
-}
-
-module.exports = [Image]
diff --git a/src/js/events/membership.js b/src/js/events/membership.js
deleted file mode 100644
index 5617d3e..0000000
--- a/src/js/events/membership.js
+++ /dev/null
@@ -1,127 +0,0 @@
-const {UngroupableEvent} = require("./event")
-const {ejs} = require("../basic")
-const {extractDisplayName, resolveMxc, extractLocalpart} = require("../functions")
-
-class MembershipEvent extends UngroupableEvent {
-	constructor(data) {
-		super(data)
-		this.class("c-message-event")
-		this.senderName = extractDisplayName(data)
-		if (data.content.avatar_url) {
-			this.smallAvatar = ejs("img")
-				.attribute("width", "32")
-				.attribute("height", "32")
-				.attribute("src", resolveMxc(data.content.avatar_url, 32, "crop"))
-				.class("c-message-event__avatar")
-		} else {
-			this.smallAvatar = ""
-		}
-		this.render()
-	}
-
-	static canRender(eventData) {
-		return eventData.type === "m.room.member"
-	}
-
-	renderInner(iconURL, elements) {
-		this.clearChildren()
-		this.child(
-			ejs("div").class("c-message-event__inner").child(
-				iconURL ? ejs("img").class("c-message-event__icon").attribute("width", "20").attribute("height", "20").attribute("src", iconURL) : "",
-				...elements
-			)
-		)
-		super.render()
-	}
-}
-
-
-class JoinedEvent extends MembershipEvent {
-	static canRender(eventData) {
-		return super.canRender(eventData) && eventData.content.membership === "join"
-	}
-
-	render() {
-		const changes = []
-		const prev = this.data.unsigned.prev_content
-		if (prev && prev.membership === "join") {
-			if (prev.avatar_url !== this.data.content.avatar_url) {
-				changes.push("changed their avatar")
-			}
-			if (prev.displayname !== this.data.content.displayname) {
-				changes.push(`changed their display name (was ${this.data.unsigned.prev_content.displayname})`)
-			}
-		}
-		let message
-		let iconURL
-		if (changes.length) {
-			message = " " + changes.join(", ")
-			iconURL = "static/profile-event.svg"
-		} else {
-			message = " joined the room"
-			iconURL = "static/join-event.svg"
-		}
-		this.renderInner(iconURL, [
-			this.smallAvatar,
-			this.senderName,
-			message
-		])
-	}
-}
-
-class InvitedEvent extends MembershipEvent {
-	static canRender(eventData) {
-		return super.canRender(eventData) && eventData.content.membership === "invite"
-	}
-
-	render() {
-		this.renderInner("static/invite-event.svg", [
-			this.smallAvatar,
-			`${extractLocalpart(this.data.sender)} invited ${this.data.state_key}` // full mxid for clarity
-		])
-	}
-}
-
-class LeaveEvent extends MembershipEvent {
-	static canRender(eventData) {
-		return super.canRender(eventData) && eventData.content.membership === "leave"
-	}
-
-	render() {
-		this.renderInner("static/leave-event.svg", [
-			this.smallAvatar,
-			this.senderName,
-			" left the room"
-		])
-	}
-}
-
-class BanEvent extends MembershipEvent {
-	static canRender(eventData) {
-		return super.canRender(eventData) && eventData.content.membership === "ban"
-	}
-
-	render() {
-		let message =
-			 ` left (banned by ${this.data.sender}`
-			 + (this.data.content.reason ? `, reason: ${this.data.content.reason}` : "")
-			 + ")"
-		this.renderInner("static/leave-event.svg", [
-			this.smallAvatar,
-			this.senderName,
-			message
-		])
-	}
-}
-
-class UnknownMembership extends MembershipEvent {
-	render() {
-		this.renderInner("", [
-			this.smallAvatar,
-			this.senderName,
-			ejs("i").text(" unknown membership event")
-		])
-	}
-}
-
-module.exports = [JoinedEvent, InvitedEvent, LeaveEvent, BanEvent, UnknownMembership]
diff --git a/src/js/events/message.js b/src/js/events/message.js
deleted file mode 100644
index ad885ff..0000000
--- a/src/js/events/message.js
+++ /dev/null
@@ -1,164 +0,0 @@
-const {ejs, ElemJS} = require("../basic")
-const {HighlightedCode} = require("./components")
-const DOMPurify = require("dompurify")
-const {resolveMxc} = require("../functions")
-const {GroupableEvent} = require("./event")
-
-const purifier = DOMPurify()
-
-purifier.addHook("uponSanitizeAttribute", (node, hookevent, config) => {
-	// If purifier already rejected an attribute there is no point in checking it
-	if (hookevent.keepAttr === false) return;
-
-	const allowedElementAttributes = {
-		"FONT": ["data-mx-bg-color", "data-mx-color", "color"],
-		"SPAN": ["data-mx-bg-color", "data-mx-color", "data-mx-spoiler"],
-		"A": ["name", "target", "href"],
-		"IMG": ["width", "height", "alt", "title", "src", "data-mx-emoticon"],
-		"OL": ["start"],
-		"CODE": ["class"],
-	}
-
-	const allowedAttributes = allowedElementAttributes[node.tagName] || []
-	hookevent.keepAttr = allowedAttributes.indexOf(hookevent.attrName) > -1
-})
-
-purifier.addHook("uponSanitizeElement", (node, hookevent, config) => {
-	// Remove bad classes from our code element
-	if (node.tagName === "CODE") {
-		node.classList.forEach(c => {
-			if (!c.startsWith("language-")) {
-				node.classList.remove(c)
-			}
-		})
-	}
-	if (node.tagName === "A") {
-		node.setAttribute("rel", "noopener") // prevent the opening page from accessing carbon
-		node.setAttribute("target", "_blank") // open in a new tab instead of replacing carbon
-	}
-	return node
-})
-
-function cleanHTML(html) {
-	const config = {
-		ALLOWED_TAGS: [
-			"font", "del", "h1", "h2", "h3", "h4", "h5", "h6", "blockquote", "p",
-			"a", "ul", "ol", "sup", "sub", "li", "b", "i", "u", "strong", "em",
-			"strike", "code", "hr", "br", "div", "table", "thead", "tbody", "tr",
-			"th", "td", "caption", "pre", "span", "img",
-			// matrix tags
-			"mx-reply"
-		],
-
-		// In case we mess up in the uponSanitizeAttribute hook
-		ALLOWED_ATTR: [
-			"color", "name", "target", "href", "width", "height", "alt", "title",
-			"src", "start", "class", "noreferrer", "noopener",
-			// matrix attrs
-			"data-mx-emoticon", "data-mx-bg-color", "data-mx-color", "data-mx-spoiler"
-		],
-
-		// Return a DOM fragment instead of a string, avoids potential future mutation XSS
-		// should also be faster than the browser parsing HTML twice
-		// https://research.securitum.com/mutation-xss-via-mathml-mutation-dompurify-2-0-17-bypass/
-		RETURN_DOM_FRAGMENT: true,
-		RETURN_DOM_IMPORT: true
-	}
-	return purifier.sanitize(html, config)
-}
-
-// Here we put all the processing of the messages that isn't as likely to potentially lead to security issues
-function postProcessElements(element) {
-	element.querySelectorAll("pre").forEach(n => {
-		new HighlightedCode(n)
-	})
-
-	element.querySelectorAll("img").forEach(n => {
-		let src = n.getAttribute("src")
-		if (src) src = resolveMxc(src)
-		n.setAttribute("src", src)
-	})
-
-	element.querySelectorAll("font, span").forEach(n => {
-		const color = n.getAttribute("data-mx-color") || n.getAttribute("color")
-		const bgColor = n.getAttribute("data-mx-bg-color")
-		if (color) n.style.color = color
-		if (bgColor) n.style.backgroundColor = bgColor
-	})
-
-	element.querySelectorAll("[data-mx-spoiler]").forEach(spoiler => {
-		spoiler.classList.add("mx-spoiler")
-		spoiler.setAttribute("tabindex", 0)
-		function toggle() {
-			spoiler.classList.toggle("mx-spoiler--shown")
-		}
-		spoiler.addEventListener("click", toggle)
-		spoiler.addEventListener("keydown", event => {
-			if (event.key === "Enter") toggle()
-		})
-	})
-}
-
-
-class HTMLMessage extends GroupableEvent {
-	render() {
-		this.clearChildren()
-
-		let html = this.data.content.formatted_body
-
-		const fragment = cleanHTML(html)
-		postProcessElements(fragment)
-
-		this.child(ejs(fragment))
-
-		super.render()
-	}
-
-	static canRender(event) {
-		const content = event.content
-		return (
-			event.type === "m.room.message"
-				&& (content.msgtype === "m.text" || content.msgtype === "m.notice")
-				&& content.format === "org.matrix.custom.html"
-				&& content.formatted_body
-		)
-	}
-}
-
-function autoLinkText(text) {
-	const fragment = ejs(new DocumentFragment())
-	let lastIndex = 0
-	text.replace(/https?:\/\/(?:[A-Za-z-]+\.)+[A-Za-z]{1,10}(?::[0-9]{1,6})?(?:\/[^ ]*)?/g, (url, index) => {
-		// add text before URL
-		fragment.addText(text.slice(lastIndex, index))
-		// add URL
-		fragment.child(
-			ejs("a")
-				.attribute("target", "_blank")
-				.attribute("noopener", "")
-				.attribute("href", url)
-				.addText(url)
-		)
-		// update state
-		lastIndex = index + url.length
-	})
-	// add final text
-	fragment.addText(text.slice(lastIndex))
-	return fragment
-}
-
-class TextMessage extends GroupableEvent {
-	render() {
-		this.clearChildren()
-		this.class("c-message--plain")
-		const fragment = autoLinkText(this.data.content.body)
-		this.child(fragment)
-		super.render()
-	}
-
-	static canRender(event) {
-		return event.type === "m.room.message"
-	}
-}
-
-module.exports = [HTMLMessage, TextMessage]
diff --git a/src/js/events/render-event.js b/src/js/events/render-event.js
deleted file mode 100644
index 620da3e..0000000
--- a/src/js/events/render-event.js
+++ /dev/null
@@ -1,24 +0,0 @@
-const imageEvent = require("./image")
-const messageEvent = require("./message")
-const encryptedEvent = require("./encrypted")
-const membershipEvent = require("./membership")
-const unknownEvent = require("./unknown")
-const callEvent = require("./call")
-const hiddenEvent = require("./hidden")
-
-const events = [
-	...imageEvent,
-	...messageEvent,
-	...encryptedEvent,
-	...membershipEvent,
-	...callEvent,
-	...hiddenEvent,
-	...unknownEvent,
-]
-
-function renderEvent(eventData) {
-	const constructor = events.find(e => e.canRender(eventData))
-	return new constructor(eventData)
-}
-
-module.exports = {renderEvent}
diff --git a/src/js/events/unknown.js b/src/js/events/unknown.js
deleted file mode 100644
index 5133aa8..0000000
--- a/src/js/events/unknown.js
+++ /dev/null
@@ -1,19 +0,0 @@
-const {GroupableEvent} = require("./event")
-const {ejs} = require("../basic")
-
-class UnknownEvent extends GroupableEvent {
-	static canRender() {
-		return true
-	}
-
-	render() {
-		this.clearChildren()
-		this.child(
-			ejs("i").text(`Unknown event of type ${this.data.type}`)
-		)
-		super.render()
-	}
-}
-
-module.exports = [UnknownEvent]
-
diff --git a/src/js/focus.js b/src/js/focus.js
deleted file mode 100644
index 2413484..0000000
--- a/src/js/focus.js
+++ /dev/null
@@ -1,11 +0,0 @@
-document.body.classList.remove("show-focus")
-
-document.addEventListener("mousedown", () => {
-	document.body.classList.remove("show-focus")
-})
-
-document.addEventListener("keydown", event => {
-	if (event.key === "Tab") {
-		document.body.classList.add("show-focus")
-	}
-})
diff --git a/src/js/functions.js b/src/js/functions.js
index 3c346c4..299d8a9 100644
--- a/src/js/functions.js
+++ b/src/js/functions.js
@@ -1,10 +1,7 @@
-const lsm = require("./lsm.js")
+import * as lsm from $to_relative "/js/lsm.js"
 
 function resolveMxc(url, size, method) {
-	const match = url.match(/^mxc:\/\/([^/]+)\/(.*)/)
-	if (!match) return url
-	let [server, id] = match.slice(1)
-	id = id.replace(/#.*$/, "")
+	const [server, id] = url.match(/^mxc:\/\/([^/]+)\/(.*)/).slice(1)
 	if (size && method) {
 		return `${lsm.get("domain")}/_matrix/media/r0/thumbnail/${server}/${id}?width=${size}&height=${size}&method=${method}`
 	} else {
@@ -12,28 +9,4 @@ function resolveMxc(url, size, method) {
 	}
 }
 
-function extractLocalpart(mxid) {
-	// try to extract the localpart from the mxid
-	let match = mxid.match(/^@([^:]+):/)
-	if (match) {
-		return match[1]
-	}
-	// localpart extraction failed, use the whole mxid
-	return mxid
-}
-
-function extractDisplayName(stateEvent) {
-	const mxid = stateEvent.state_key
-	// see if a display name is set
-	if (stateEvent.content.displayname) {
-		return stateEvent.content.displayname
-	}
-	// fall back to the mxid
-	return extractLocalpart(mxid)
-}
-
-module.exports = {
-	resolveMxc,
-	extractLocalpart,
-	extractDisplayName
-}
+export {resolveMxc}
diff --git a/src/js/groups.js b/src/js/groups.js
index 38b6706..e49ade4 100644
--- a/src/js/groups.js
+++ b/src/js/groups.js
@@ -1,4 +1,4 @@
-const {q} = require("./basic.js")
+import {q} from $to_relative "/js/basic.js"
 
 let state = "CLOSED"
 
diff --git a/src/js/lazy-load-module.js b/src/js/lazy-load-module.js
deleted file mode 100644
index efe642d..0000000
--- a/src/js/lazy-load-module.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// I hate this with passion
-async function lazyLoad(url) {
-	const cache = window.lazyLoadCache || new Map()
-	window.lazyLoadCache = cache
-	if (cache.get(url)) return cache.get(url)
-
-	const module = loadModuleWithoutCache(url)
-	cache.set(url, module)
-	return module
-}
-
-// Loads the module without caching
-async function loadModuleWithoutCache(url) {
-	const src = await fetch(url).then(r => r.text())
-	let module = {}
-	eval(src)
-	return module.exports
-}
-
-module.exports = {lazyLoad}
diff --git a/src/js/login.js b/src/js/login.js
deleted file mode 100644
index 4ae9eae..0000000
--- a/src/js/login.js
+++ /dev/null
@@ -1,167 +0,0 @@
-const {q, ElemJS, ejs} = require("./basic.js")
-
-const password = q("#password")
-const homeserver = q("#homeserver")
-
-class Username extends ElemJS {
-	constructor() {
-		super(q("#username"))
-
-		this.on("change", this.updateServer.bind(this))
-	}
-
-	isValid() {
-		return !!this.element.value.match(/^@?[a-z0-9._=\/-]+(?::[a-zA-Z0-9.:\[\]-]+)?$/)
-	}
-
-	getUsername() {
-		return this.element.value.match(/^@?([a-z0-9._=\/-]+)/)[1]
-	}
-
-	getServer() {
-		const server = this.element.value.match(/^@?[a-z0-9._=\?-]+:([a-zA-Z0-9.:\[\]-]+)$/)
-		if (server && server[1]) return server[1]
-		else return null
-	}
-
-	updateServer() {
-		if (!this.isValid()) return
-		if (this.getServer()) homeserver.value = this.getServer()
-	}
-}
-
-const username = new Username()
-
-class Feedback extends ElemJS {
-	constructor() {
-		super(q("#feedback"))
-		this.loading = false
-		this.loadingIcon = ejs("span").class("loading-icon")
-		this.messageSpan = ejs("span")
-		this.child(this.messageSpan)
-	}
-
-	setLoading(state) {
-		if (this.loading && !state) {
-			this.loadingIcon.remove()
-		} else if (!this.loading && state) {
-			this.childAt(0, this.loadingIcon)
-		}
-		this.loading = state
-	}
-
-	message(content, isError) {
-		this.removeClass("form-feedback")
-		this.removeClass("form-error")
-		if (content) this.class("form-feedback")
-		if(isError) this.class("form-error")
-
-		this.messageSpan.text(content)
-	}
-}
-
-const feedback = new Feedback()
-
-class Form extends ElemJS {
-	constructor() {
-		super(q("#form"))
-
-		this.processing = false
-
-		this.on("submit", this.submit.bind(this))
-	}
-
-	async submit() {
-		if (this.processing) return
-		this.processing = true
-		if (!username.isValid()) return this.cancel("Username is not valid.")
-
-		// Resolve homeserver address
-		let domain
-		try {
-			domain = await this.findHomeserver(homeserver.value)
-		} catch(e) {
-			return this.cancel(e.message)
-		}
-
-		// Request access token
-		this.status("Logging in...")
-		const root = await fetch(`${domain}/_matrix/client/r0/login`, {
-			method: "POST",
-			body: JSON.stringify({
-				type: "m.login.password",
-				user: username.getUsername(),
-				password: password.value
-			})
-		}).then(res => res.json())
-
-		if (!root.access_token) {
-			if (root.error) {
-				this.cancel(`Server said: ${root.error}`)
-			} else {
-				this.cancel("Login mysteriously failed.")
-				console.error(root)
-			}
-			return
-		}
-
-		localStorage.setItem("mx_user_id", root.user_id)
-		localStorage.setItem("domain", domain)
-		localStorage.setItem("access_token", root.access_token)
-
-		location.assign("../")
-	}
-
-	async findHomeserver(address, maxDepth = 5) {
-
-		//Protects from servers sending us on a redirect loop
-		maxDepth--
-		if (maxDepth <= 0) throw new Error(`Failed to look up homeserver, maximum search depth reached`)
-	
-		//Normalise the address
-		if (!address.match(/^https?:\/\//)) {
-			console.warn(`${address} doesn't specify the protocol, assuming https`)
-			address = "https://" + address
-		}
-		address = address.replace(/\/*$/, "")
-		
-		this.status(`Looking up homeserver... trying ${address}`)
-	
-		// Check if we found the actual matrix server
-		try {
-			const versionsReq = await fetch(`${address}/_matrix/client/versions`)
-			if (versionsReq.ok) {
-				const versions = await versionsReq.json()
-				if (Array.isArray(versions.versions)) return address
-			}
-		} catch(e) {}
-	
-		// Find the next matrix server in the chain
-		const root = await fetch(`${address}/.well-known/matrix/client`).then(res => res.json()).catch(e => {
- 			console.error(e)
-			throw new Error(`Failed to look up server ${address}`)
-		})
-
-		let nextAddress = root["m.homeserver"].base_url
-		nextAddress = nextAddress.replace(/\/*$/, "")
-
-		if (address === nextAddress) {
-			throw new Error(`Failed to look up server ${address}, /.well-known/matrix/client found a redirect loop`);
-		}
-
-		return this.findHomeserver(nextAddress, maxDepth)
-	}
-
-	status(message) {
-		feedback.setLoading(true)
-		feedback.message(message)
-	}
-
-	cancel(message) {
-		this.processing = false
-		feedback.setLoading(false)
-		feedback.message(message, true)
-	}
-}
-
-const form = new Form()
diff --git a/src/js/lsm.js b/src/js/lsm.js
index 7e9ad4d..7338343 100644
--- a/src/js/lsm.js
+++ b/src/js/lsm.js
@@ -8,4 +8,4 @@ function set(name, value) {
 
 window.lsm = {get, set}
 
-module.exports = {get, set}
+export {get, set}
diff --git a/src/js/main.js b/src/js/main.js
deleted file mode 100644
index 1bc0be0..0000000
--- a/src/js/main.js
+++ /dev/null
@@ -1,11 +0,0 @@
-require("./focus.js")
-const groups = require("./groups.js")
-const chat_input = require("./chat-input.js")
-const room_picker = require("./room-picker.js")
-const sync = require("./sync/sync.js")
-const chat = require("./chat.js")
-require("./typing.js")
-
-if (!localStorage.getItem("access_token")) {
-	location.assign("./login/")
-}
diff --git a/src/js/read-marker.js b/src/js/read-marker.js
deleted file mode 100644
index 53b4658..0000000
--- a/src/js/read-marker.js
+++ /dev/null
@@ -1,149 +0,0 @@
-const {ElemJS, ejs, q} = require("./basic.js")
-const {store} = require("./store/store.js")
-const lsm = require("./lsm.js")
-
-function markFullyRead(roomID, eventID) {
-	return fetch(`${lsm.get("domain")}/_matrix/client/r0/rooms/${roomID}/read_markers?access_token=${lsm.get("access_token")}`, {
-		method: "POST",
-		body: JSON.stringify({
-			"m.fully_read": eventID,
-			"m.read": eventID
-		})
-	})
-}
-
-class ReadBanner extends ElemJS {
-	constructor() {
-		super(q("#c-chat-banner"))
-
-		this.newMessages = ejs("span")
-		this.child(
-			ejs("div").class("c-chat-banner__inner").child(
-				ejs("button").class("c-chat-banner__part").on("click", this.jumpTo.bind(this)).child(
-					ejs("div").class("c-chat-banner__part-inner")
-						.child(this.newMessages)
-						.addText(" new messages")
-				),
-				ejs("button").class("c-chat-banner__part", "c-chat-banner__last").on("click", this.markRead.bind(this)).child(
-					ejs("div").class("c-chat-banner__part-inner").text("Mark as read")
-				)
-			)
-		)
-
-		store.activeRoom.subscribe("changeSelf", this.render.bind(this))
-		store.notificationsChange.subscribe("changeSelf", this.render.bind(this))
-		this.render()
-	}
-
-	async jumpTo() {
-		if (!store.activeRoom.exists()) return
-		const timeline = store.activeRoom.value().timeline
-		const readMarker = timeline.readMarker
-		while (true) {
-			if (readMarker.attached) {
-				readMarker.element.scrollIntoView({behavior: "smooth", block: "center"})
-				return
-			} else {
-				q("#c-chat-messages").scrollTo({
-					top: 0,
-					left: 0,
-					behavior: "smooth"
-				})
-				await new Promise(resolve => {
-					const unsubscribe = timeline.subscribe("afterScrollbackLoad", () => {
-						unsubscribe()
-						resolve()
-					})
-				})
-			}
-		}
-	}
-
-	markRead() {
-		if (!store.activeRoom.exists()) return
-		const timeline = store.activeRoom.value().timeline
-		markFullyRead(timeline.id, timeline.latestEventID)
-	}
-
-	render() {
-		let count = 0
-		if (store.activeRoom.exists()) {
-			count = store.activeRoom.value().number.state.unreads
-		}
-		if (count !== 0) {
-			this.newMessages.text(count)
-			this.class("c-chat-banner--active")
-		} else {
-			this.removeClass("c-chat-banner--active")
-		}
-	}
-}
-const readBanner = new ReadBanner()
-
-class ReadMarker extends ElemJS {
-	constructor(timeline) {
-		super("div")
-
-		this.class("c-read-marker")
-		this.loadingIcon = ejs("div")
-			.class("c-read-marker__loading", "loading-icon")
-			.style("display", "none")
-		this.child(
-			ejs("div").class("c-read-marker__inner").child(
-				ejs("div").class("c-read-marker__text").child(this.loadingIcon).addText("New")
-			)
-		)
-
-		let processing = false
-		const observer = new IntersectionObserver(entries => {
-			const entry = entries[0]
-			if (!entry.isIntersecting) return
-			if (processing) return
-			processing = true
-			this.loadingIcon.style("display", "")
-			markFullyRead(this.timeline.id, this.timeline.latestEventID).then(() => {
-				this.loadingIcon.style("display", "none")
-				processing = false
-			})
-		}, {
-			root: document.getElementById("c-chat-messages"),
-			rootMargin: "-80px 0px 0px 0px", // marker must be this distance inside the top of the screen to be counted as read
-			threshold: 0.01
-		})
-		observer.observe(this.element)
-
-		this.attached = false
-		this.timeline = timeline
-		this.timeline.userReads.get(lsm.get("mx_user_id")).subscribe("changeSelf", (_, eventID) => {
-			// read marker updated, attach to it
-			const event = this.timeline.map.get(eventID)
-			this.attach(event)
-		})
-		this.timeline.subscribe("afterChange", () => {
-			// timeline has new events, attach to last read one
-			const eventID = this.timeline.userReads.get(lsm.get("mx_user_id")).value()
-			const event = this.timeline.map.get(eventID)
-			this.attach(event)
-		})
-	}
-
-	attach(event) {
-		if (event && event.data.origin_server_ts !== this.timeline.latest) {
-			this.class("c-read-marker--attached")
-			event.element.insertAdjacentElement("beforeend", this.element)
-			this.attached = true
-		} else {
-			this.removeClass("c-read-marker--attached")
-			this.attached = false
-		}
-		if (store.activeRoom.value() === this.timeline.room) {
-			readBanner.render()
-		}
-	}
-}
-
-module.exports = {
-	ReadMarker,
-	readBanner,
-	markFullyRead
-}
diff --git a/src/js/room-picker.js b/src/js/room-picker.js
index 9192ae9..8e696de 100644
--- a/src/js/room-picker.js
+++ b/src/js/room-picker.js
@@ -1,10 +1,10 @@
-const {q, ElemJS, ejs} = require("./basic.js")
-const {store} = require("./store/store.js")
-const {SubscribeMapList} = require("./store/subscribe_map_list.js")
-const {SubscribeValue} = require("./store/subscribe_value.js")
-const {Timeline} = require("./timeline.js")
-const lsm = require("./lsm.js")
-const {resolveMxc, extractLocalpart, extractDisplayName} = require("./functions.js")
+import {q, ElemJS, ejs} from $to_relative "/js/basic.js"
+import {store} from $to_relative "/js/store/store.js"
+import {SubscribeMapList} from $to_relative "/js/store/SubscribeMapList.js"
+import {SubscribeValue} from $to_relative "/js/store/SubscribeValue.js"
+import {Timeline} from $to_relative "/js/Timeline.js"
+import * as lsm from $to_relative "/js/lsm.js"
+import {resolveMxc} from $to_relative "/js/functions.js"
 
 class ActiveGroupMarker extends ElemJS {
 	constructor() {
@@ -25,43 +25,12 @@ class ActiveGroupMarker extends ElemJS {
 
 const activeGroupMarker = new ActiveGroupMarker()
 
-class GroupNotifier extends ElemJS {
-	constructor() {
-		super("div")
-
-		this.class("c-group__number")
-		this.state = {}
-		this.render()
-	}
-
-	update(state) {
-		Object.assign(this.state, state)
-		this.render()
-	}
-
-	clear() {
-		this.state = {}
-		this.render()
-	}
-
-	render() {
-		let total = Object.values(this.state).reduce((a, c) => a + c, 0)
-		if (total > 0) {
-			this.text(total)
-			this.class("c-group__number--active")
-		} else {
-			this.removeClass("c-group__number--active")
-		}
-	}
-}
-
 class Group extends ElemJS {
 	constructor(key, data) {
 		super("div")
 
 		this.data = data
 		this.order = this.data.order
-		this.number = new GroupNotifier()
 
 		this.class("c-group")
 		this.child(
@@ -69,7 +38,6 @@ class Group extends ElemJS {
 			 ? ejs("img").class("c-group__icon").attribute("src", this.data.icon)
 			 : ejs("div").class("c-group__icon")
 			),
-			this.number,
 			ejs("div").class("c-group__name").text(this.data.name)
 		)
 
@@ -88,73 +56,12 @@ class Group extends ElemJS {
 	}
 }
 
-class RoomNotifier extends ElemJS {
-	constructor(room) {
-		super("div")
-
-		this.class("c-room__number")
-
-		this.room = room
-		this.classes = [
-			"notifications",
-			"unreads",
-			"none"
-		]
-		this.state = {
-			notifications: 0,
-			unreads: 0
-		}
-		this.render()
-	}
-
-	/**
-	 * @param {object} state
-	 * @param {number} [state.notifications]
-	 * @param {number} [state.unreads]
-	 */
-	update(state) {
-		Object.assign(this.state, state)
-		this.informGroup()
-		this.render()
-	}
-
-	informGroup() {
-		this.room.getGroup().number.update({[this.room.id]: (
-			this.state.notifications || (this.state.unreads ? 1 : 0)
-		)})
-	}
-
-	render() {
-		const display = {
-			number: this.state.notifications || this.state.unreads,
-			kind: this.state.notifications ? "notifications" : "unreads"
-		}
-		// set number
-		if (display.number) {
-			this.text(display.number)
-		} else {
-			this.text("")
-			display.kind = "none"
-		}
-		// set class
-		this.classes.forEach(c => {
-			const name = "c-room__number--" + c
-			if (c === display.kind) {
-				this.class(name)
-			} else {
-				this.removeClass(name)
-			}
-		})
-	}
-}
-
 class Room extends ElemJS {
 	constructor(id, data) {
 		super("div")
 
 		this.id = id
 		this.data = data
-		this.number = new RoomNotifier(this)
 		this.timeline = new Timeline(this)
 		this.group = null
 		this.members = new SubscribeMapList(SubscribeValue)
@@ -168,80 +75,43 @@ class Room extends ElemJS {
 	}
 
 	get order() {
-		let string = ""
-		if (this.number.state.notifications) {
-			string += "N"
-		} else if (this.number.state.unreads) {
-			string += "U"
-		} else {
-			string += "_"
-		}
 		if (this.group) {
-			string += this.name
+			let chars = 36
+			let total = 0
+			const name = this.getName()
+			for (let i = 0; i < name.length; i++) {
+				const c = name[i]
+				let d = 0
+				if (c >= "A" && c <= "Z") d = c.charCodeAt(0) - 65 + 10
+				else if (c >= "a" && c <= "z") d = c.charCodeAt(0) - 97 + 10
+				else if (c >= "0" && c <= "9") d = +c
+				total += d * chars ** (-i)
+			}
+			return total
 		} else {
-			string += (4000000000000 - this.timeline.latest) // good until 2065 :)
-		}
-		return string
-	}
-
-	getMemberName(mxid) {
-		if (this.members.has(mxid)) {
-			const state = this.members.get(mxid).value()
-			return extractDisplayName(state)
-		} else {
-			return extractLocalpart(mxid)
-		}
-	}
-
-	getHeroes() {
-		if (this.data.summary) {
-			return this.data.summary["m.heroes"]
-		} else {
-			const me = lsm.get("mx_user_id")
-			return this.data.state.events.filter(e => e.type === "m.room.member" && e.content.membership === "join" && e.state_key !== me).map(e => e.state_key)
+			return -this.timeline.latest
 		}
 	}
 
 	getName() {
-		// if the room has a name
 		let name = this.data.state.events.find(e => e.type === "m.room.name")
-		if (name && name.content.name) {
-			return name.content.name
+		if (name) {
+			name = name.content.name
+		} else {
+			const users = this.data.summary["m.heroes"]
+			const usernames = users.map(u => (u.match(/^@([^:]+):/) || [])[1] || u)
+			name = usernames.join(", ")
 		}
-		// if the room has no name, use its canonical alias
-		let canonicalAlias = this.data.state.events.find(e => e.type === "m.room.canonical_alias")
-		if (canonicalAlias && canonicalAlias.content.alias) {
-			return canonicalAlias.content.alias
-		}
-		// if the room has no alias, use the names of its members ("heroes")
-		const users = this.getHeroes()
-		if (users && users.length) {
-			const usernames = users.map(mxid => this.getMemberName(mxid))
-			return usernames.join(", ")
-		}
-		// the room is empty
-		return "Empty room"
+		return name
 	}
 
 	getIcon() {
-		// if the room has a normal avatar
 		const avatar = this.data.state.events.find(e => e.type === "m.room.avatar")
 		if (avatar) {
-			const url = avatar.content.url || avatar.content.avatar_url
-			if (url) {
-				return resolveMxc(url, 32, "crop")
-			}
+			return resolveMxc(avatar.content.url || avatar.content.avatar_url, 32, "crop")
+		} else {
+			return null
 		}
-		// if the room has no avatar set, use a member's avatar
-		const users = this.getHeroes()
-		if (users && users[0] && this.members.has(users[0])) {
-			// console.log(users[0], this.members.get(users[0]))
-			const userAvatar = this.members.get(users[0]).value().content.avatar_url
-			if (userAvatar) {
-				return resolveMxc(userAvatar, 32, "crop")
-			}
-		}
-		return null
 	}
 
 	isDirect() {
@@ -274,7 +144,6 @@ class Room extends ElemJS {
 			this.child(ejs("div").class("c-room__icon", "c-room__icon--no-icon"))
 		}
 		this.child(ejs("div").class("c-room__name").text(this.getName()))
-		this.child(this.number)
 		// active
 		const active = store.activeRoom.value() === this
 		this.element.classList[active ? "add" : "remove"]("c-room--active")
@@ -294,7 +163,6 @@ class Rooms extends ElemJS {
 		store.activeGroup.subscribe("changeSelf", this.render.bind(this))
 		store.directs.subscribe("changeItem", this.render.bind(this))
 		store.newEvents.subscribe("changeSelf", this.sort.bind(this))
-		store.notificationsChange.subscribe("changeSelf", this.sort.bind(this))
 
 		this.render()
 	}
@@ -355,12 +223,8 @@ class Groups extends ElemJS {
 	render() {
 		this.clearChildren()
 		store.groups.forEach((key, item) => {
-			item.value().number.clear()
 			this.child(item.value())
 		})
-		store.rooms.forEach((id, room) => {
-			room.value().number.informGroup() // update group notification number
-		})
 	}
 }
 const groups = new Groups()
diff --git a/src/js/sender.js b/src/js/sender.js
deleted file mode 100644
index 55943dc..0000000
--- a/src/js/sender.js
+++ /dev/null
@@ -1,120 +0,0 @@
-const {ElemJS, ejs} = require("./basic.js")
-const {store} = require("./store/store.js")
-const {resolveMxc} = require("./functions.js")
-
-function nameToColor(str) {
-	// code from element's react sdk
-	const colors = ["#55a7f0", "#da55ff", "#1bc47c", "#ea657e", "#fd8637", "#22cec6", "#8c8de3", "#71bf22"]
-	let hash = 0
-	let i
-	let chr
-	if (str.length === 0) {
-		return hash
-	}
-	for (i = 0; i < str.length; i++) {
-		chr = str.charCodeAt(i)
-		hash = ((hash << 5) - hash) + chr
-		hash |= 0
-	}
-	hash = Math.abs(hash) % 8
-	return colors[hash]
-}
-
-class Avatar extends ElemJS {
-	constructor() {
-		super("div")
-		this.class("c-message-group__avatar")
-
-		this.mxc = undefined
-		this.image = null
-
-		this.update(null)
-	}
-
-	update(mxc) {
-		if (mxc === this.mxc) return
-		this.mxc = mxc
-		this.hasImage = !!mxc
-		if (this.hasImage) {
-			const size = 96
-			const url = resolveMxc(mxc, size, "crop")
-			this.image = ejs("img").class("c-message-group__icon").attribute("src", url).attribute("width", size).attribute("height", size)
-			this.image.on("error", this.onError.bind(this))
-		}
-		this.render()
-	}
-
-	onError() {
-		this.hasImage = false
-		this.render()
-	}
-
-	render() {
-		this.clearChildren()
-		if (this.hasImage) {
-			this.child(this.image)
-		} else {
-			this.child(
-				ejs("div").class("c-message-group__icon", "c-message-group__icon--no-icon")
-			)
-		}
-	}
-}
-
-/** Must update at least once to render. */
-class Name extends ElemJS {
-	constructor() {
-		super("div")
-		this.class("c-message-group__name")
-
-		/**
-		 * Keeps track of whether we have the proper display name or not.
-		 * If we do, then we shoudn't override it with the mxid if the name becomes unavailable.
-		 */
-		this.hasName = false
-		this.name = ""
-		this.mxid = ""
-	}
-
-	update(event) {
-		this.mxid = event.state_key
-		if (event.content.displayname) {
-			this.hasName = true
-			this.name = event.content.displayname
-		} else if (!this.hasName) {
-			this.name = this.mxid
-		}
-		this.render()
-	}
-
-	render() {
-		// set text
-		this.text(this.name)
-		// set color
-		this.style("color", nameToColor(this.mxid))
-	}
-}
-
-class Sender {
-	constructor(roomID, mxid) {
-		this.sender = store.rooms.get(roomID).value().members.get(mxid)
-		this.name = new Name()
-		this.avatar = new Avatar()
-		this.sender.subscribe("changeSelf", this.update.bind(this))
-		this.update()
-	}
-
-	update() {
-		if (this.sender.exists()) {
-			// name
-			this.name.update(this.sender.value())
-
-			// avatar
-			this.avatar.update(this.sender.value().content.avatar_url)
-		}
-	}
-}
-
-module.exports = {
-	Sender
-}
diff --git a/src/js/store/subscribable.js b/src/js/store/Subscribable.js
similarity index 86%
rename from src/js/store/subscribable.js
rename to src/js/store/Subscribable.js
index 56bf971..6c7640e 100644
--- a/src/js/store/subscribable.js
+++ b/src/js/store/Subscribable.js
@@ -20,8 +20,6 @@ class Subscribable {
 		} else {
 			throw new Error(`Cannot subscribe to non-existent event ${event}, available events are: ${Object.keys(this.events).join(", ")}`)
 		}
-		// return a function we can call to easily unsubscribe
-		return () => this.unsubscribe(event, callback)
 	}
 
 	unsubscribe(event, callback) {
@@ -37,4 +35,4 @@ class Subscribable {
 	}
 }
 
-module.exports = {Subscribable}
+export {Subscribable}
diff --git a/src/js/store/SubscribeMap.js b/src/js/store/SubscribeMap.js
new file mode 100644
index 0000000..8b0dc0c
--- /dev/null
+++ b/src/js/store/SubscribeMap.js
@@ -0,0 +1,41 @@
+import {Subscribable} from $to_relative "/js/store/Subscribable.js"
+import {SubscribeValue} from $to_relative "/js/store/SubscribeValue.js"
+
+class SubscribeMap extends Subscribable {
+	constructor() {
+		super()
+		Object.assign(this.events, {
+			addItem: [],
+			changeItem: [],
+			removeItem: []
+		})
+		this.map = new Map()
+	}
+
+	has(key) {
+		return this.map.has(key) && this.map.get(key).exists()
+	}
+
+	get(key) {
+		if (this.map.has(key)) {
+			return this.map.get(key)
+		} else {
+			this.map.set(key, new SubscribeValue())
+		}
+	}
+
+	set(key, value) {
+		let s
+		if (this.map.has(key)) {
+			s = this.map.get(key).set(value)
+			this.broadcast("changeItem", key)
+		} else {
+			s = new SubscribeValue().set(value)
+			this.map.set(key, s)
+			this.broadcast("addItem", key)
+		}
+		return s
+	}
+}
+
+export {SubscribeMap}
diff --git a/src/js/store/subscribe_map_list.js b/src/js/store/SubscribeMapList.js
similarity index 72%
rename from src/js/store/subscribe_map_list.js
rename to src/js/store/SubscribeMapList.js
index 794a8da..1883303 100644
--- a/src/js/store/subscribe_map_list.js
+++ b/src/js/store/SubscribeMapList.js
@@ -1,5 +1,5 @@
-const {Subscribable} = require("./subscribable.js")
-const {SubscribeValue} = require("./subscribe_value.js")
+import {Subscribable} from $to_relative "/js/store/Subscribable.js"
+import {SubscribeValue} from $to_relative "/js/store/SubscribeValue.js"
 
 class SubscribeMapList extends Subscribable {
 	constructor(inner) {
@@ -54,15 +54,6 @@ class SubscribeMapList extends Subscribable {
 	}
 
 	sort() {
-		const key = this.list[0]
-		if (typeof this.map.get(key).value().order === "number") {
-			this.sortByNumber()
-		} else {
-			this.sortByString()
-		}
-	}
-
-	sortByNumber() {
 		this.list.sort((a, b) => {
 			const orderA = this.map.get(a).value().order
 			const orderB = this.map.get(b).value().order
@@ -71,17 +62,6 @@ class SubscribeMapList extends Subscribable {
 		this.broadcast("changeItem")
 	}
 
-	sortByString() {
-		this.list.sort((a, b) => {
-			const orderA = this.map.get(a).value().order
-			const orderB = this.map.get(b).value().order
-			if (orderA < orderB) return -1
-			else if (orderA > orderB) return 1
-			else return 0
-		})
-		this.broadcast("changeItem")
-	}
-
 	_add(key, value, start) {
 		let s
 		if (this.map.has(key)) {
@@ -103,4 +83,4 @@ class SubscribeMapList extends Subscribable {
 	}
 }
 
-module.exports = {SubscribeMapList}
+export {SubscribeMapList}
diff --git a/src/js/store/subscribe_set.js b/src/js/store/SubscribeSet.js
similarity index 88%
rename from src/js/store/subscribe_set.js
rename to src/js/store/SubscribeSet.js
index 32c758c..789aaaf 100644
--- a/src/js/store/subscribe_set.js
+++ b/src/js/store/SubscribeSet.js
@@ -1,4 +1,4 @@
-const {Subscribable} = require("./subscribable.js")
+import {Subscribable} from $to_relative "/js/store/Subscribable.js"
 
 class SubscribeSet extends Subscribable {
 	constructor() {
@@ -47,4 +47,4 @@ class SubscribeSet extends Subscribable {
 	}
 }
 
-module.exports = {SubscribeSet}
+export {SubscribeSet}
diff --git a/src/js/store/subscribe_value.js b/src/js/store/SubscribeValue.js
similarity index 85%
rename from src/js/store/subscribe_value.js
rename to src/js/store/SubscribeValue.js
index 9c71959..6657e27 100644
--- a/src/js/store/subscribe_value.js
+++ b/src/js/store/SubscribeValue.js
@@ -1,4 +1,4 @@
-const {Subscribable} = require("./subscribable.js")
+import {Subscribable} from $to_relative "/js/store/Subscribable.js"
 
 class SubscribeValue extends Subscribable {
 	constructor() {
@@ -30,7 +30,7 @@ class SubscribeValue extends Subscribable {
 
 	edit(f) {
 		if (this.exists()) {
-			this.data = f(this.data)
+			f(this.data)
 			this.set(this.data)
 		} else {
 			throw new Error("Tried to edit a SubscribeValue that had no value")
@@ -44,4 +44,4 @@ class SubscribeValue extends Subscribable {
 	}
 }
 
-module.exports = {SubscribeValue}
+export {SubscribeValue}
diff --git a/src/js/store/store.js b/src/js/store/store.js
index 8ef4511..1c0552d 100644
--- a/src/js/store/store.js
+++ b/src/js/store/store.js
@@ -1,7 +1,7 @@
-const {Subscribable} = require("./subscribable.js")
-const {SubscribeMapList} = require("./subscribe_map_list.js")
-const {SubscribeSet} = require("./subscribe_set.js")
-const {SubscribeValue} = require("./subscribe_value.js")
+import {Subscribable} from $to_relative "/js/store/Subscribable.js"
+import {SubscribeMapList} from $to_relative "/js/store/SubscribeMapList.js"
+import {SubscribeSet} from $to_relative "/js/store/SubscribeSet.js"
+import {SubscribeValue} from $to_relative "/js/store/SubscribeValue.js"
 
 const store = {
 	groups: new SubscribeMapList(SubscribeValue),
@@ -9,10 +9,9 @@ const store = {
 	directs: new SubscribeSet(),
 	activeGroup: new SubscribeValue(),
 	activeRoom: new SubscribeValue(),
-	newEvents: new Subscribable(),
-	notificationsChange: new Subscribable()
+	newEvents: new Subscribable()
 }
 
 window.store = store
 
-module.exports = {store}
+export {store}
diff --git a/src/js/store/subscribe_map.js b/src/js/store/subscribe_map.js
deleted file mode 100644
index 6159597..0000000
--- a/src/js/store/subscribe_map.js
+++ /dev/null
@@ -1,74 +0,0 @@
-const {Subscribable} = require("./subscribable.js")
-
-class SubscribeMap extends Subscribable {
-	constructor(inner) {
-		super()
-		this.inner = inner
-		Object.assign(this.events, {
-			addItem: [],
-			editItem: [],
-			deleteItem: [],
-			changeItem: [],
-			askSet: []
-		})
-		Object.assign(this.eventDeps, {
-			addItem: ["changeItem"],
-			editItem: ["changeItem"],
-			deleteItem: ["changeItem"],
-			changeItem: [],
-			askSet: []
-		})
-		this.map = new Map()
-	}
-
-	has(key) {
-		return this.map.has(key) && this.map.get(key).exists()
-	}
-
-	get(key) {
-		if (this.map.has(key)) {
-			return this.map.get(key)
-		} else {
-			const item = new this.inner()
-			this.map.set(key, item)
-			return item
-		}
-	}
-
-	forEach(f) {
-		for (const entry of this.map.entries()) {
-			f(entry[0], entry[1])
-		}
-	}
-
-	askSet(key, value) {
-		this.broadcast("askSet", {key, value})
-	}
-
-	set(key, value) {
-		let s
-		if (this.map.has(key)) {
-			const exists = this.map.get(key).exists()
-			s = this.map.get(key).set(value)
-			if (exists) {
-				this.broadcast("editItem", key)
-			} else {
-				this.broadcast("addItem", key)
-			}
-		} else {
-			s = new this.inner().set(value)
-			this.map.set(key, s)
-			this.broadcast("addItem", key)
-		}
-		return s
-	}
-
-	delete(key) {
-		if (this.backing.has(key)) {
-			this.backing.delete(key)
-			this.broadcast("deleteItem", key)
-		}
-	}
-}
-
-module.exports = {SubscribeMap}
diff --git a/src/js/sync/sync.js b/src/js/sync/sync.js
index f8bfc52..bbd6b11 100644
--- a/src/js/sync/sync.js
+++ b/src/js/sync/sync.js
@@ -1,6 +1,6 @@
-const {store} = require("../store/store.js")
-const lsm = require("../lsm.js")
-const {resolveMxc} = require("../functions.js")
+import {store} from $to_relative "/js/store/store.js"
+import * as lsm from $to_relative "/js/lsm.js"
+import {resolveMxc} from $to_relative "/js/functions.js"
 
 let lastBatch = null
 
@@ -11,7 +11,7 @@ function sync() {
 		room: {
 			// pulling more from the timeline massively increases download size
 			timeline: {
-				limit: 1
+				limit: 5
 			},
 			// members are not currently needed
 			state: {
@@ -37,88 +37,63 @@ function sync() {
 function manageSync(root) {
 	try {
 		let newEvents = false
-		let notificationsChange = false
 
 		// set up directs
-		if (root.account_data) {
-			const directs = root.account_data.events.find(e => e.type === "m.direct")
-			if (directs) {
-				Object.values(directs.content).forEach(ids => {
-					ids.forEach(id => store.directs.add(id))
-				})
-			}
-		}
-
-		// set up rooms
-		if (root.rooms) {
-			if (root.rooms.join) {
-				Object.entries(root.rooms.join).forEach(([id, data]) => {
-					if (!store.rooms.has(id)) {
-						store.rooms.askAdd(id, data)
-					}
-					const room = store.rooms.get(id).value()
-					const timeline = room.timeline
-					if (data.state && data.state.events) timeline.updateStateEvents(data.state.events)
-					if (data.timeline && data.timeline.events) {
-						if (!timeline.from) timeline.from = data.timeline.prev_batch
-						if (data.timeline.events.length) {
-							newEvents = true
-							timeline.updateEvents(data.timeline.events)
-						}
-					}
-					if (data.ephemeral && data.ephemeral.events) timeline.updateEphemeral(data.ephemeral.events)
-					if (data.unread_notifications) {
-						timeline.updateNotificationCount(data.unread_notifications.notification_count)
-						notificationsChange = true
-					}
-					if (data["org.matrix.msc2654.unread_count"] != undefined) {
-						timeline.updateUnreadCount(data["org.matrix.msc2654.unread_count"])
-						notificationsChange = true
-					}
-				})
-			}
-		}
-
-		// set up groups
-		if (root.groups) {
-			Promise.all(
-				Object.keys(root.groups.join).map(id => {
-					if (!store.groups.has(id)) {
-						return Promise.all(["profile", "rooms"].map(path => {
-							const url = new URL(`${lsm.get("domain")}/_matrix/client/r0/groups/${id}/${path}`)
-							url.searchParams.append("access_token", lsm.get("access_token"))
-							return fetch(url.toString()).then(res => res.json())
-						})).then(([profile, rooms]) => {
-							rooms = rooms.chunk
-							let order = 999
-							let orderEvent = root.account_data.events.find(e => e.type === "im.vector.web.tag_ordering")
-							if (orderEvent) {
-								if (orderEvent.content.tags.includes(id)) {
-									order = orderEvent.content.tags.indexOf(id)
-								}
-							}
-							const data = {
-								name: profile.name,
-								icon: resolveMxc(profile.avatar_url, 96, "crop"),
-								order
-							}
-							store.groups.askAdd(id, data)
-							rooms.forEach(groupRoom => {
-								if (store.rooms.has(groupRoom.room_id)) {
-									store.rooms.get(groupRoom.room_id).value().setGroup(id)
-								}
-							})
-							store.newEvents.broadcast("changeSelf") // trigger a room list update
-						})
-					}
-				})
-			).then(() => {
-				store.rooms.sort()
+		const directs = root.account_data.events.find(e => e.type === "m.direct")
+		if (directs) {
+			Object.values(directs.content).forEach(ids => {
+				ids.forEach(id => store.directs.add(id))
 			})
 		}
 
+		// set up rooms
+		Object.entries(root.rooms.join).forEach(([id, data]) => {
+			if (!store.rooms.has(id)) {
+				store.rooms.askAdd(id, data)
+			}
+			const room = store.rooms.get(id).value()
+			const timeline = room.timeline
+			if (data.timeline.events.length) newEvents = true
+			timeline.updateStateEvents(data.state.events)
+			timeline.updateEvents(data.timeline.events)
+		})
+
+		// set up groups
+		Promise.all(
+			Object.keys(root.groups.join).map(id => {
+				if (!store.groups.has(id)) {
+					return Promise.all(["profile", "rooms"].map(path => {
+						const url = new URL(`${lsm.get("domain")}/_matrix/client/r0/groups/${id}/${path}`)
+						url.searchParams.append("access_token", lsm.get("access_token"))
+						return fetch(url.toString()).then(res => res.json())
+					})).then(([profile, rooms]) => {
+						rooms = rooms.chunk
+						let order = 999
+						let orderEvent = root.account_data.events.find(e => e.type === "im.vector.web.tag_ordering")
+						if (orderEvent) {
+							if (orderEvent.content.tags.includes(id)) {
+								order = orderEvent.content.tags.indexOf(id)
+							}
+						}
+						const data = {
+							name: profile.name,
+							icon: resolveMxc(profile.avatar_url, 96, "crop"),
+							order
+						}
+						store.groups.askAdd(id, data)
+						rooms.forEach(groupRoom => {
+							if (store.rooms.has(groupRoom.room_id)) {
+								store.rooms.get(groupRoom.room_id).value().setGroup(id)
+							}
+						})
+						store.newEvents.broadcast("changeSelf") // trigger a room list update
+					})
+				}
+			})
+		).then(() => {
+			store.rooms.sort()
+		})
 		if (newEvents) store.newEvents.broadcast("changeSelf")
-		if (notificationsChange) store.notificationsChange.broadcast("changeSelf")
 	} catch (e) {
 		console.error(root)
 		throw e
@@ -146,6 +121,4 @@ function syncLoop() {
 
 store.activeGroup.set(store.groups.get("directs").value())
 
-if (lsm.get("access_token")) {
-	syncLoop()
-}
+syncLoop()
diff --git a/src/js/timeline.js b/src/js/timeline.js
deleted file mode 100644
index 0a36d14..0000000
--- a/src/js/timeline.js
+++ /dev/null
@@ -1,408 +0,0 @@
-const {ElemJS, ejs, q} = require("./basic.js")
-const {Subscribable} = require("./store/subscribable.js")
-const {SubscribeValue} = require("./store/subscribe_value.js")
-const {SubscribeMap} = require("./store/subscribe_map.js")
-const {store} = require("./store/store.js")
-const {Anchor} = require("./anchor.js")
-const {Sender} = require("./sender.js")
-const {ReadMarker, markFullyRead} = require("./read-marker.js")
-const lsm = require("./lsm.js")
-const {resolveMxc} = require("./functions.js")
-const {renderEvent} = require("./events/render-event")
-const {dateFormatter} = require("./date-formatter")
-
-let debug = false
-
-const NO_MAX = Symbol("NO_MAX")
-
-let sentIndex = 0
-
-function getTxnId() {
-	return Date.now() + (sentIndex++)
-}
-
-function eventSearch(list, event, min = 0, max = NO_MAX) {
-	if (list.length === 0) return {success: false, i: 0}
-
-	if (max === NO_MAX) max = list.length - 1
-	let mid = Math.floor((max + min) / 2)
-	// success condition
-	if (list[mid] && list[mid].data.event_id === event.data.event_id) return {success: true, i: mid}
-	// failed condition
-	if (min >= max) {
-		while (mid !== -1 && (!list[mid] || list[mid].data.origin_server_ts > event.data.origin_server_ts)) mid--
-		return {
-			success: false,
-			i: mid + 1
-		}
-	}
-	// recurse (below)
-	if (list[mid].data.origin_server_ts > event.data.origin_server_ts) return eventSearch(list, event, min, mid - 1)
-	// recurse (above)
-	else return eventSearch(list, event, mid + 1, max)
-}
-
-class EventGroup extends ElemJS {
-	constructor(reactive, list) {
-		super("div")
-		this.class("c-message-group")
-		this.reactive = reactive
-		this.list = list
-		this.data = {
-			sender: list[0].data.sender,
-			origin_server_ts: list[0].data.origin_server_ts
-		}
-		this.sender = new Sender(this.reactive.id, this.data.sender)
-		this.child(
-			this.sender.avatar,
-			this.messages = ejs("div").class("c-message-group__messages").child(
-				ejs("div").class("c-message-group__intro").child(
-					this.sender.name,
-					ejs("div").class("c-message-group__date").text(dateFormatter.format(this.data.origin_server_ts))
-				),
-				...this.list
-			)
-		)
-	}
-
-	canGroup() {
-		if (this.list.length) return this.list[0].canGroup()
-		else return true
-	}
-
-	addEvent(event) {
-		const index = eventSearch(this.list, event).i
-		event.setGroup(this)
-		this.list.splice(index, 0, event)
-		this.messages.childAt(index + 1, event)
-	}
-
-	removeEvent(event) {
-		const search = eventSearch(this.list, event)
-		if (!search.success) throw new Error(`Event ${event.data.event_id} not found in this group`)
-		const index = search.i
-		// actually remove the event
-		this.list.splice(index, 1)
-		event.remove() // should get everything else
-		if (this.list.length === 0) this.reactive.removeGroup(this)
-	}
-}
-
-/** Displays a spinner and creates an event to notify timeline to load more messages */
-class LoadMore extends ElemJS {
-	constructor(id) {
-		super("div")
-		this.class("c-message-notice")
-		this.id = id
-
-		this.child(
-			ejs("div").class("c-message-notice__inner").child(
-				ejs("span").class("loading-icon"),
-				ejs("span").text("Loading more...")
-			)
-		)
-		const intersection_observer = new IntersectionObserver(e => this.intersectionHandler(e))
-		intersection_observer.observe(this.element)
-	}
-
-	intersectionHandler(e) {
-		if (e.some(e => e.isIntersecting)) {
-			store.rooms.get(this.id).value().timeline.loadScrollback()
-		}
-	}
-}
-
-class ReactiveTimeline extends ElemJS {
-	constructor(id, list) {
-		super("div")
-		this.class("c-event-groups")
-		this.id = id
-		this.list = list
-		this.loadMore = new LoadMore(this.id)
-		this.render()
-	}
-
-	addEvent(event) {
-		this.loadMore.remove()
-		// if (debug) console.log("running search", this.list, event)
-		// if (debug) debugger;
-		const search = eventSearch(this.list, event)
-		// console.log(search, this.list.map(l => l.data.sender), event.data)
-		if (!search.success) {
-			if (search.i >= 1) {
-				// add at end
-				this.tryAddGroups(event, [search.i - 1, search.i])
-			} else {
-				// add at start
-				this.tryAddGroups(event, [0, -1])
-			}
-		} else {
-			this.tryAddGroups(event, [search.i])
-		}
-		this.loadMore = new LoadMore(this.id)
-		this.childAt(0, this.loadMore)
-	}
-
-	tryAddGroups(event, indices) {
-		const createGroupAt = i => {
-			// if (printed++ < 100) console.log("tryadd success, created group")
-			if (i === -1) {
-				// here, -1 means at the start, before the first group
-				i = 0 // jank but it does the trick
-			}
-			if (event.canGroup()) {
-				const group = new EventGroup(this, [event])
-				this.list.splice(i, 0, group)
-				this.childAt(i, group)
-				event.setGroup(group)
-			} else {
-				this.list.splice(i, 0, event)
-				this.childAt(i, event)
-			}
-		}
-		const success = indices.some(i => {
-			if (!this.list[i]) {
-				createGroupAt(i)
-				return true
-			} else if (event.canGroup() && this.list[i] && this.list[i].canGroup() && this.list[i].data.sender === event.data.sender) {
-				// if (printed++ < 100) console.log("tryadd success, using existing group")
-				this.list[i].addEvent(event)
-				return true
-			}
-		})
-		// if (!success) console.log("tryadd failure", indices, this.list.map(l => l.data.sender), event.data) // I believe all the bugs are now fixed. Lol.
-		if (!success) createGroupAt(indices[0])
-	}
-
-	removeGroup(group) {
-		const index = this.list.indexOf(group)
-		this.list.splice(index, 1)
-		group.remove() // should get everything else
-	}
-
-	render() {
-		this.clearChildren()
-		this.child(this.loadMore)
-		this.list.forEach(group => this.child(group))
-		this.anchor = new Anchor()
-		this.child(this.anchor)
-	}
-}
-
-class Timeline extends Subscribable {
-	constructor(room) {
-		super()
-		Object.assign(this.events, {
-			beforeChange: [],
-			afterChange: [],
-			beforeScrollbackLoad: [],
-			afterScrollbackLoad: [],
-		})
-		Object.assign(this.eventDeps, {
-			beforeChange: [],
-			afterChange: [],
-			beforeScrollbackLoad: [],
-			afterScrollbackLoad: [],
-		})
-		this.room = room
-		this.id = this.room.id
-		this.list = []
-		this.map = new Map()
-		this.reactiveTimeline = new ReactiveTimeline(this.id, [])
-		this.latest = 0
-		this.latestEventID = null
-		this.pending = new Set()
-		this.pendingEdits = []
-		this.typing = new SubscribeValue().set([])
-		this.userReads = new SubscribeMap(SubscribeValue)
-		this.readMarker = new ReadMarker(this)
-		this.from = null
-	}
-
-	updateStateEvents(events) {
-		for (const eventData of events) {
-			let id = eventData.event_id
-			if (eventData.type === "m.room.member") {
-				// update members
-				if (eventData.membership !== "leave") {
-					const member = this.room.members.get(eventData.state_key)
-					// only use the latest state
-					if (!member.exists() || eventData.origin_server_ts > member.data.origin_server_ts) {
-						member.set(eventData)
-					}
-				}
-			}
-		}
-	}
-
-	updateEvents(events) {
-		this.broadcast("beforeChange")
-		// handle state events
-		this.updateStateEvents(events)
-		for (const eventData of events) {
-			// set variables
-			let id = eventData.event_id
-			if (eventData.origin_server_ts > this.latest) {
-				this.latest = eventData.origin_server_ts
-				this.latestEventID = id
-			}
-			// handle local echoes
-			if (eventData.sender === lsm.get("mx_user_id") && eventData.content && this.pending.has(eventData.content["chat.carbon.message.pending_id"])) {
-				const pendingID = eventData.content["chat.carbon.message.pending_id"]
-				if (id !== pendingID) {
-					const target = this.map.get(pendingID)
-					this.map.set(id, target)
-					this.map.delete(pendingID)
-					// update fully read marker - assume we have fully read up to messages we send
-					markFullyRead(this.id, id)
-				}
-			}
-			// handle timeline events
-			if (this.map.has(id)) {
-				// update existing event
-				this.map.get(id).update(eventData)
-			} else {
-				// skip redacted events
-				if (eventData.unsigned && eventData.unsigned.redacted_by) {
-					continue
-				}
-				// handle redactions
-				if (eventData.type === "m.room.redaction") {
-					if (this.map.has(eventData.redacts)) this.map.get(eventData.redacts).removeEvent()
-					continue
-				}
-				// handle edits
-				if (eventData.type === "m.room.message" && eventData.content["m.relates_to"] && eventData.content["m.relates_to"].rel_type === "m.replace") {
-					this.pendingEdits.push(eventData)
-					continue
-				}
-				// add new event
-				const event = renderEvent(eventData)
-				this.map.set(id, event)
-				this.reactiveTimeline.addEvent(event)
-				// update read receipt for sender on their own event
-				this.moveReadReceipt(eventData.sender, id)
-			}
-		}
-		// apply edits
-		this.pendingEdits = this.pendingEdits.filter(eventData => {
-			const replaces = eventData.content["m.relates_to"].event_id
-			if (this.map.has(replaces)) {
-				const event = this.map.get(replaces)
-				event.data.content = eventData.content["m.new_content"]
-				event.setEdited(eventData.origin_server_ts)
-				event.update(event.data)
-				return false // handled; remove from list
-			} else {
-				return true // we don't have the event it edits yet; keep in list
-			}
-		})
-		this.broadcast("afterChange")
-	}
-
-	updateEphemeral(events) {
-		for (const eventData of events) {
-			if (eventData.type === "m.typing") {
-				this.typing.set(eventData.content.user_ids)
-			}
-			if (eventData.type === "m.receipt") {
-				for (const eventID of Object.keys(eventData.content)) {
-					for (const user of Object.keys(eventData.content[eventID]["m.read"])) {
-						this.moveReadReceipt(user, eventID)
-					}
-				}
-				// console.log("Updated read receipts:", this.userReads)
-			}
-		}
-	}
-
-	moveReadReceipt(user, eventID) {
-		// check for a previous event to move from
-		const prev = this.userReads.get(user)
-		if (prev.exists()) {
-			const prevID = prev.value()
-			if (this.map.has(prevID) && this.map.has(eventID)) {
-				// ensure new message came later
-				if (this.map.get(eventID).data.origin_server_ts < this.map.get(prevID).data.origin_server_ts) return
-				this.map.get(prevID).readBy.delete(user)
-			}
-		}
-		// set on new message
-		this.userReads.set(user, eventID)
-		if (this.map.has(eventID)) this.map.get(eventID).readBy.add(user)
-	}
-
-	updateUnreadCount(count) {
-		this.room.number.update({unreads: count})
-	}
-
-	updateNotificationCount(count) {
-		this.room.number.update({notifications: count})
-	}
-
-	removeEvent(id) {
-		if (!this.map.has(id)) throw new Error(`Tried to delete event ID ${id} which does not exist`)
-		this.map.get(id).removeEvent()
-		this.map.delete(id)
-	}
-
-	getTimeline() {
-		return this.reactiveTimeline
-	}
-
-	async loadScrollback() {
-		debug = true
-		if (!this.from) return // no more scrollback for this timeline
-		const url = new URL(`${lsm.get("domain")}/_matrix/client/r0/rooms/${this.id}/messages`)
-		url.searchParams.set("access_token", lsm.get("access_token"))
-		url.searchParams.set("from", this.from)
-		url.searchParams.set("dir", "b")
-		url.searchParams.set("limit", "20")
-		const filter = {
-			lazy_load_members: true
-		}
-		url.searchParams.set("filter", JSON.stringify(filter))
-
-		const root = await fetch(url.toString()).then(res => res.json())
-
-		this.broadcast("beforeScrollbackLoad")
-
-		this.from = root.end
-		// console.log(this.updateEvents, root.chunk)
-		if (root.state) this.updateStateEvents(root.state)
-		if (root.chunk.length) {
-			// there are events to display
-			this.updateEvents(root.chunk)
-		}
-		if (!root.chunk.length || !root.end) {
-			// we reached the top of the scrollback
-			this.reactiveTimeline.loadMore.remove()
-		}
-		this.broadcast("afterScrollbackLoad")
-	}
-
-	send(type, content) {
-		const tx = getTxnId()
-		const id = `pending$${tx}`
-		this.pending.add(id)
-		content["chat.carbon.message.pending_id"] = id
-		const fakeEvent = {
-			type,
-			origin_server_ts: Date.now(),
-			event_id: id,
-			sender: lsm.get("mx_user_id"),
-			content,
-			pending: true
-		}
-		this.updateEvents([fakeEvent])
-		return fetch(`${lsm.get("domain")}/_matrix/client/r0/rooms/${this.id}/send/m.room.message/${tx}?access_token=${lsm.get("access_token")}`, {
-			method: "PUT",
-			body: JSON.stringify(content),
-			headers: {
-				"Content-Type": "application/json"
-			}
-		})
-	}
-}
-
-module.exports = {Timeline}
diff --git a/src/js/typing.js b/src/js/typing.js
deleted file mode 100644
index b6208ef..0000000
--- a/src/js/typing.js
+++ /dev/null
@@ -1,69 +0,0 @@
-const {ElemJS, ejs, q} = require("./basic")
-const {store} = require("./store/store")
-const lsm = require("./lsm")
-
-/**
- * Maximum number of typing users to display all names for.
- * More will be shown as "X users are typing".
- */
-const maxUsers = 4
-
-function getMemberName(mxid) {
-	return store.activeRoom.value().getMemberName(mxid)
-}
-
-class Typing extends ElemJS {
-	constructor() {
-		super(q("#c-typing"))
-
-		this.typingUnsubscribe = null
-
-		this.message = ejs("span")
-		this.child(this.message)
-
-		store.activeRoom.subscribe("changeSelf", this.changeRoom.bind(this))
-	}
-
-	changeRoom() {
-		if (this.typingUnsubscribe) {
-			this.typingUnsubscribe()
-			this.typingUnsubscribe = null
-		}
-		if (!store.activeRoom.exists()) return
-		const room = store.activeRoom.value()
-		this.typingUnsubscribe = room.timeline.typing.subscribe("changeSelf", this.render.bind(this))
-		this.render()
-	}
-
-	render() {
-		if (!store.activeRoom.exists()) return
-		const room = store.activeRoom.value()
-		let users = [...room.timeline.typing.value()]
-		// don't show own typing status
-		users = users.filter(u => u !== lsm.get("mx_user_id"))
-		if (users.length === 0) {
-			// nobody is typing
-			this.removeClass("c-typing--typing")
-		} else {
-			let message = ""
-			if (users.length === 1) {
-				message = `${getMemberName(users[0])} is typing...`
-			} else if (users.length <= maxUsers) {
-				// feel free to rewrite this loop if you know a better way
-				for (let i = 0; i < users.length; i++) {
-					if (i < users.length-1) {
-						message += `${getMemberName(users[i])}, `
-					} else {
-						message += `and ${getMemberName(users[i])} are typing...`
-					}
-				}
-			} else {
-				message = `${users.length} people are typing...`
-			}
-			this.class("c-typing--typing")
-			this.message.text(message)
-		}
-	}
-}
-
-new Typing()
diff --git a/src/login.pug b/src/login.pug
index 470ee82..105b6bd 100644
--- a/src/login.pug
+++ b/src/login.pug
@@ -1,32 +1,21 @@
 doctype html
 html
-  head
-    meta(charset="utf-8")
-    title Carbon
-    meta(name="viewport" content="width=device-width, initial-scale=1")
-    link(rel="stylesheet" type="text/css" href=getStatic("/sass/login.sass"))
-    script(type="module" src=getStatic("/js/login.js"))
-
-  body
-    main.main
-      .center-login-container
-        h1 Welcome to Carbon!
-        form.login-form(method="post" onsubmit="return false")#form
-          .data-input
-            .form-input-container
-              label(for="username") Username
-              input(type="text" name="username" autocomplete="username" placeholder="@username:server.tld" pattern="^@?[a-z0-9._=/-]+(?::[a-zA-Z0-9.:\\[\\]-]+)?$" required)#username
-
-            .form-input-container
-              label(for="password") Password
-              input(name="password" autocomplete="current-password" type="password" required)#password
-
-            .form-input-container
-              label(for="homeserver") Homeserver
-              input(type="text" name="homeserver" value="matrix.org" placeholder="matrix.org" required)#homeserver
-
-          #feedback
-
-          .form-input-container
-            input(type="submit" value="Log in")#submit
+	head
+		meta(charset="utf-8")
+		link(rel="stylesheet" type="text/css" href=getStatic("/sass/main.sass"))
+		title Carbon
+	body
+		main.main
+			form
+				div
+					label(for="login") Username
+					input(type="text" name="login" autocomplete="username" placeholder="example:matrix.org" required)#login
+				div
+					label(for="password") Password
+					input(type="text" name="password" autocomplete="current-password" required)#password
+				div
 
+					label(for="homeserver") Homeserver
+					input(type="text" name="homeserver" value="matrix.org" required)#homeserver
+				div
+					input(type="submit" value="Login")
diff --git a/src/sass/base.sass b/src/sass/base.sass
index dfb9f7a..0232c2e 100644
--- a/src/sass/base.sass
+++ b/src/sass/base.sass
@@ -21,39 +21,3 @@ body
 .main
   height: 100vh
   display: flex
-
-button
-  appearance: none
-  border: none
-  background: none
-  color: inherit
-  font-family: inherit
-  font-size: inherit
-  font-style: inherit
-  font-weight: inherit
-  padding: 0
-  margin: 0
-  line-height: inherit
-  cursor: inherit
-
-// focus resets
-
-:focus
-  outline: none
-
-:-moz-focusring
-  outline: none
-
-::-moz-focus-inner
-  border: 0
-
-select:-moz-focusring
-  color: transparent
-  text-shadow: 0 0 0 #ddd
-
-body.show-focus
-  a, select, button, input, video, div, span
-    outline-color: #fff
-
-    &:focus
-      outline: 2px dotted
diff --git a/src/sass/colors.sass b/src/sass/colors.sass
index a603edd..278fc02 100644
--- a/src/sass/colors.sass
+++ b/src/sass/colors.sass
@@ -5,5 +5,3 @@ $mild: #393c42
 $milder: #42454a
 $divider: #4b4e54
 $muted: #999
-$link: #57bffd
-$notify-highlight: #ffac4b
diff --git a/src/sass/components/chat-banner.sass b/src/sass/components/chat-banner.sass
deleted file mode 100644
index f17acce..0000000
--- a/src/sass/components/chat-banner.sass
+++ /dev/null
@@ -1,50 +0,0 @@
-@use "../colors" as c
-
-.c-chat-banner
-  position: sticky
-  z-index: 1
-  top: 0
-  left: 0
-  right: 0
-  margin-right: 12px
-  outline-color: #000
-  opacity: 0
-  transform: translateY(-40px)
-  transition: transform 0.2s ease, opacity 0.2s ease-out
-
-  &--active
-    opacity: 1
-    transform: translateY(0px)
-
-  &__inner
-    display: grid
-    grid-template-columns: 1fr auto
-    background: c.$notify-highlight
-    color: #000
-    margin: 0px 12px
-    padding: 0px 12px
-    border-radius: 0px 0px 10px 10px
-    line-height: 1
-    box-shadow: 0px 5px 5px -2px rgba(0, 0, 0, 0.1)
-    cursor: pointer
-
-    &:hover
-      box-shadow: 0px 5px 5px -2px rgba(0, 0, 0, 0.6)
-
-  &__part
-    padding: 6px 0px 8px
-
-    &:hover
-      text-decoration: underline
-
-  &__part-inner
-    display: block
-    width: 100% // yes, really.
-    text-align: left
-
-  &__last
-    margin-left: 8px
-
-  &__last &__part-inner
-    border-left: 1px solid #222
-    padding-left: 8px
diff --git a/src/sass/components/chat-input.sass b/src/sass/components/chat-input.sass
index bb82dde..892fee6 100644
--- a/src/sass/components/chat-input.sass
+++ b/src/sass/components/chat-input.sass
@@ -6,14 +6,11 @@
   -webkit-appearance: $value
 
 .c-chat-input
-  position: relative
   width: 100%
   border-top: 2px solid c.$divider
   background-color: c.$dark
 
   &__textarea
-    position: relative
-    z-index: 1
     width: calc(100% - 40px)
     height: 16px + (16px * 1.45)
     box-sizing: border-box
diff --git a/src/sass/components/chat.sass b/src/sass/components/chat.sass
index c8bb391..5ca48e0 100644
--- a/src/sass/components/chat.sass
+++ b/src/sass/components/chat.sass
@@ -2,12 +2,11 @@
 
 .c-chat
   display: grid
-  grid-template-rows: 0 1fr 82px // fixed so that input box height adjustment doesn't mess up scroll
+  grid-template-rows: 1fr 82px // fixed so that input box height adjustment doesn't mess up scroll
   align-items: end
   flex: 1
 
   &__messages
-    position: relative
     height: 100%
     overflow-y: scroll
     scrollbar-color: c.$darkest c.$darker
diff --git a/src/sass/components/groups.sass b/src/sass/components/groups.sass
index 6eca6ec..e91f4cc 100644
--- a/src/sass/components/groups.sass
+++ b/src/sass/components/groups.sass
@@ -36,13 +36,11 @@ $out-width: $base-width + rooms.$list-width
     box-sizing: border-box
 
 .c-group
-  position: relative
   display: flex
   align-items: center
   padding: $icon-padding / 2 $icon-padding
   cursor: pointer
   border-radius: 8px
-  background-color: c.$darkest
 
   &:hover
     background-color: c.$darker
@@ -64,29 +62,6 @@ $out-width: $base-width + rooms.$list-width
     overflow: hidden
     text-overflow: ellipsis
 
-  &__number
-    position: absolute
-    right: 240px
-    bottom: 0px
-    background: #ddd
-    color: #000
-    font-size: 14px
-    line-height: 1
-    padding: 3px 4px
-    border-radius: 7px
-    border: 3px solid c.$darkest
-    opacity: 0
-    transform: translate(6px, 6px)
-    transition: transform 0.15s ease-out, opacity 0.15s ease-out
-    pointer-events: none
-
-    @at-root .c-group:hover &
-      border-color: c.$darker
-
-    &--active
-      opacity: 1
-      transform: translate(0px, 0px)
-
 .c-group-marker
   position: absolute
   top: 5px
diff --git a/src/sass/components/highlighted-code.sass b/src/sass/components/highlighted-code.sass
deleted file mode 100644
index 1ec7290..0000000
--- a/src/sass/components/highlighted-code.sass
+++ /dev/null
@@ -1 +0,0 @@
-@use "../../../node_modules/highlight.js/scss/obsidian"
diff --git a/src/sass/components/messages.sass b/src/sass/components/messages.sass
index 060dec4..7f56834 100644
--- a/src/sass/components/messages.sass
+++ b/src/sass/components/messages.sass
@@ -1,6 +1,6 @@
 @use "../colors" as c
 
-.c-event-groups > *
+.c-event-groups *
   overflow-anchor: none
 
 .c-message-group, .c-message-event
@@ -9,8 +9,7 @@
   border-top: 1px solid c.$divider
 
 .c-message-group
-  display: grid
-  grid-template-columns: auto 1fr
+  display: flex
 
   &__avatar
     flex-shrink: 0
@@ -24,7 +23,7 @@
     border-radius: 50%
 
     &--no-icon
-      background-color: #bbb
+      background-color: #48d
 
   &__intro
     display: flex
@@ -47,19 +46,9 @@
 
 .c-message
   margin-top: 4px
-  overflow-wrap: anywhere
   opacity: 1
   transition: opacity 0.2s ease-out
 
-  &--plain
-    white-space: pre-wrap
-
-  &--media
-    // fix whitespace
-    font-size: 0
-    margin-top: 8px
-    display: flex
-
   &--pending
     opacity: 0.5
 
@@ -77,70 +66,18 @@
     &:hover
       background-color: c.$darker
 
-  &__image
-    width: auto
-    height: auto
-    max-width: 400px
-    max-height: 300px
-
-  // message formatting rules
-
-  code, pre
-    border-radius: 4px
-    font-size: 0.9em
-
-  pre
-    background-color: c.$darkest
-    padding: 8px
-    border: 1px solid c.$divider
-    white-space: pre-wrap
-
-  code
-    background-color: c.$darker
-    padding: 2px 4px
-
-  a
-    color: c.$link
-
-  blockquote
-    margin-left: 8px
-    border-left: 4px solid c.$muted
-    padding: 2px 0px 2px 12px
-
-  p, pre, blockquote
-    margin: 16px 0px
-
-    &:first-child
-      margin-top: 0px
-
-    &:last-child
-      margin-bottom: 0px
-
 .c-message-event
-  // closer spacing than normal messages
-  padding-top: 2px
+  padding-top: 10px
   padding-left: 6px
-  margin-bottom: -4px
-  line-height: 1.2
 
   &__inner
-    text-indent: -36px
-    margin-left: 36px
-
-  img
-    // let me know if there's a smarter way to line this shit up
-    position: relative
-    top: -5px
-    transform: translateY(50%)
+    display: flex
+    align-items: center
 
   &__icon
     margin-right: 8px
-
-  &__avatar
-    width: 16px
-    height: 16px
-    border-radius: 50%
-    margin: 0px 6px
+    position: relative
+    top: 1px
 
 .c-message-notice
   padding: 12px
@@ -150,37 +87,3 @@
     padding: 12px
     background-color: c.$milder
     border-radius: 8px
-
-.c-media
-  &__wrapper
-    overflow: hidden
-    position: relative
-
-  &--spoiler
-    cursor: pointer
-
-    img
-      filter: blur(40px)
-
-  &--shown img
-    filter: none
-
-  &__spoiler
-    position: absolute
-    top: 0
-    bottom: 0
-    left: 0
-    right: 0
-    display: flex
-    align-items: center
-    justify-content: center
-    font-size: 18px
-    font-weight: 500
-    color: #fff
-    text-transform: uppercase
-    background: rgba(0, 0, 0, 0.3)
-    cursor: pointer
-    pointer-events: none
-
-  &--shown &__spoiler
-    display: none
diff --git a/src/sass/components/read-marker.sass b/src/sass/components/read-marker.sass
deleted file mode 100644
index 7e1c572..0000000
--- a/src/sass/components/read-marker.sass
+++ /dev/null
@@ -1,42 +0,0 @@
-@use "../colors" as c
-
-.c-read-marker
-  display: none
-  position: relative
-
-  &--attached
-    display: block
-
-  &__inner
-    position: absolute
-    left: -64px
-    right: 0px
-    height: 2px
-    top: 0px
-    background-color: c.$notify-highlight
-
-    @at-root .c-message:last-child &
-      top: 11px
-
-    @at-root .c-message-event &
-      top: 7px
-
-  &__text
-    position: absolute
-    right: -14px
-    top: -9px
-    display: flex
-    align-items: center
-    background-color: c.$notify-highlight
-    color: #000
-    font-size: 12px
-    font-weight: 600
-    line-height: 1
-    padding: 4px
-    border-radius: 5px
-    text-transform: uppercase
-
-  &__loading
-    background-color: #000
-    width: 10px
-    height: 10px
diff --git a/src/sass/components/rooms.sass b/src/sass/components/rooms.sass
index 670d9ba..462e13c 100644
--- a/src/sass/components/rooms.sass
+++ b/src/sass/components/rooms.sass
@@ -43,23 +43,3 @@ $icon-padding: 8px
     white-space: nowrap
     overflow: hidden
     text-overflow: ellipsis
-    flex: 1
-
-  &__number
-    flex-shrink: 0
-    line-height: 1
-    padding: 4px 5px
-    border-radius: 5px
-    font-size: 14px
-    pointer-events: none
-
-    &--none
-      display: none
-
-    &--unreads
-      background-color: #ddd
-      color: #111
-
-    &--notifications
-      background-color: #ffac4b
-      color: #000
diff --git a/src/sass/components/spoilers.sass b/src/sass/components/spoilers.sass
deleted file mode 100644
index e8a1784..0000000
--- a/src/sass/components/spoilers.sass
+++ /dev/null
@@ -1,8 +0,0 @@
-.mx-spoiler
-  color: #331911
-  background-color:  #331911
-  outline-color: #fff !important
-  cursor: pointer
-
-  &--shown
-    color: inherit
diff --git a/src/sass/components/typing.sass b/src/sass/components/typing.sass
deleted file mode 100644
index dad8d90..0000000
--- a/src/sass/components/typing.sass
+++ /dev/null
@@ -1,21 +0,0 @@
-@use "../colors" as c
-
-.c-typing
-  height: 39px
-  background: c.$divider
-  position: absolute
-  right: 0
-  left: 0
-  top: 0
-  z-index: 0
-  margin: 20px
-  border-radius: 8px
-  padding: 0px 12px
-  font-size: 14px
-  line-height: 19px
-  transform: translateY(0px)
-  transition: transform 0.15s ease
-  color: #fff
-
-  &--typing
-    transform: translateY(-21px)
diff --git a/src/sass/loading.sass b/src/sass/loading.sass
deleted file mode 100644
index 9705bbe..0000000
--- a/src/sass/loading.sass
+++ /dev/null
@@ -1,13 +0,0 @@
-@keyframes spin
-  0%
-    transform: rotate(0deg)
-  100%
-    transform: rotate(180deg)
-
-.loading-icon
-  display: inline-block
-  background-color: #ccc
-  width: 12px
-  height: 12px
-  margin-right: 6px
-  animation: spin 0.7s infinite
diff --git a/src/sass/login.sass b/src/sass/login.sass
deleted file mode 100644
index 74d08ac..0000000
--- a/src/sass/login.sass
+++ /dev/null
@@ -1,73 +0,0 @@
-@use "./base"
-@use "./loading.sass"
-@use "./colors.sass" as c
-
-
-.main
-  justify-content: center
-  align-items: center
-
-.center-login-container
-  display: flex
-  flex-flow: column
-  justify-content: center
-  align-items: center
-  width: min(100vw, 450px)
-  padding: max(1rem,3vw) 2rem
-  margin: 8px
-  box-shadow: 0px 2px 10px c.$darkest
-  background-color: c.$darker
-  border-radius: 5px
-
-.login-form
-  align-items: center
-  flex: 1 1 auto
-  width: 100%
-  display: flex
-  justify-content: space-around
-  flex-flow: column
-
-.data-input
-  width: 100%
-
-.form-input-container
-  width: 100%
-  display: flex
-  flex-direction: column
-  margin: 1em 0
-
-.form-feedback
-  width: 100%
-  margin: -0.5em 0 -0.8em
-
-.form-error
-  color: red
-
-
-input, button
-  font-family: inherit
-  font-size: 17px
-  background-color: c.$mild
-  color: #eee
-  width: 100%
-  border-radius: 5px
-  box-sizing: border-box
-  transition: background-color 0.15s ease-out, border-color 0.15s ease-out
-  padding: 4px 9px
-  border: 0px
-
-input[type="text"],input[type="password"]
-  border: 3px solid transparent
-  margin: 0.4em 0px
-
-  &:hover, &:focus
-    border-color: c.$milder
-
-button, input[type="submit"]
-  padding: 7px
-
-  &:hover
-    background-color: c.$milder
-
-label
-  font-size: 18px
diff --git a/src/sass/main.sass b/src/sass/main.sass
index c050148..d342bbb 100644
--- a/src/sass/main.sass
+++ b/src/sass/main.sass
@@ -1,13 +1,7 @@
 @use "./base"
-@use "./loading"
 @use "./components/groups"
 @use "./components/rooms"
 @use "./components/messages"
 @use "./components/chat"
 @use "./components/chat-input"
-@use "./components/typing"
 @use "./components/anchor"
-@use "./components/highlighted-code"
-@use "./components/read-marker"
-@use "./components/chat-banner"
-@use "./components/spoilers"