diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..485dee6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.idea
diff --git a/app/composer.json b/app/composer.json
index 39e3351..2408098 100644
--- a/app/composer.json
+++ b/app/composer.json
@@ -55,19 +55,20 @@
"laminas/laminas-diactoros": "^3.0.0",
"laminas/laminas-stdlib": "^3.6",
"mezzio/mezzio": "^3.7",
+ "mezzio/mezzio-authentication-session": "^1.9",
"mezzio/mezzio-fastroute": "^3.11.0",
"mezzio/mezzio-helpers": "^5.7",
"mezzio/mezzio-platesrenderer": "^2.10"
},
"require-dev": {
+ "filp/whoops": "^2.15.4",
"laminas/laminas-coding-standard": "~2.5.0",
"laminas/laminas-development-mode": "^3.12.0",
"mezzio/mezzio-tooling": "^2.9",
"phpunit/phpunit": "^10.5.5",
"psalm/plugin-phpunit": "^0.18.4",
"roave/security-advisories": "dev-master",
- "vimeo/psalm": "^5.18",
- "filp/whoops": "^2.15.4"
+ "vimeo/psalm": "^5.18"
},
"autoload": {
"psr-4": {
diff --git a/app/composer.lock b/app/composer.lock
index eb405bc..cf4b3d6 100644
--- a/app/composer.lock
+++ b/app/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "ac40ea0195435e6db97e4041dd7b543c",
+ "content-hash": "e4a4cfd4117c44efbf1503d8c2d5beb0",
"packages": [
{
"name": "brick/varexporter",
@@ -128,6 +128,68 @@
],
"time": "2022-01-17T14:14:24+00:00"
},
+ {
+ "name": "dflydev/fig-cookies",
+ "version": "v3.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/dflydev/dflydev-fig-cookies.git",
+ "reference": "ebe6c15c9895fc490efe620ad734c8ef4a85bdb0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/dflydev/dflydev-fig-cookies/zipball/ebe6c15c9895fc490efe620ad734c8ef4a85bdb0",
+ "reference": "ebe6c15c9895fc490efe620ad734c8ef4a85bdb0",
+ "shasum": ""
+ },
+ "require": {
+ "ext-pcre": "*",
+ "php": "^7.2 || ^8.0",
+ "psr/http-message": "^1.0.1 || ^2"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^8",
+ "phpstan/extension-installer": "^1.0",
+ "phpstan/phpstan": "^0.12",
+ "phpstan/phpstan-phpunit": "^0.12.16",
+ "phpunit/phpunit": "^7.2.6 || ^9",
+ "scrutinizer/ocular": "^1.8",
+ "squizlabs/php_codesniffer": "^3.3",
+ "vimeo/psalm": "^4.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Dflydev\\FigCookies\\": "src/Dflydev/FigCookies"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Beau Simensen",
+ "email": "beau@dflydev.com"
+ }
+ ],
+ "description": "Cookies for PSR-7 HTTP Message Interface.",
+ "keywords": [
+ "cookies",
+ "psr-7",
+ "psr7"
+ ],
+ "support": {
+ "issues": "https://github.com/dflydev/dflydev-fig-cookies/issues",
+ "source": "https://github.com/dflydev/dflydev-fig-cookies/tree/v3.1.0"
+ },
+ "time": "2023-07-18T20:41:43+00:00"
+ },
{
"name": "elie29/zend-phpdi-config",
"version": "v9.0.1",
@@ -969,6 +1031,158 @@
],
"time": "2024-02-14T10:42:11+00:00"
},
+ {
+ "name": "mezzio/mezzio-authentication",
+ "version": "1.9.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/mezzio/mezzio-authentication.git",
+ "reference": "2e232154ea7ea44800b4706a9242220bf16958e5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/mezzio/mezzio-authentication/zipball/2e232154ea7ea44800b4706a9242220bf16958e5",
+ "reference": "2e232154ea7ea44800b4706a9242220bf16958e5",
+ "shasum": ""
+ },
+ "require": {
+ "php": "~8.1.0 || ~8.2.0 || ~8.3.0",
+ "psr/container": "^1.0 || ^2.0",
+ "psr/http-message": "^1.0.1 || ^2.0.0",
+ "psr/http-server-middleware": "^1.0",
+ "webmozart/assert": "^1.11.0"
+ },
+ "conflict": {
+ "container-interop/container-interop": "<1.2.0",
+ "zendframework/zend-expressive-authentication": "*"
+ },
+ "require-dev": {
+ "ext-sqlite3": "*",
+ "laminas/laminas-coding-standard": "~2.5.0",
+ "phpunit/phpunit": "^10.4.2",
+ "psalm/plugin-phpunit": "^0.18.4",
+ "vimeo/psalm": "^5.16"
+ },
+ "suggest": {
+ "ext-pdo": "*: for use with the PDO-backed UserRepositoryInterface implementation",
+ "mezzio/mezzio-authentication-basic": "Provides an HTTP Basic Authentication AuthenticationInterface implementation",
+ "mezzio/mezzio-authentication-laminasauthentication": "Provides a laminas-authentication AuthenticationInterface implementation",
+ "mezzio/mezzio-authentication-session": "Provides a username/password + session AuthenticationInterface implementation"
+ },
+ "type": "library",
+ "extra": {
+ "laminas": {
+ "config-provider": "Mezzio\\Authentication\\ConfigProvider"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Mezzio\\Authentication\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Authentication middleware for Mezzio and PSR-7 applications",
+ "homepage": "https://mezzio.dev",
+ "keywords": [
+ "Authentication",
+ "http",
+ "laminas",
+ "mezzio",
+ "middleware",
+ "psr-15",
+ "psr-7"
+ ],
+ "support": {
+ "chat": "https://laminas.dev/chat",
+ "docs": "https://docs.mezzio.dev/mezzio-authentication/",
+ "forum": "https://discourse.laminas.dev",
+ "issues": "https://github.com/mezzio/mezzio-authentication/issues",
+ "rss": "https://github.com/mezzio/mezzio-authentication/releases.atom",
+ "source": "https://github.com/mezzio/mezzio-authentication"
+ },
+ "funding": [
+ {
+ "url": "https://funding.communitybridge.org/projects/laminas-project",
+ "type": "community_bridge"
+ }
+ ],
+ "time": "2023-11-28T15:52:34+00:00"
+ },
+ {
+ "name": "mezzio/mezzio-authentication-session",
+ "version": "1.9.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/mezzio/mezzio-authentication-session.git",
+ "reference": "19ff41fa09808b7fce968e14faf31c5c4fbec788"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/mezzio/mezzio-authentication-session/zipball/19ff41fa09808b7fce968e14faf31c5c4fbec788",
+ "reference": "19ff41fa09808b7fce968e14faf31c5c4fbec788",
+ "shasum": ""
+ },
+ "require": {
+ "mezzio/mezzio-authentication": "^1.3",
+ "mezzio/mezzio-session": "^1.6",
+ "php": "~8.1.0 || ~8.2.0 || ~8.3.0",
+ "psr/container": "^1.0 || ^2.0",
+ "psr/http-factory": "^1.0",
+ "psr/http-message": "^1.0.1 || ^2.0.0",
+ "webmozart/assert": "^1.10"
+ },
+ "conflict": {
+ "zendframework/zend-expressive-authentication-session": "*"
+ },
+ "require-dev": {
+ "laminas/laminas-coding-standard": "~2.5.0",
+ "laminas/laminas-diactoros": "^3.3",
+ "phpunit/phpunit": "^10.5.5",
+ "psalm/plugin-phpunit": "^0.18.4",
+ "vimeo/psalm": "^5.18.0"
+ },
+ "type": "library",
+ "extra": {
+ "laminas": {
+ "config-provider": "Mezzio\\Authentication\\Session\\ConfigProvider"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Mezzio\\Authentication\\Session\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Username/password, session-backed authentication adapter for mezzio-authentication.",
+ "homepage": "https://mezzio.dev",
+ "keywords": [
+ "Authentication",
+ "laminas",
+ "mezzio",
+ "session"
+ ],
+ "support": {
+ "chat": "https://laminas.dev/chat",
+ "docs": "https://docs.mezzio.dev/mezzio-authentication-session/",
+ "forum": "https://discourse.laminas.dev",
+ "issues": "https://github.com/mezzio/mezzio-authentication-session/issues",
+ "rss": "https://github.com/mezzio/mezzio-authentication-session/releases.atom",
+ "source": "https://github.com/mezzio/mezzio-authentication-session"
+ },
+ "funding": [
+ {
+ "url": "https://funding.communitybridge.org/projects/laminas-project",
+ "type": "community_bridge"
+ }
+ ],
+ "time": "2024-01-01T21:20:46+00:00"
+ },
{
"name": "mezzio/mezzio-fastroute",
"version": "3.11.0",
@@ -1280,6 +1494,82 @@
],
"time": "2023-10-31T17:23:17+00:00"
},
+ {
+ "name": "mezzio/mezzio-session",
+ "version": "1.14.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/mezzio/mezzio-session.git",
+ "reference": "8e5d85644c6749149e3ef2de91a82ae0bd363b3d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/mezzio/mezzio-session/zipball/8e5d85644c6749149e3ef2de91a82ae0bd363b3d",
+ "reference": "8e5d85644c6749149e3ef2de91a82ae0bd363b3d",
+ "shasum": ""
+ },
+ "require": {
+ "dflydev/fig-cookies": "^3.0",
+ "ext-json": "*",
+ "php": "~8.1.0 || ~8.2.0 || ~8.3.0",
+ "psr/container": "^1.0 || ^2.0",
+ "psr/http-server-middleware": "^1.0"
+ },
+ "conflict": {
+ "zendframework/zend-expressive-session": "*"
+ },
+ "require-dev": {
+ "laminas/laminas-coding-standard": "~2.5.0",
+ "laminas/laminas-diactoros": "^3.3.0",
+ "phpunit/phpunit": "^10.4.2",
+ "psalm/plugin-phpunit": "^0.18.4",
+ "vimeo/psalm": "^5.15"
+ },
+ "suggest": {
+ "mezzio/mezzio-csrf": "^1.0 || ^1.0-dev for CSRF protection capabilities",
+ "mezzio/mezzio-flash": "^1.0 || ^1.0-dev for flash message capabilities",
+ "mezzio/mezzio-session-ext": "^1.0 || ^1.0-dev for an ext-session persistence adapter"
+ },
+ "type": "library",
+ "extra": {
+ "laminas": {
+ "config-provider": "Mezzio\\Session\\ConfigProvider"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Mezzio\\Session\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Session container and middleware for PSR-7 applications",
+ "homepage": "https://mezzio.dev",
+ "keywords": [
+ "laminas",
+ "mezzio",
+ "middleware",
+ "psr-7",
+ "session"
+ ],
+ "support": {
+ "chat": "https://laminas.dev/chat",
+ "docs": "https://docs.mezzio.dev/mezzio-session/",
+ "forum": "https://discourse.laminas.dev",
+ "issues": "https://github.com/mezzio/mezzio-session/issues",
+ "rss": "https://github.com/mezzio/mezzio-session/releases.atom",
+ "source": "https://github.com/mezzio/mezzio-session"
+ },
+ "funding": [
+ {
+ "url": "https://funding.communitybridge.org/projects/laminas-project",
+ "type": "community_bridge"
+ }
+ ],
+ "time": "2024-01-13T12:11:07+00:00"
+ },
{
"name": "mezzio/mezzio-template",
"version": "2.10.0",
diff --git a/app/config/autoload/dependencies.global.php b/app/config/autoload/dependencies.global.php
index cc8b534..cd68c29 100644
--- a/app/config/autoload/dependencies.global.php
+++ b/app/config/autoload/dependencies.global.php
@@ -2,6 +2,11 @@
declare(strict_types=1);
+use Mezzio\Authentication\AuthenticationInterface;
+use Mezzio\Authentication\Session\PhpSession;
+use Mezzio\Authentication\UserRepository\PdoDatabase;
+use Mezzio\Authentication\UserRepositoryInterface;
+
return [
// Provides application-wide services.
// We recommend using fully-qualified class names whenever possible as
@@ -10,7 +15,8 @@ return [
// Use 'aliases' to alias a service name to another service. The
// key is the alias name, the value is the service to which it points.
'aliases' => [
- // Fully\Qualified\ClassOrInterfaceName::class => Fully\Qualified\ClassName::class,
+ AuthenticationInterface::class => PhpSession::class,
+ UserRepositoryInterface::class => PdoDatabase::class,
],
// Use 'invokables' for constructor-less services, or services that do
// not require arguments to the constructor. Map a service name to the
diff --git a/app/config/autoload/mezzio-tooling-factories.global.php b/app/config/autoload/mezzio-tooling-factories.global.php
new file mode 100644
index 0000000..190002c
--- /dev/null
+++ b/app/config/autoload/mezzio-tooling-factories.global.php
@@ -0,0 +1,19 @@
+ [
+ 'factories' => [
+ App\Login\LoginHandler::class => App\Login\LoginHandlerFactory::class,
+ ],
+ ],
+];
diff --git a/app/config/autoload/mezzio.global.php b/app/config/autoload/mezzio.global.php
index 64d701e..cf70e76 100644
--- a/app/config/autoload/mezzio.global.php
+++ b/app/config/autoload/mezzio.global.php
@@ -21,4 +21,7 @@ return [
'template_error' => 'error::error',
],
],
+ 'authentication' => [
+ 'redirect' => '/login',
+ ],
];
diff --git a/app/config/config.php b/app/config/config.php
index c1abe84..824b2aa 100644
--- a/app/config/config.php
+++ b/app/config/config.php
@@ -14,6 +14,9 @@ $cacheConfig = [
];
$aggregator = new ConfigAggregator([
+ \Mezzio\Authentication\Session\ConfigProvider::class,
+ \Mezzio\Authentication\ConfigProvider::class,
+ \Mezzio\Session\ConfigProvider::class,
\Mezzio\Tooling\ConfigProvider::class,
\Mezzio\Plates\ConfigProvider::class,
\Mezzio\Helper\ConfigProvider::class,
diff --git a/app/src/App/src/Login/LoginHandler.php b/app/src/App/src/Login/LoginHandler.php
new file mode 100644
index 0000000..02b5ec7
--- /dev/null
+++ b/app/src/App/src/Login/LoginHandler.php
@@ -0,0 +1,34 @@
+renderer = $renderer;
+ }
+
+ public function handle(ServerRequestInterface $request) : ResponseInterface
+ {
+ // Do some work...
+ // Render and return a response:
+ return new HtmlResponse($this->renderer->render(
+ 'app::login',
+ [] // parameters to pass to template
+ ));
+ }
+}
diff --git a/app/src/App/src/Login/LoginHandlerFactory.php b/app/src/App/src/Login/LoginHandlerFactory.php
new file mode 100644
index 0000000..0721215
--- /dev/null
+++ b/app/src/App/src/Login/LoginHandlerFactory.php
@@ -0,0 +1,16 @@
+get(TemplateRendererInterface::class));
+ }
+}
diff --git a/app/src/App/templates/app/login-page.phtml b/app/src/App/templates/app/login-page.phtml
deleted file mode 100644
index 3f2c3d6..0000000
--- a/app/src/App/templates/app/login-page.phtml
+++ /dev/null
@@ -1,17 +0,0 @@
-layout('layout::default', ['title' => 'Home']) ?>
-
-
diff --git a/app/src/App/templates/app/login.phtml b/app/src/App/templates/app/login.phtml
new file mode 100644
index 0000000..33449fe
--- /dev/null
+++ b/app/src/App/templates/app/login.phtml
@@ -0,0 +1 @@
+Template for App\Login\LoginHandler
\ No newline at end of file
diff --git a/app/src/App/templates/fragments/login-form.phtml b/app/src/App/templates/fragments/login-form.phtml
deleted file mode 100644
index a94ab4e..0000000
--- a/app/src/App/templates/fragments/login-form.phtml
+++ /dev/null
@@ -1,18 +0,0 @@
-
diff --git a/frontend/.editorconfig b/frontend/.editorconfig
new file mode 100644
index 0000000..f086e7f
--- /dev/null
+++ b/frontend/.editorconfig
@@ -0,0 +1,3 @@
+[*.{html,js,jsx,ts,tsx}]
+indent_type = space
+indent_size = 2
diff --git a/frontend/.gitignore b/frontend/.gitignore
new file mode 100644
index 0000000..468f82a
--- /dev/null
+++ b/frontend/.gitignore
@@ -0,0 +1,175 @@
+# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
+
+# Logs
+
+logs
+_.log
+npm-debug.log_
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Caches
+
+.cache
+
+# 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/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+
+web_modules/
+
+# TypeScript cache
+
+*.tsbuildinfo
+
+# Optional npm cache directory
+
+.npm
+
+# Optional eslint cache
+
+.eslintcache
+
+# Optional stylelint cache
+
+.stylelintcache
+
+# 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 variable files
+
+.env
+.env.development.local
+.env.test.local
+.env.production.local
+.env.local
+
+# parcel-bundler cache (https://parceljs.org/)
+
+.parcel-cache
+
+# Next.js build output
+
+.next
+out
+
+# Nuxt.js build / generate output
+
+.nuxt
+dist
+
+# Gatsby files
+
+# 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
+
+# vuepress v2.x temp and cache directory
+
+.temp
+
+# Docusaurus cache and generated files
+
+.docusaurus
+
+# 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
+
+# yarn v2
+
+.yarn/cache
+.yarn/unplugged
+.yarn/build-state.yml
+.yarn/install-state.gz
+.pnp.*
+
+# IntelliJ based IDEs
+.idea
+
+# Finder (MacOS) folder config
+.DS_Store
diff --git a/frontend/README.md b/frontend/README.md
new file mode 100644
index 0000000..a9f5141
--- /dev/null
+++ b/frontend/README.md
@@ -0,0 +1,15 @@
+# slovocast-frontend
+
+To install dependencies:
+
+```bash
+bun install
+```
+
+To run:
+
+```bash
+bun run index.ts
+```
+
+This project was created using `bun init` in bun v1.0.24. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
diff --git a/frontend/build.ts b/frontend/build.ts
new file mode 100644
index 0000000..ec4bcf5
--- /dev/null
+++ b/frontend/build.ts
@@ -0,0 +1,4 @@
+await Bun.build({
+ entrypoints: [ './src/index.ts' ],
+ outdir: './public/js'
+});
diff --git a/frontend/bun.lockb b/frontend/bun.lockb
new file mode 100755
index 0000000..eb366bb
Binary files /dev/null and b/frontend/bun.lockb differ
diff --git a/frontend/package.json b/frontend/package.json
new file mode 100644
index 0000000..a995dac
--- /dev/null
+++ b/frontend/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "slovocast-frontend",
+ "module": "index.ts",
+ "type": "module",
+ "devDependencies": {
+ "@types/bun": "latest",
+ "@types/mithril": "^2.2.6"
+ },
+ "peerDependencies": {
+ "typescript": "^5.0.0"
+ },
+ "dependencies": {
+ "bun": "^1.0.29",
+ "mithril": "^2.2.2"
+ }
+}
\ No newline at end of file
diff --git a/frontend/public/index.html b/frontend/public/index.html
new file mode 100644
index 0000000..8c68dd2
--- /dev/null
+++ b/frontend/public/index.html
@@ -0,0 +1,9 @@
+
+
+
+ Slovocast
+
+
+
+
+
diff --git a/frontend/public/js/index.js b/frontend/public/js/index.js
new file mode 100644
index 0000000..744a1da
--- /dev/null
+++ b/frontend/public/js/index.js
@@ -0,0 +1,1934 @@
+var __create = Object.create;
+var __defProp = Object.defineProperty;
+var __getProtoOf = Object.getPrototypeOf;
+var __getOwnPropNames = Object.getOwnPropertyNames;
+var __hasOwnProp = Object.prototype.hasOwnProperty;
+var __toESM = (mod, isNodeMode, target) => {
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
+ for (let key of __getOwnPropNames(mod))
+ if (!__hasOwnProp.call(to, key))
+ __defProp(to, key, {
+ get: () => mod[key],
+ enumerable: true
+ });
+ return to;
+};
+var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
+
+// node_modules/mithril/render/vnode.js
+var require_vnode = __commonJS((exports, module) => {
+ var Vnode = function(tag, key, attrs, children, text, dom) {
+ return { tag, key, attrs, children, text, dom, domSize: undefined, state: undefined, events: undefined, instance: undefined };
+ };
+ Vnode.normalize = function(node) {
+ if (Array.isArray(node))
+ return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined);
+ if (node == null || typeof node === "boolean")
+ return null;
+ if (typeof node === "object")
+ return node;
+ return Vnode("#", undefined, undefined, String(node), undefined, undefined);
+ };
+ Vnode.normalizeChildren = function(input) {
+ var children = [];
+ if (input.length) {
+ var isKeyed = input[0] != null && input[0].key != null;
+ for (var i = 1;i < input.length; i++) {
+ if ((input[i] != null && input[i].key != null) !== isKeyed) {
+ throw new TypeError(isKeyed && (input[i] != null || typeof input[i] === "boolean") ? "In fragments, vnodes must either all have keys or none have keys. You may wish to consider using an explicit keyed empty fragment, m.fragment({key: ...}), instead of a hole." : "In fragments, vnodes must either all have keys or none have keys.");
+ }
+ }
+ for (var i = 0;i < input.length; i++) {
+ children[i] = Vnode.normalize(input[i]);
+ }
+ }
+ return children;
+ };
+ module.exports = Vnode;
+});
+
+// node_modules/mithril/render/hyperscriptVnode.js
+var require_hyperscriptVnode = __commonJS((exports, module) => {
+ var Vnode = require_vnode();
+ module.exports = function() {
+ var attrs = arguments[this], start = this + 1, children;
+ if (attrs == null) {
+ attrs = {};
+ } else if (typeof attrs !== "object" || attrs.tag != null || Array.isArray(attrs)) {
+ attrs = {};
+ start = this;
+ }
+ if (arguments.length === start + 1) {
+ children = arguments[start];
+ if (!Array.isArray(children))
+ children = [children];
+ } else {
+ children = [];
+ while (start < arguments.length)
+ children.push(arguments[start++]);
+ }
+ return Vnode("", attrs.key, attrs, children);
+ };
+});
+
+// node_modules/mithril/util/hasOwn.js
+var require_hasOwn = __commonJS((exports, module) => {
+ module.exports = {}.hasOwnProperty;
+});
+
+// node_modules/mithril/render/hyperscript.js
+var require_hyperscript = __commonJS((exports, module) => {
+ var isEmpty = function(object) {
+ for (var key in object)
+ if (hasOwn.call(object, key))
+ return false;
+ return true;
+ };
+ var compileSelector = function(selector) {
+ var match, tag = "div", classes = [], attrs = {};
+ while (match = selectorParser.exec(selector)) {
+ var type = match[1], value = match[2];
+ if (type === "" && value !== "")
+ tag = value;
+ else if (type === "#")
+ attrs.id = value;
+ else if (type === ".")
+ classes.push(value);
+ else if (match[3][0] === "[") {
+ var attrValue = match[6];
+ if (attrValue)
+ attrValue = attrValue.replace(/\\(["'])/g, "$1").replace(/\\\\/g, "\\");
+ if (match[4] === "class")
+ classes.push(attrValue);
+ else
+ attrs[match[4]] = attrValue === "" ? attrValue : attrValue || true;
+ }
+ }
+ if (classes.length > 0)
+ attrs.className = classes.join(" ");
+ return selectorCache[selector] = { tag, attrs };
+ };
+ var execSelector = function(state, vnode) {
+ var attrs = vnode.attrs;
+ var hasClass = hasOwn.call(attrs, "class");
+ var className = hasClass ? attrs.class : attrs.className;
+ vnode.tag = state.tag;
+ vnode.attrs = {};
+ if (!isEmpty(state.attrs) && !isEmpty(attrs)) {
+ var newAttrs = {};
+ for (var key in attrs) {
+ if (hasOwn.call(attrs, key))
+ newAttrs[key] = attrs[key];
+ }
+ attrs = newAttrs;
+ }
+ for (var key in state.attrs) {
+ if (hasOwn.call(state.attrs, key) && key !== "className" && !hasOwn.call(attrs, key)) {
+ attrs[key] = state.attrs[key];
+ }
+ }
+ if (className != null || state.attrs.className != null)
+ attrs.className = className != null ? state.attrs.className != null ? String(state.attrs.className) + " " + String(className) : className : state.attrs.className != null ? state.attrs.className : null;
+ if (hasClass)
+ attrs.class = null;
+ for (var key in attrs) {
+ if (hasOwn.call(attrs, key) && key !== "key") {
+ vnode.attrs = attrs;
+ break;
+ }
+ }
+ return vnode;
+ };
+ var hyperscript = function(selector) {
+ if (selector == null || typeof selector !== "string" && typeof selector !== "function" && typeof selector.view !== "function") {
+ throw Error("The selector must be either a string or a component.");
+ }
+ var vnode = hyperscriptVnode.apply(1, arguments);
+ if (typeof selector === "string") {
+ vnode.children = Vnode.normalizeChildren(vnode.children);
+ if (selector !== "[")
+ return execSelector(selectorCache[selector] || compileSelector(selector), vnode);
+ }
+ vnode.tag = selector;
+ return vnode;
+ };
+ var Vnode = require_vnode();
+ var hyperscriptVnode = require_hyperscriptVnode();
+ var hasOwn = require_hasOwn();
+ var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g;
+ var selectorCache = {};
+ module.exports = hyperscript;
+});
+
+// node_modules/mithril/render/trust.js
+var require_trust = __commonJS((exports, module) => {
+ var Vnode = require_vnode();
+ module.exports = function(html) {
+ if (html == null)
+ html = "";
+ return Vnode("<", undefined, undefined, html, undefined, undefined);
+ };
+});
+
+// node_modules/mithril/render/fragment.js
+var require_fragment = __commonJS((exports, module) => {
+ var Vnode = require_vnode();
+ var hyperscriptVnode = require_hyperscriptVnode();
+ module.exports = function() {
+ var vnode = hyperscriptVnode.apply(0, arguments);
+ vnode.tag = "[";
+ vnode.children = Vnode.normalizeChildren(vnode.children);
+ return vnode;
+ };
+});
+
+// node_modules/mithril/hyperscript.js
+var require_hyperscript2 = __commonJS((exports, module) => {
+ var hyperscript = require_hyperscript();
+ hyperscript.trust = require_trust();
+ hyperscript.fragment = require_fragment();
+ module.exports = hyperscript;
+});
+
+// node_modules/mithril/promise/polyfill.js
+var require_polyfill = __commonJS((exports, module) => {
+ var PromisePolyfill = function(executor) {
+ if (!(this instanceof PromisePolyfill))
+ throw new Error("Promise must be called with 'new'.");
+ if (typeof executor !== "function")
+ throw new TypeError("executor must be a function.");
+ var self = this, resolvers = [], rejectors = [], resolveCurrent = handler(resolvers, true), rejectCurrent = handler(rejectors, false);
+ var instance = self._instance = { resolvers, rejectors };
+ var callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout;
+ function handler(list, shouldAbsorb) {
+ return function execute(value) {
+ var then;
+ try {
+ if (shouldAbsorb && value != null && (typeof value === "object" || typeof value === "function") && typeof (then = value.then) === "function") {
+ if (value === self)
+ throw new TypeError("Promise can't be resolved with itself.");
+ executeOnce(then.bind(value));
+ } else {
+ callAsync(function() {
+ if (!shouldAbsorb && list.length === 0)
+ console.error("Possible unhandled promise rejection:", value);
+ for (var i = 0;i < list.length; i++)
+ list[i](value);
+ resolvers.length = 0, rejectors.length = 0;
+ instance.state = shouldAbsorb;
+ instance.retry = function() {
+ execute(value);
+ };
+ });
+ }
+ } catch (e) {
+ rejectCurrent(e);
+ }
+ };
+ }
+ function executeOnce(then) {
+ var runs = 0;
+ function run(fn) {
+ return function(value) {
+ if (runs++ > 0)
+ return;
+ fn(value);
+ };
+ }
+ var onerror = run(rejectCurrent);
+ try {
+ then(run(resolveCurrent), onerror);
+ } catch (e) {
+ onerror(e);
+ }
+ }
+ executeOnce(executor);
+ };
+ PromisePolyfill.prototype.then = function(onFulfilled, onRejection) {
+ var self = this, instance = self._instance;
+ function handle(callback, list, next, state) {
+ list.push(function(value) {
+ if (typeof callback !== "function")
+ next(value);
+ else
+ try {
+ resolveNext(callback(value));
+ } catch (e) {
+ if (rejectNext)
+ rejectNext(e);
+ }
+ });
+ if (typeof instance.retry === "function" && state === instance.state)
+ instance.retry();
+ }
+ var resolveNext, rejectNext;
+ var promise = new PromisePolyfill(function(resolve, reject) {
+ resolveNext = resolve, rejectNext = reject;
+ });
+ handle(onFulfilled, instance.resolvers, resolveNext, true), handle(onRejection, instance.rejectors, rejectNext, false);
+ return promise;
+ };
+ PromisePolyfill.prototype.catch = function(onRejection) {
+ return this.then(null, onRejection);
+ };
+ PromisePolyfill.prototype.finally = function(callback) {
+ return this.then(function(value) {
+ return PromisePolyfill.resolve(callback()).then(function() {
+ return value;
+ });
+ }, function(reason) {
+ return PromisePolyfill.resolve(callback()).then(function() {
+ return PromisePolyfill.reject(reason);
+ });
+ });
+ };
+ PromisePolyfill.resolve = function(value) {
+ if (value instanceof PromisePolyfill)
+ return value;
+ return new PromisePolyfill(function(resolve) {
+ resolve(value);
+ });
+ };
+ PromisePolyfill.reject = function(value) {
+ return new PromisePolyfill(function(resolve, reject) {
+ reject(value);
+ });
+ };
+ PromisePolyfill.all = function(list) {
+ return new PromisePolyfill(function(resolve, reject) {
+ var total = list.length, count = 0, values = [];
+ if (list.length === 0)
+ resolve([]);
+ else
+ for (var i = 0;i < list.length; i++) {
+ (function(i2) {
+ function consume(value) {
+ count++;
+ values[i2] = value;
+ if (count === total)
+ resolve(values);
+ }
+ if (list[i2] != null && (typeof list[i2] === "object" || typeof list[i2] === "function") && typeof list[i2].then === "function") {
+ list[i2].then(consume, reject);
+ } else
+ consume(list[i2]);
+ })(i);
+ }
+ });
+ };
+ PromisePolyfill.race = function(list) {
+ return new PromisePolyfill(function(resolve, reject) {
+ for (var i = 0;i < list.length; i++) {
+ list[i].then(resolve, reject);
+ }
+ });
+ };
+ module.exports = PromisePolyfill;
+});
+
+// node_modules/mithril/promise/promise.js
+var require_promise = __commonJS((exports, module) => {
+ var PromisePolyfill = require_polyfill();
+ if (typeof window !== "undefined") {
+ if (typeof window.Promise === "undefined") {
+ window.Promise = PromisePolyfill;
+ } else if (!window.Promise.prototype.finally) {
+ window.Promise.prototype.finally = PromisePolyfill.prototype.finally;
+ }
+ module.exports = window.Promise;
+ } else if (typeof global !== "undefined") {
+ if (typeof global.Promise === "undefined") {
+ global.Promise = PromisePolyfill;
+ } else if (!global.Promise.prototype.finally) {
+ global.Promise.prototype.finally = PromisePolyfill.prototype.finally;
+ }
+ module.exports = global.Promise;
+ } else {
+ module.exports = PromisePolyfill;
+ }
+});
+
+// node_modules/mithril/render/render.js
+var require_render = __commonJS((exports, module) => {
+ var Vnode = require_vnode();
+ module.exports = function($window) {
+ var $doc = $window && $window.document;
+ var currentRedraw;
+ var nameSpace = {
+ svg: "http://www.w3.org/2000/svg",
+ math: "http://www.w3.org/1998/Math/MathML"
+ };
+ function getNameSpace(vnode) {
+ return vnode.attrs && vnode.attrs.xmlns || nameSpace[vnode.tag];
+ }
+ function checkState(vnode, original) {
+ if (vnode.state !== original)
+ throw new Error("'vnode.state' must not be modified.");
+ }
+ function callHook(vnode) {
+ var original = vnode.state;
+ try {
+ return this.apply(original, arguments);
+ } finally {
+ checkState(vnode, original);
+ }
+ }
+ function activeElement() {
+ try {
+ return $doc.activeElement;
+ } catch (e) {
+ return null;
+ }
+ }
+ function createNodes(parent, vnodes, start, end, hooks, nextSibling, ns) {
+ for (var i = start;i < end; i++) {
+ var vnode = vnodes[i];
+ if (vnode != null) {
+ createNode(parent, vnode, hooks, ns, nextSibling);
+ }
+ }
+ }
+ function createNode(parent, vnode, hooks, ns, nextSibling) {
+ var tag = vnode.tag;
+ if (typeof tag === "string") {
+ vnode.state = {};
+ if (vnode.attrs != null)
+ initLifecycle(vnode.attrs, vnode, hooks);
+ switch (tag) {
+ case "#":
+ createText(parent, vnode, nextSibling);
+ break;
+ case "<":
+ createHTML(parent, vnode, ns, nextSibling);
+ break;
+ case "[":
+ createFragment(parent, vnode, hooks, ns, nextSibling);
+ break;
+ default:
+ createElement(parent, vnode, hooks, ns, nextSibling);
+ }
+ } else
+ createComponent(parent, vnode, hooks, ns, nextSibling);
+ }
+ function createText(parent, vnode, nextSibling) {
+ vnode.dom = $doc.createTextNode(vnode.children);
+ insertNode(parent, vnode.dom, nextSibling);
+ }
+ var possibleParents = { caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup" };
+ function createHTML(parent, vnode, ns, nextSibling) {
+ var match = vnode.children.match(/^\s*?<(\w+)/im) || [];
+ var temp = $doc.createElement(possibleParents[match[1]] || "div");
+ if (ns === "http://www.w3.org/2000/svg") {
+ temp.innerHTML = "";
+ temp = temp.firstChild;
+ } else {
+ temp.innerHTML = vnode.children;
+ }
+ vnode.dom = temp.firstChild;
+ vnode.domSize = temp.childNodes.length;
+ vnode.instance = [];
+ var fragment = $doc.createDocumentFragment();
+ var child;
+ while (child = temp.firstChild) {
+ vnode.instance.push(child);
+ fragment.appendChild(child);
+ }
+ insertNode(parent, fragment, nextSibling);
+ }
+ function createFragment(parent, vnode, hooks, ns, nextSibling) {
+ var fragment = $doc.createDocumentFragment();
+ if (vnode.children != null) {
+ var children = vnode.children;
+ createNodes(fragment, children, 0, children.length, hooks, null, ns);
+ }
+ vnode.dom = fragment.firstChild;
+ vnode.domSize = fragment.childNodes.length;
+ insertNode(parent, fragment, nextSibling);
+ }
+ function createElement(parent, vnode, hooks, ns, nextSibling) {
+ var tag = vnode.tag;
+ var attrs = vnode.attrs;
+ var is = attrs && attrs.is;
+ ns = getNameSpace(vnode) || ns;
+ var element = ns ? is ? $doc.createElementNS(ns, tag, { is }) : $doc.createElementNS(ns, tag) : is ? $doc.createElement(tag, { is }) : $doc.createElement(tag);
+ vnode.dom = element;
+ if (attrs != null) {
+ setAttrs(vnode, attrs, ns);
+ }
+ insertNode(parent, element, nextSibling);
+ if (!maybeSetContentEditable(vnode)) {
+ if (vnode.children != null) {
+ var children = vnode.children;
+ createNodes(element, children, 0, children.length, hooks, null, ns);
+ if (vnode.tag === "select" && attrs != null)
+ setLateSelectAttrs(vnode, attrs);
+ }
+ }
+ }
+ function initComponent(vnode, hooks) {
+ var sentinel;
+ if (typeof vnode.tag.view === "function") {
+ vnode.state = Object.create(vnode.tag);
+ sentinel = vnode.state.view;
+ if (sentinel.$$reentrantLock$$ != null)
+ return;
+ sentinel.$$reentrantLock$$ = true;
+ } else {
+ vnode.state = undefined;
+ sentinel = vnode.tag;
+ if (sentinel.$$reentrantLock$$ != null)
+ return;
+ sentinel.$$reentrantLock$$ = true;
+ vnode.state = vnode.tag.prototype != null && typeof vnode.tag.prototype.view === "function" ? new vnode.tag(vnode) : vnode.tag(vnode);
+ }
+ initLifecycle(vnode.state, vnode, hooks);
+ if (vnode.attrs != null)
+ initLifecycle(vnode.attrs, vnode, hooks);
+ vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode));
+ if (vnode.instance === vnode)
+ throw Error("A view cannot return the vnode it received as argument");
+ sentinel.$$reentrantLock$$ = null;
+ }
+ function createComponent(parent, vnode, hooks, ns, nextSibling) {
+ initComponent(vnode, hooks);
+ if (vnode.instance != null) {
+ createNode(parent, vnode.instance, hooks, ns, nextSibling);
+ vnode.dom = vnode.instance.dom;
+ vnode.domSize = vnode.dom != null ? vnode.instance.domSize : 0;
+ } else {
+ vnode.domSize = 0;
+ }
+ }
+ function updateNodes(parent, old, vnodes, hooks, nextSibling, ns) {
+ if (old === vnodes || old == null && vnodes == null)
+ return;
+ else if (old == null || old.length === 0)
+ createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns);
+ else if (vnodes == null || vnodes.length === 0)
+ removeNodes(parent, old, 0, old.length);
+ else {
+ var isOldKeyed = old[0] != null && old[0].key != null;
+ var isKeyed = vnodes[0] != null && vnodes[0].key != null;
+ var start = 0, oldStart = 0;
+ if (!isOldKeyed)
+ while (oldStart < old.length && old[oldStart] == null)
+ oldStart++;
+ if (!isKeyed)
+ while (start < vnodes.length && vnodes[start] == null)
+ start++;
+ if (isOldKeyed !== isKeyed) {
+ removeNodes(parent, old, oldStart, old.length);
+ createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns);
+ } else if (!isKeyed) {
+ var commonLength = old.length < vnodes.length ? old.length : vnodes.length;
+ start = start < oldStart ? start : oldStart;
+ for (;start < commonLength; start++) {
+ o = old[start];
+ v = vnodes[start];
+ if (o === v || o == null && v == null)
+ continue;
+ else if (o == null)
+ createNode(parent, v, hooks, ns, getNextSibling(old, start + 1, nextSibling));
+ else if (v == null)
+ removeNode(parent, o);
+ else
+ updateNode(parent, o, v, hooks, getNextSibling(old, start + 1, nextSibling), ns);
+ }
+ if (old.length > commonLength)
+ removeNodes(parent, old, start, old.length);
+ if (vnodes.length > commonLength)
+ createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns);
+ } else {
+ var oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oe, ve, topSibling;
+ while (oldEnd >= oldStart && end >= start) {
+ oe = old[oldEnd];
+ ve = vnodes[end];
+ if (oe.key !== ve.key)
+ break;
+ if (oe !== ve)
+ updateNode(parent, oe, ve, hooks, nextSibling, ns);
+ if (ve.dom != null)
+ nextSibling = ve.dom;
+ oldEnd--, end--;
+ }
+ while (oldEnd >= oldStart && end >= start) {
+ o = old[oldStart];
+ v = vnodes[start];
+ if (o.key !== v.key)
+ break;
+ oldStart++, start++;
+ if (o !== v)
+ updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns);
+ }
+ while (oldEnd >= oldStart && end >= start) {
+ if (start === end)
+ break;
+ if (o.key !== ve.key || oe.key !== v.key)
+ break;
+ topSibling = getNextSibling(old, oldStart, nextSibling);
+ moveNodes(parent, oe, topSibling);
+ if (oe !== v)
+ updateNode(parent, oe, v, hooks, topSibling, ns);
+ if (++start <= --end)
+ moveNodes(parent, o, nextSibling);
+ if (o !== ve)
+ updateNode(parent, o, ve, hooks, nextSibling, ns);
+ if (ve.dom != null)
+ nextSibling = ve.dom;
+ oldStart++;
+ oldEnd--;
+ oe = old[oldEnd];
+ ve = vnodes[end];
+ o = old[oldStart];
+ v = vnodes[start];
+ }
+ while (oldEnd >= oldStart && end >= start) {
+ if (oe.key !== ve.key)
+ break;
+ if (oe !== ve)
+ updateNode(parent, oe, ve, hooks, nextSibling, ns);
+ if (ve.dom != null)
+ nextSibling = ve.dom;
+ oldEnd--, end--;
+ oe = old[oldEnd];
+ ve = vnodes[end];
+ }
+ if (start > end)
+ removeNodes(parent, old, oldStart, oldEnd + 1);
+ else if (oldStart > oldEnd)
+ createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns);
+ else {
+ var originalNextSibling = nextSibling, vnodesLength = end - start + 1, oldIndices = new Array(vnodesLength), li = 0, i = 0, pos = 2147483647, matched = 0, map, lisIndices;
+ for (i = 0;i < vnodesLength; i++)
+ oldIndices[i] = -1;
+ for (i = end;i >= start; i--) {
+ if (map == null)
+ map = getKeyMap(old, oldStart, oldEnd + 1);
+ ve = vnodes[i];
+ var oldIndex = map[ve.key];
+ if (oldIndex != null) {
+ pos = oldIndex < pos ? oldIndex : -1;
+ oldIndices[i - start] = oldIndex;
+ oe = old[oldIndex];
+ old[oldIndex] = null;
+ if (oe !== ve)
+ updateNode(parent, oe, ve, hooks, nextSibling, ns);
+ if (ve.dom != null)
+ nextSibling = ve.dom;
+ matched++;
+ }
+ }
+ nextSibling = originalNextSibling;
+ if (matched !== oldEnd - oldStart + 1)
+ removeNodes(parent, old, oldStart, oldEnd + 1);
+ if (matched === 0)
+ createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns);
+ else {
+ if (pos === -1) {
+ lisIndices = makeLisIndices(oldIndices);
+ li = lisIndices.length - 1;
+ for (i = end;i >= start; i--) {
+ v = vnodes[i];
+ if (oldIndices[i - start] === -1)
+ createNode(parent, v, hooks, ns, nextSibling);
+ else {
+ if (lisIndices[li] === i - start)
+ li--;
+ else
+ moveNodes(parent, v, nextSibling);
+ }
+ if (v.dom != null)
+ nextSibling = vnodes[i].dom;
+ }
+ } else {
+ for (i = end;i >= start; i--) {
+ v = vnodes[i];
+ if (oldIndices[i - start] === -1)
+ createNode(parent, v, hooks, ns, nextSibling);
+ if (v.dom != null)
+ nextSibling = vnodes[i].dom;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ function updateNode(parent, old, vnode, hooks, nextSibling, ns) {
+ var oldTag = old.tag, tag = vnode.tag;
+ if (oldTag === tag) {
+ vnode.state = old.state;
+ vnode.events = old.events;
+ if (shouldNotUpdate(vnode, old))
+ return;
+ if (typeof oldTag === "string") {
+ if (vnode.attrs != null) {
+ updateLifecycle(vnode.attrs, vnode, hooks);
+ }
+ switch (oldTag) {
+ case "#":
+ updateText(old, vnode);
+ break;
+ case "<":
+ updateHTML(parent, old, vnode, ns, nextSibling);
+ break;
+ case "[":
+ updateFragment(parent, old, vnode, hooks, nextSibling, ns);
+ break;
+ default:
+ updateElement(old, vnode, hooks, ns);
+ }
+ } else
+ updateComponent(parent, old, vnode, hooks, nextSibling, ns);
+ } else {
+ removeNode(parent, old);
+ createNode(parent, vnode, hooks, ns, nextSibling);
+ }
+ }
+ function updateText(old, vnode) {
+ if (old.children.toString() !== vnode.children.toString()) {
+ old.dom.nodeValue = vnode.children;
+ }
+ vnode.dom = old.dom;
+ }
+ function updateHTML(parent, old, vnode, ns, nextSibling) {
+ if (old.children !== vnode.children) {
+ removeHTML(parent, old);
+ createHTML(parent, vnode, ns, nextSibling);
+ } else {
+ vnode.dom = old.dom;
+ vnode.domSize = old.domSize;
+ vnode.instance = old.instance;
+ }
+ }
+ function updateFragment(parent, old, vnode, hooks, nextSibling, ns) {
+ updateNodes(parent, old.children, vnode.children, hooks, nextSibling, ns);
+ var domSize = 0, children = vnode.children;
+ vnode.dom = null;
+ if (children != null) {
+ for (var i = 0;i < children.length; i++) {
+ var child = children[i];
+ if (child != null && child.dom != null) {
+ if (vnode.dom == null)
+ vnode.dom = child.dom;
+ domSize += child.domSize || 1;
+ }
+ }
+ if (domSize !== 1)
+ vnode.domSize = domSize;
+ }
+ }
+ function updateElement(old, vnode, hooks, ns) {
+ var element = vnode.dom = old.dom;
+ ns = getNameSpace(vnode) || ns;
+ if (vnode.tag === "textarea") {
+ if (vnode.attrs == null)
+ vnode.attrs = {};
+ }
+ updateAttrs(vnode, old.attrs, vnode.attrs, ns);
+ if (!maybeSetContentEditable(vnode)) {
+ updateNodes(element, old.children, vnode.children, hooks, null, ns);
+ }
+ }
+ function updateComponent(parent, old, vnode, hooks, nextSibling, ns) {
+ vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode));
+ if (vnode.instance === vnode)
+ throw Error("A view cannot return the vnode it received as argument");
+ updateLifecycle(vnode.state, vnode, hooks);
+ if (vnode.attrs != null)
+ updateLifecycle(vnode.attrs, vnode, hooks);
+ if (vnode.instance != null) {
+ if (old.instance == null)
+ createNode(parent, vnode.instance, hooks, ns, nextSibling);
+ else
+ updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, ns);
+ vnode.dom = vnode.instance.dom;
+ vnode.domSize = vnode.instance.domSize;
+ } else if (old.instance != null) {
+ removeNode(parent, old.instance);
+ vnode.dom = undefined;
+ vnode.domSize = 0;
+ } else {
+ vnode.dom = old.dom;
+ vnode.domSize = old.domSize;
+ }
+ }
+ function getKeyMap(vnodes, start, end) {
+ var map = Object.create(null);
+ for (;start < end; start++) {
+ var vnode = vnodes[start];
+ if (vnode != null) {
+ var key = vnode.key;
+ if (key != null)
+ map[key] = start;
+ }
+ }
+ return map;
+ }
+ var lisTemp = [];
+ function makeLisIndices(a) {
+ var result = [0];
+ var u = 0, v = 0, i = 0;
+ var il = lisTemp.length = a.length;
+ for (var i = 0;i < il; i++)
+ lisTemp[i] = a[i];
+ for (var i = 0;i < il; ++i) {
+ if (a[i] === -1)
+ continue;
+ var j = result[result.length - 1];
+ if (a[j] < a[i]) {
+ lisTemp[i] = j;
+ result.push(i);
+ continue;
+ }
+ u = 0;
+ v = result.length - 1;
+ while (u < v) {
+ var c = (u >>> 1) + (v >>> 1) + (u & v & 1);
+ if (a[result[c]] < a[i]) {
+ u = c + 1;
+ } else {
+ v = c;
+ }
+ }
+ if (a[i] < a[result[u]]) {
+ if (u > 0)
+ lisTemp[i] = result[u - 1];
+ result[u] = i;
+ }
+ }
+ u = result.length;
+ v = result[u - 1];
+ while (u-- > 0) {
+ result[u] = v;
+ v = lisTemp[v];
+ }
+ lisTemp.length = 0;
+ return result;
+ }
+ function getNextSibling(vnodes, i, nextSibling) {
+ for (;i < vnodes.length; i++) {
+ if (vnodes[i] != null && vnodes[i].dom != null)
+ return vnodes[i].dom;
+ }
+ return nextSibling;
+ }
+ function moveNodes(parent, vnode, nextSibling) {
+ var frag = $doc.createDocumentFragment();
+ moveChildToFrag(parent, frag, vnode);
+ insertNode(parent, frag, nextSibling);
+ }
+ function moveChildToFrag(parent, frag, vnode) {
+ while (vnode.dom != null && vnode.dom.parentNode === parent) {
+ if (typeof vnode.tag !== "string") {
+ vnode = vnode.instance;
+ if (vnode != null)
+ continue;
+ } else if (vnode.tag === "<") {
+ for (var i = 0;i < vnode.instance.length; i++) {
+ frag.appendChild(vnode.instance[i]);
+ }
+ } else if (vnode.tag !== "[") {
+ frag.appendChild(vnode.dom);
+ } else if (vnode.children.length === 1) {
+ vnode = vnode.children[0];
+ if (vnode != null)
+ continue;
+ } else {
+ for (var i = 0;i < vnode.children.length; i++) {
+ var child = vnode.children[i];
+ if (child != null)
+ moveChildToFrag(parent, frag, child);
+ }
+ }
+ break;
+ }
+ }
+ function insertNode(parent, dom, nextSibling) {
+ if (nextSibling != null)
+ parent.insertBefore(dom, nextSibling);
+ else
+ parent.appendChild(dom);
+ }
+ function maybeSetContentEditable(vnode) {
+ if (vnode.attrs == null || vnode.attrs.contenteditable == null && vnode.attrs.contentEditable == null)
+ return false;
+ var children = vnode.children;
+ if (children != null && children.length === 1 && children[0].tag === "<") {
+ var content = children[0].children;
+ if (vnode.dom.innerHTML !== content)
+ vnode.dom.innerHTML = content;
+ } else if (children != null && children.length !== 0)
+ throw new Error("Child node of a contenteditable must be trusted.");
+ return true;
+ }
+ function removeNodes(parent, vnodes, start, end) {
+ for (var i = start;i < end; i++) {
+ var vnode = vnodes[i];
+ if (vnode != null)
+ removeNode(parent, vnode);
+ }
+ }
+ function removeNode(parent, vnode) {
+ var mask = 0;
+ var original = vnode.state;
+ var stateResult, attrsResult;
+ if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeremove === "function") {
+ var result = callHook.call(vnode.state.onbeforeremove, vnode);
+ if (result != null && typeof result.then === "function") {
+ mask = 1;
+ stateResult = result;
+ }
+ }
+ if (vnode.attrs && typeof vnode.attrs.onbeforeremove === "function") {
+ var result = callHook.call(vnode.attrs.onbeforeremove, vnode);
+ if (result != null && typeof result.then === "function") {
+ mask |= 2;
+ attrsResult = result;
+ }
+ }
+ checkState(vnode, original);
+ if (!mask) {
+ onremove(vnode);
+ removeChild(parent, vnode);
+ } else {
+ if (stateResult != null) {
+ var next = function() {
+ if (mask & 1) {
+ mask &= 2;
+ if (!mask)
+ reallyRemove();
+ }
+ };
+ stateResult.then(next, next);
+ }
+ if (attrsResult != null) {
+ var next = function() {
+ if (mask & 2) {
+ mask &= 1;
+ if (!mask)
+ reallyRemove();
+ }
+ };
+ attrsResult.then(next, next);
+ }
+ }
+ function reallyRemove() {
+ checkState(vnode, original);
+ onremove(vnode);
+ removeChild(parent, vnode);
+ }
+ }
+ function removeHTML(parent, vnode) {
+ for (var i = 0;i < vnode.instance.length; i++) {
+ parent.removeChild(vnode.instance[i]);
+ }
+ }
+ function removeChild(parent, vnode) {
+ while (vnode.dom != null && vnode.dom.parentNode === parent) {
+ if (typeof vnode.tag !== "string") {
+ vnode = vnode.instance;
+ if (vnode != null)
+ continue;
+ } else if (vnode.tag === "<") {
+ removeHTML(parent, vnode);
+ } else {
+ if (vnode.tag !== "[") {
+ parent.removeChild(vnode.dom);
+ if (!Array.isArray(vnode.children))
+ break;
+ }
+ if (vnode.children.length === 1) {
+ vnode = vnode.children[0];
+ if (vnode != null)
+ continue;
+ } else {
+ for (var i = 0;i < vnode.children.length; i++) {
+ var child = vnode.children[i];
+ if (child != null)
+ removeChild(parent, child);
+ }
+ }
+ }
+ break;
+ }
+ }
+ function onremove(vnode) {
+ if (typeof vnode.tag !== "string" && typeof vnode.state.onremove === "function")
+ callHook.call(vnode.state.onremove, vnode);
+ if (vnode.attrs && typeof vnode.attrs.onremove === "function")
+ callHook.call(vnode.attrs.onremove, vnode);
+ if (typeof vnode.tag !== "string") {
+ if (vnode.instance != null)
+ onremove(vnode.instance);
+ } else {
+ var children = vnode.children;
+ if (Array.isArray(children)) {
+ for (var i = 0;i < children.length; i++) {
+ var child = children[i];
+ if (child != null)
+ onremove(child);
+ }
+ }
+ }
+ }
+ function setAttrs(vnode, attrs, ns) {
+ if (vnode.tag === "input" && attrs.type != null)
+ vnode.dom.setAttribute("type", attrs.type);
+ var isFileInput = attrs != null && vnode.tag === "input" && attrs.type === "file";
+ for (var key in attrs) {
+ setAttr(vnode, key, null, attrs[key], ns, isFileInput);
+ }
+ }
+ function setAttr(vnode, key, old, value, ns, isFileInput) {
+ if (key === "key" || key === "is" || value == null || isLifecycleMethod(key) || old === value && !isFormAttribute(vnode, key) && typeof value !== "object" || key === "type" && vnode.tag === "input")
+ return;
+ if (key[0] === "o" && key[1] === "n")
+ return updateEvent(vnode, key, value);
+ if (key.slice(0, 6) === "xlink:")
+ vnode.dom.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(6), value);
+ else if (key === "style")
+ updateStyle(vnode.dom, old, value);
+ else if (hasPropertyKey(vnode, key, ns)) {
+ if (key === "value") {
+ if ((vnode.tag === "input" || vnode.tag === "textarea") && vnode.dom.value === "" + value && (isFileInput || vnode.dom === activeElement()))
+ return;
+ if (vnode.tag === "select" && old !== null && vnode.dom.value === "" + value)
+ return;
+ if (vnode.tag === "option" && old !== null && vnode.dom.value === "" + value)
+ return;
+ if (isFileInput && "" + value !== "") {
+ console.error("`value` is read-only on file inputs!");
+ return;
+ }
+ }
+ vnode.dom[key] = value;
+ } else {
+ if (typeof value === "boolean") {
+ if (value)
+ vnode.dom.setAttribute(key, "");
+ else
+ vnode.dom.removeAttribute(key);
+ } else
+ vnode.dom.setAttribute(key === "className" ? "class" : key, value);
+ }
+ }
+ function removeAttr(vnode, key, old, ns) {
+ if (key === "key" || key === "is" || old == null || isLifecycleMethod(key))
+ return;
+ if (key[0] === "o" && key[1] === "n")
+ updateEvent(vnode, key, undefined);
+ else if (key === "style")
+ updateStyle(vnode.dom, old, null);
+ else if (hasPropertyKey(vnode, key, ns) && key !== "className" && key !== "title" && !(key === "value" && (vnode.tag === "option" || vnode.tag === "select" && vnode.dom.selectedIndex === -1 && vnode.dom === activeElement())) && !(vnode.tag === "input" && key === "type")) {
+ vnode.dom[key] = null;
+ } else {
+ var nsLastIndex = key.indexOf(":");
+ if (nsLastIndex !== -1)
+ key = key.slice(nsLastIndex + 1);
+ if (old !== false)
+ vnode.dom.removeAttribute(key === "className" ? "class" : key);
+ }
+ }
+ function setLateSelectAttrs(vnode, attrs) {
+ if ("value" in attrs) {
+ if (attrs.value === null) {
+ if (vnode.dom.selectedIndex !== -1)
+ vnode.dom.value = null;
+ } else {
+ var normalized = "" + attrs.value;
+ if (vnode.dom.value !== normalized || vnode.dom.selectedIndex === -1) {
+ vnode.dom.value = normalized;
+ }
+ }
+ }
+ if ("selectedIndex" in attrs)
+ setAttr(vnode, "selectedIndex", null, attrs.selectedIndex, undefined);
+ }
+ function updateAttrs(vnode, old, attrs, ns) {
+ if (old && old === attrs) {
+ console.warn("Don't reuse attrs object, use new object for every redraw, this will throw in next major");
+ }
+ if (attrs != null) {
+ if (vnode.tag === "input" && attrs.type != null)
+ vnode.dom.setAttribute("type", attrs.type);
+ var isFileInput = vnode.tag === "input" && attrs.type === "file";
+ for (var key in attrs) {
+ setAttr(vnode, key, old && old[key], attrs[key], ns, isFileInput);
+ }
+ }
+ var val;
+ if (old != null) {
+ for (var key in old) {
+ if ((val = old[key]) != null && (attrs == null || attrs[key] == null)) {
+ removeAttr(vnode, key, val, ns);
+ }
+ }
+ }
+ }
+ function isFormAttribute(vnode, attr) {
+ return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === activeElement() || vnode.tag === "option" && vnode.dom.parentNode === $doc.activeElement;
+ }
+ function isLifecycleMethod(attr) {
+ return attr === "oninit" || attr === "oncreate" || attr === "onupdate" || attr === "onremove" || attr === "onbeforeremove" || attr === "onbeforeupdate";
+ }
+ function hasPropertyKey(vnode, key, ns) {
+ return ns === undefined && (vnode.tag.indexOf("-") > -1 || vnode.attrs != null && vnode.attrs.is || key !== "href" && key !== "list" && key !== "form" && key !== "width" && key !== "height") && key in vnode.dom;
+ }
+ var uppercaseRegex = /[A-Z]/g;
+ function toLowerCase(capital) {
+ return "-" + capital.toLowerCase();
+ }
+ function normalizeKey(key) {
+ return key[0] === "-" && key[1] === "-" ? key : key === "cssFloat" ? "float" : key.replace(uppercaseRegex, toLowerCase);
+ }
+ function updateStyle(element, old, style) {
+ if (old === style) {
+ } else if (style == null) {
+ element.style.cssText = "";
+ } else if (typeof style !== "object") {
+ element.style.cssText = style;
+ } else if (old == null || typeof old !== "object") {
+ element.style.cssText = "";
+ for (var key in style) {
+ var value = style[key];
+ if (value != null)
+ element.style.setProperty(normalizeKey(key), String(value));
+ }
+ } else {
+ for (var key in style) {
+ var value = style[key];
+ if (value != null && (value = String(value)) !== String(old[key])) {
+ element.style.setProperty(normalizeKey(key), value);
+ }
+ }
+ for (var key in old) {
+ if (old[key] != null && style[key] == null) {
+ element.style.removeProperty(normalizeKey(key));
+ }
+ }
+ }
+ }
+ function EventDict() {
+ this._ = currentRedraw;
+ }
+ EventDict.prototype = Object.create(null);
+ EventDict.prototype.handleEvent = function(ev) {
+ var handler = this["on" + ev.type];
+ var result;
+ if (typeof handler === "function")
+ result = handler.call(ev.currentTarget, ev);
+ else if (typeof handler.handleEvent === "function")
+ handler.handleEvent(ev);
+ if (this._ && ev.redraw !== false)
+ (0, this._)();
+ if (result === false) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ }
+ };
+ function updateEvent(vnode, key, value) {
+ if (vnode.events != null) {
+ vnode.events._ = currentRedraw;
+ if (vnode.events[key] === value)
+ return;
+ if (value != null && (typeof value === "function" || typeof value === "object")) {
+ if (vnode.events[key] == null)
+ vnode.dom.addEventListener(key.slice(2), vnode.events, false);
+ vnode.events[key] = value;
+ } else {
+ if (vnode.events[key] != null)
+ vnode.dom.removeEventListener(key.slice(2), vnode.events, false);
+ vnode.events[key] = undefined;
+ }
+ } else if (value != null && (typeof value === "function" || typeof value === "object")) {
+ vnode.events = new EventDict;
+ vnode.dom.addEventListener(key.slice(2), vnode.events, false);
+ vnode.events[key] = value;
+ }
+ }
+ function initLifecycle(source, vnode, hooks) {
+ if (typeof source.oninit === "function")
+ callHook.call(source.oninit, vnode);
+ if (typeof source.oncreate === "function")
+ hooks.push(callHook.bind(source.oncreate, vnode));
+ }
+ function updateLifecycle(source, vnode, hooks) {
+ if (typeof source.onupdate === "function")
+ hooks.push(callHook.bind(source.onupdate, vnode));
+ }
+ function shouldNotUpdate(vnode, old) {
+ do {
+ if (vnode.attrs != null && typeof vnode.attrs.onbeforeupdate === "function") {
+ var force = callHook.call(vnode.attrs.onbeforeupdate, vnode, old);
+ if (force !== undefined && !force)
+ break;
+ }
+ if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeupdate === "function") {
+ var force = callHook.call(vnode.state.onbeforeupdate, vnode, old);
+ if (force !== undefined && !force)
+ break;
+ }
+ return false;
+ } while (false);
+ vnode.dom = old.dom;
+ vnode.domSize = old.domSize;
+ vnode.instance = old.instance;
+ vnode.attrs = old.attrs;
+ vnode.children = old.children;
+ vnode.text = old.text;
+ return true;
+ }
+ var currentDOM;
+ return function(dom, vnodes, redraw) {
+ if (!dom)
+ throw new TypeError("DOM element being rendered to does not exist.");
+ if (currentDOM != null && dom.contains(currentDOM)) {
+ throw new TypeError("Node is currently being rendered to and thus is locked.");
+ }
+ var prevRedraw = currentRedraw;
+ var prevDOM = currentDOM;
+ var hooks = [];
+ var active = activeElement();
+ var namespace = dom.namespaceURI;
+ currentDOM = dom;
+ currentRedraw = typeof redraw === "function" ? redraw : undefined;
+ try {
+ if (dom.vnodes == null)
+ dom.textContent = "";
+ vnodes = Vnode.normalizeChildren(Array.isArray(vnodes) ? vnodes : [vnodes]);
+ updateNodes(dom, dom.vnodes, vnodes, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace);
+ dom.vnodes = vnodes;
+ if (active != null && activeElement() !== active && typeof active.focus === "function")
+ active.focus();
+ for (var i = 0;i < hooks.length; i++)
+ hooks[i]();
+ } finally {
+ currentRedraw = prevRedraw;
+ currentDOM = prevDOM;
+ }
+ };
+ };
+});
+
+// node_modules/mithril/render.js
+var require_render2 = __commonJS((exports, module) => {
+ module.exports = require_render()(typeof window !== "undefined" ? window : null);
+});
+
+// node_modules/mithril/api/mount-redraw.js
+var require_mount_redraw = __commonJS((exports, module) => {
+ var Vnode = require_vnode();
+ module.exports = function(render, schedule, console2) {
+ var subscriptions = [];
+ var pending = false;
+ var offset = -1;
+ function sync() {
+ for (offset = 0;offset < subscriptions.length; offset += 2) {
+ try {
+ render(subscriptions[offset], Vnode(subscriptions[offset + 1]), redraw);
+ } catch (e) {
+ console2.error(e);
+ }
+ }
+ offset = -1;
+ }
+ function redraw() {
+ if (!pending) {
+ pending = true;
+ schedule(function() {
+ pending = false;
+ sync();
+ });
+ }
+ }
+ redraw.sync = sync;
+ function mount(root, component) {
+ if (component != null && component.view == null && typeof component !== "function") {
+ throw new TypeError("m.mount expects a component, not a vnode.");
+ }
+ var index = subscriptions.indexOf(root);
+ if (index >= 0) {
+ subscriptions.splice(index, 2);
+ if (index <= offset)
+ offset -= 2;
+ render(root, []);
+ }
+ if (component != null) {
+ subscriptions.push(root, component);
+ render(root, Vnode(component), redraw);
+ }
+ }
+ return { mount, redraw };
+ };
+});
+
+// node_modules/mithril/mount-redraw.js
+var require_mount_redraw2 = __commonJS((exports, module) => {
+ var render = require_render2();
+ module.exports = require_mount_redraw()(render, typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : null, typeof console !== "undefined" ? console : null);
+});
+
+// node_modules/mithril/querystring/build.js
+var require_build = __commonJS((exports, module) => {
+ module.exports = function(object) {
+ if (Object.prototype.toString.call(object) !== "[object Object]")
+ return "";
+ var args = [];
+ for (var key in object) {
+ destructure(key, object[key]);
+ }
+ return args.join("&");
+ function destructure(key2, value) {
+ if (Array.isArray(value)) {
+ for (var i = 0;i < value.length; i++) {
+ destructure(key2 + "[" + i + "]", value[i]);
+ }
+ } else if (Object.prototype.toString.call(value) === "[object Object]") {
+ for (var i in value) {
+ destructure(key2 + "[" + i + "]", value[i]);
+ }
+ } else
+ args.push(encodeURIComponent(key2) + (value != null && value !== "" ? "=" + encodeURIComponent(value) : ""));
+ }
+ };
+});
+
+// node_modules/mithril/util/assign.js
+var require_assign = __commonJS((exports, module) => {
+ var hasOwn = require_hasOwn();
+ module.exports = Object.assign || function(target, source) {
+ for (var key in source) {
+ if (hasOwn.call(source, key))
+ target[key] = source[key];
+ }
+ };
+});
+
+// node_modules/mithril/pathname/build.js
+var require_build2 = __commonJS((exports, module) => {
+ var buildQueryString = require_build();
+ var assign = require_assign();
+ module.exports = function(template, params) {
+ if (/:([^\/\.-]+)(\.{3})?:/.test(template)) {
+ throw new SyntaxError("Template parameter names must be separated by either a '/', '-', or '.'.");
+ }
+ if (params == null)
+ return template;
+ var queryIndex = template.indexOf("?");
+ var hashIndex = template.indexOf("#");
+ var queryEnd = hashIndex < 0 ? template.length : hashIndex;
+ var pathEnd = queryIndex < 0 ? queryEnd : queryIndex;
+ var path = template.slice(0, pathEnd);
+ var query = {};
+ assign(query, params);
+ var resolved = path.replace(/:([^\/\.-]+)(\.{3})?/g, function(m, key, variadic) {
+ delete query[key];
+ if (params[key] == null)
+ return m;
+ return variadic ? params[key] : encodeURIComponent(String(params[key]));
+ });
+ var newQueryIndex = resolved.indexOf("?");
+ var newHashIndex = resolved.indexOf("#");
+ var newQueryEnd = newHashIndex < 0 ? resolved.length : newHashIndex;
+ var newPathEnd = newQueryIndex < 0 ? newQueryEnd : newQueryIndex;
+ var result = resolved.slice(0, newPathEnd);
+ if (queryIndex >= 0)
+ result += template.slice(queryIndex, queryEnd);
+ if (newQueryIndex >= 0)
+ result += (queryIndex < 0 ? "?" : "&") + resolved.slice(newQueryIndex, newQueryEnd);
+ var querystring = buildQueryString(query);
+ if (querystring)
+ result += (queryIndex < 0 && newQueryIndex < 0 ? "?" : "&") + querystring;
+ if (hashIndex >= 0)
+ result += template.slice(hashIndex);
+ if (newHashIndex >= 0)
+ result += (hashIndex < 0 ? "" : "&") + resolved.slice(newHashIndex);
+ return result;
+ };
+});
+
+// node_modules/mithril/request/request.js
+var require_request = __commonJS((exports, module) => {
+ var buildPathname = require_build2();
+ var hasOwn = require_hasOwn();
+ module.exports = function($window, Promise2, oncompletion) {
+ var callbackCount = 0;
+ function PromiseProxy(executor) {
+ return new Promise2(executor);
+ }
+ PromiseProxy.prototype = Promise2.prototype;
+ PromiseProxy.__proto__ = Promise2;
+ function makeRequest(factory) {
+ return function(url, args) {
+ if (typeof url !== "string") {
+ args = url;
+ url = url.url;
+ } else if (args == null)
+ args = {};
+ var promise = new Promise2(function(resolve, reject) {
+ factory(buildPathname(url, args.params), args, function(data) {
+ if (typeof args.type === "function") {
+ if (Array.isArray(data)) {
+ for (var i = 0;i < data.length; i++) {
+ data[i] = new args.type(data[i]);
+ }
+ } else
+ data = new args.type(data);
+ }
+ resolve(data);
+ }, reject);
+ });
+ if (args.background === true)
+ return promise;
+ var count = 0;
+ function complete() {
+ if (--count === 0 && typeof oncompletion === "function")
+ oncompletion();
+ }
+ return wrap(promise);
+ function wrap(promise2) {
+ var then = promise2.then;
+ promise2.constructor = PromiseProxy;
+ promise2.then = function() {
+ count++;
+ var next = then.apply(promise2, arguments);
+ next.then(complete, function(e) {
+ complete();
+ if (count === 0)
+ throw e;
+ });
+ return wrap(next);
+ };
+ return promise2;
+ }
+ };
+ }
+ function hasHeader(args, name) {
+ for (var key in args.headers) {
+ if (hasOwn.call(args.headers, key) && key.toLowerCase() === name)
+ return true;
+ }
+ return false;
+ }
+ return {
+ request: makeRequest(function(url, args, resolve, reject) {
+ var method = args.method != null ? args.method.toUpperCase() : "GET";
+ var body = args.body;
+ var assumeJSON = (args.serialize == null || args.serialize === JSON.serialize) && !(body instanceof $window.FormData || body instanceof $window.URLSearchParams);
+ var responseType = args.responseType || (typeof args.extract === "function" ? "" : "json");
+ var xhr = new $window.XMLHttpRequest, aborted = false, isTimeout = false;
+ var original = xhr, replacedAbort;
+ var abort = xhr.abort;
+ xhr.abort = function() {
+ aborted = true;
+ abort.call(this);
+ };
+ xhr.open(method, url, args.async !== false, typeof args.user === "string" ? args.user : undefined, typeof args.password === "string" ? args.password : undefined);
+ if (assumeJSON && body != null && !hasHeader(args, "content-type")) {
+ xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
+ }
+ if (typeof args.deserialize !== "function" && !hasHeader(args, "accept")) {
+ xhr.setRequestHeader("Accept", "application/json, text/*");
+ }
+ if (args.withCredentials)
+ xhr.withCredentials = args.withCredentials;
+ if (args.timeout)
+ xhr.timeout = args.timeout;
+ xhr.responseType = responseType;
+ for (var key in args.headers) {
+ if (hasOwn.call(args.headers, key)) {
+ xhr.setRequestHeader(key, args.headers[key]);
+ }
+ }
+ xhr.onreadystatechange = function(ev) {
+ if (aborted)
+ return;
+ if (ev.target.readyState === 4) {
+ try {
+ var success = ev.target.status >= 200 && ev.target.status < 300 || ev.target.status === 304 || /^file:\/\//i.test(url);
+ var response = ev.target.response, message;
+ if (responseType === "json") {
+ if (!ev.target.responseType && typeof args.extract !== "function") {
+ try {
+ response = JSON.parse(ev.target.responseText);
+ } catch (e) {
+ response = null;
+ }
+ }
+ } else if (!responseType || responseType === "text") {
+ if (response == null)
+ response = ev.target.responseText;
+ }
+ if (typeof args.extract === "function") {
+ response = args.extract(ev.target, args);
+ success = true;
+ } else if (typeof args.deserialize === "function") {
+ response = args.deserialize(response);
+ }
+ if (success)
+ resolve(response);
+ else {
+ var completeErrorResponse = function() {
+ try {
+ message = ev.target.responseText;
+ } catch (e) {
+ message = response;
+ }
+ var error = new Error(message);
+ error.code = ev.target.status;
+ error.response = response;
+ reject(error);
+ };
+ if (xhr.status === 0) {
+ setTimeout(function() {
+ if (isTimeout)
+ return;
+ completeErrorResponse();
+ });
+ } else
+ completeErrorResponse();
+ }
+ } catch (e) {
+ reject(e);
+ }
+ }
+ };
+ xhr.ontimeout = function(ev) {
+ isTimeout = true;
+ var error = new Error("Request timed out");
+ error.code = ev.target.status;
+ reject(error);
+ };
+ if (typeof args.config === "function") {
+ xhr = args.config(xhr, args, url) || xhr;
+ if (xhr !== original) {
+ replacedAbort = xhr.abort;
+ xhr.abort = function() {
+ aborted = true;
+ replacedAbort.call(this);
+ };
+ }
+ }
+ if (body == null)
+ xhr.send();
+ else if (typeof args.serialize === "function")
+ xhr.send(args.serialize(body));
+ else if (body instanceof $window.FormData || body instanceof $window.URLSearchParams)
+ xhr.send(body);
+ else
+ xhr.send(JSON.stringify(body));
+ }),
+ jsonp: makeRequest(function(url, args, resolve, reject) {
+ var callbackName = args.callbackName || "_mithril_" + Math.round(Math.random() * 10000000000000000) + "_" + callbackCount++;
+ var script = $window.document.createElement("script");
+ $window[callbackName] = function(data) {
+ delete $window[callbackName];
+ script.parentNode.removeChild(script);
+ resolve(data);
+ };
+ script.onerror = function() {
+ delete $window[callbackName];
+ script.parentNode.removeChild(script);
+ reject(new Error("JSONP request failed"));
+ };
+ script.src = url + (url.indexOf("?") < 0 ? "?" : "&") + encodeURIComponent(args.callbackKey || "callback") + "=" + encodeURIComponent(callbackName);
+ $window.document.documentElement.appendChild(script);
+ })
+ };
+ };
+});
+
+// node_modules/mithril/request.js
+var require_request2 = __commonJS((exports, module) => {
+ var PromisePolyfill = require_promise();
+ var mountRedraw = require_mount_redraw2();
+ module.exports = require_request()(typeof window !== "undefined" ? window : null, PromisePolyfill, mountRedraw.redraw);
+});
+
+// node_modules/mithril/querystring/parse.js
+var require_parse = __commonJS((exports, module) => {
+ var decodeURIComponentSave = function(str) {
+ try {
+ return decodeURIComponent(str);
+ } catch (err) {
+ return str;
+ }
+ };
+ module.exports = function(string) {
+ if (string === "" || string == null)
+ return {};
+ if (string.charAt(0) === "?")
+ string = string.slice(1);
+ var entries = string.split("&"), counters = {}, data = {};
+ for (var i = 0;i < entries.length; i++) {
+ var entry = entries[i].split("=");
+ var key = decodeURIComponentSave(entry[0]);
+ var value = entry.length === 2 ? decodeURIComponentSave(entry[1]) : "";
+ if (value === "true")
+ value = true;
+ else if (value === "false")
+ value = false;
+ var levels = key.split(/\]\[?|\[/);
+ var cursor = data;
+ if (key.indexOf("[") > -1)
+ levels.pop();
+ for (var j = 0;j < levels.length; j++) {
+ var level = levels[j], nextLevel = levels[j + 1];
+ var isNumber = nextLevel == "" || !isNaN(parseInt(nextLevel, 10));
+ if (level === "") {
+ var key = levels.slice(0, j).join();
+ if (counters[key] == null) {
+ counters[key] = Array.isArray(cursor) ? cursor.length : 0;
+ }
+ level = counters[key]++;
+ } else if (level === "__proto__")
+ break;
+ if (j === levels.length - 1)
+ cursor[level] = value;
+ else {
+ var desc = Object.getOwnPropertyDescriptor(cursor, level);
+ if (desc != null)
+ desc = desc.value;
+ if (desc == null)
+ cursor[level] = desc = isNumber ? [] : {};
+ cursor = desc;
+ }
+ }
+ }
+ return data;
+ };
+});
+
+// node_modules/mithril/pathname/parse.js
+var require_parse2 = __commonJS((exports, module) => {
+ var parseQueryString = require_parse();
+ module.exports = function(url) {
+ var queryIndex = url.indexOf("?");
+ var hashIndex = url.indexOf("#");
+ var queryEnd = hashIndex < 0 ? url.length : hashIndex;
+ var pathEnd = queryIndex < 0 ? queryEnd : queryIndex;
+ var path = url.slice(0, pathEnd).replace(/\/{2,}/g, "/");
+ if (!path)
+ path = "/";
+ else {
+ if (path[0] !== "/")
+ path = "/" + path;
+ if (path.length > 1 && path[path.length - 1] === "/")
+ path = path.slice(0, -1);
+ }
+ return {
+ path,
+ params: queryIndex < 0 ? {} : parseQueryString(url.slice(queryIndex + 1, queryEnd))
+ };
+ };
+});
+
+// node_modules/mithril/pathname/compileTemplate.js
+var require_compileTemplate = __commonJS((exports, module) => {
+ var parsePathname = require_parse2();
+ module.exports = function(template) {
+ var templateData = parsePathname(template);
+ var templateKeys = Object.keys(templateData.params);
+ var keys = [];
+ var regexp = new RegExp("^" + templateData.path.replace(/:([^\/.-]+)(\.{3}|\.(?!\.)|-)?|[\\^$*+.()|\[\]{}]/g, function(m, key, extra) {
+ if (key == null)
+ return "\\" + m;
+ keys.push({ k: key, r: extra === "..." });
+ if (extra === "...")
+ return "(.*)";
+ if (extra === ".")
+ return "([^/]+)\\.";
+ return "([^/]+)" + (extra || "");
+ }) + "$");
+ return function(data) {
+ for (var i = 0;i < templateKeys.length; i++) {
+ if (templateData.params[templateKeys[i]] !== data.params[templateKeys[i]])
+ return false;
+ }
+ if (!keys.length)
+ return regexp.test(data.path);
+ var values = regexp.exec(data.path);
+ if (values == null)
+ return false;
+ for (var i = 0;i < keys.length; i++) {
+ data.params[keys[i].k] = keys[i].r ? values[i + 1] : decodeURIComponent(values[i + 1]);
+ }
+ return true;
+ };
+ };
+});
+
+// node_modules/mithril/util/censor.js
+var require_censor = __commonJS((exports, module) => {
+ var hasOwn = require_hasOwn();
+ var magic = new RegExp("^(?:key|oninit|oncreate|onbeforeupdate|onupdate|onbeforeremove|onremove)$");
+ module.exports = function(attrs, extras) {
+ var result = {};
+ if (extras != null) {
+ for (var key in attrs) {
+ if (hasOwn.call(attrs, key) && !magic.test(key) && extras.indexOf(key) < 0) {
+ result[key] = attrs[key];
+ }
+ }
+ } else {
+ for (var key in attrs) {
+ if (hasOwn.call(attrs, key) && !magic.test(key)) {
+ result[key] = attrs[key];
+ }
+ }
+ }
+ return result;
+ };
+});
+
+// node_modules/mithril/api/router.js
+var require_router = __commonJS((exports, module) => {
+ var decodeURIComponentSave = function(component) {
+ try {
+ return decodeURIComponent(component);
+ } catch (e) {
+ return component;
+ }
+ };
+ var Vnode = require_vnode();
+ var m = require_hyperscript();
+ var Promise2 = require_promise();
+ var buildPathname = require_build2();
+ var parsePathname = require_parse2();
+ var compileTemplate = require_compileTemplate();
+ var assign = require_assign();
+ var censor = require_censor();
+ var sentinel = {};
+ module.exports = function($window, mountRedraw) {
+ var callAsync = $window == null ? null : typeof $window.setImmediate === "function" ? $window.setImmediate : $window.setTimeout;
+ var p = Promise2.resolve();
+ var scheduled = false;
+ var ready = false;
+ var state = 0;
+ var compiled, fallbackRoute;
+ var currentResolver = sentinel, component, attrs, currentPath, lastUpdate;
+ var RouterRoot = {
+ onbeforeupdate: function() {
+ state = state ? 2 : 1;
+ return !(!state || sentinel === currentResolver);
+ },
+ onremove: function() {
+ $window.removeEventListener("popstate", fireAsync, false);
+ $window.removeEventListener("hashchange", resolveRoute, false);
+ },
+ view: function() {
+ if (!state || sentinel === currentResolver)
+ return;
+ var vnode = [Vnode(component, attrs.key, attrs)];
+ if (currentResolver)
+ vnode = currentResolver.render(vnode[0]);
+ return vnode;
+ }
+ };
+ var SKIP = route.SKIP = {};
+ function resolveRoute() {
+ scheduled = false;
+ var prefix = $window.location.hash;
+ if (route.prefix[0] !== "#") {
+ prefix = $window.location.search + prefix;
+ if (route.prefix[0] !== "?") {
+ prefix = $window.location.pathname + prefix;
+ if (prefix[0] !== "/")
+ prefix = "/" + prefix;
+ }
+ }
+ var path = prefix.concat().replace(/(?:%[a-f89][a-f0-9])+/gim, decodeURIComponentSave).slice(route.prefix.length);
+ var data = parsePathname(path);
+ assign(data.params, $window.history.state);
+ function reject(e) {
+ console.error(e);
+ setPath(fallbackRoute, null, { replace: true });
+ }
+ loop(0);
+ function loop(i) {
+ for (;i < compiled.length; i++) {
+ if (compiled[i].check(data)) {
+ var payload = compiled[i].component;
+ var matchedRoute = compiled[i].route;
+ var localComp = payload;
+ var update = lastUpdate = function(comp) {
+ if (update !== lastUpdate)
+ return;
+ if (comp === SKIP)
+ return loop(i + 1);
+ component = comp != null && (typeof comp.view === "function" || typeof comp === "function") ? comp : "div";
+ attrs = data.params, currentPath = path, lastUpdate = null;
+ currentResolver = payload.render ? payload : null;
+ if (state === 2)
+ mountRedraw.redraw();
+ else {
+ state = 2;
+ mountRedraw.redraw.sync();
+ }
+ };
+ if (payload.view || typeof payload === "function") {
+ payload = {};
+ update(localComp);
+ } else if (payload.onmatch) {
+ p.then(function() {
+ return payload.onmatch(data.params, path, matchedRoute);
+ }).then(update, path === fallbackRoute ? null : reject);
+ } else
+ update("div");
+ return;
+ }
+ }
+ if (path === fallbackRoute) {
+ throw new Error("Could not resolve default route " + fallbackRoute + ".");
+ }
+ setPath(fallbackRoute, null, { replace: true });
+ }
+ }
+ function fireAsync() {
+ if (!scheduled) {
+ scheduled = true;
+ callAsync(resolveRoute);
+ }
+ }
+ function setPath(path, data, options) {
+ path = buildPathname(path, data);
+ if (ready) {
+ fireAsync();
+ var state2 = options ? options.state : null;
+ var title = options ? options.title : null;
+ if (options && options.replace)
+ $window.history.replaceState(state2, title, route.prefix + path);
+ else
+ $window.history.pushState(state2, title, route.prefix + path);
+ } else {
+ $window.location.href = route.prefix + path;
+ }
+ }
+ function route(root, defaultRoute, routes) {
+ if (!root)
+ throw new TypeError("DOM element being rendered to does not exist.");
+ compiled = Object.keys(routes).map(function(route2) {
+ if (route2[0] !== "/")
+ throw new SyntaxError("Routes must start with a '/'.");
+ if (/:([^\/\.-]+)(\.{3})?:/.test(route2)) {
+ throw new SyntaxError("Route parameter names must be separated with either '/', '.', or '-'.");
+ }
+ return {
+ route: route2,
+ component: routes[route2],
+ check: compileTemplate(route2)
+ };
+ });
+ fallbackRoute = defaultRoute;
+ if (defaultRoute != null) {
+ var defaultData = parsePathname(defaultRoute);
+ if (!compiled.some(function(i) {
+ return i.check(defaultData);
+ })) {
+ throw new ReferenceError("Default route doesn't match any known routes.");
+ }
+ }
+ if (typeof $window.history.pushState === "function") {
+ $window.addEventListener("popstate", fireAsync, false);
+ } else if (route.prefix[0] === "#") {
+ $window.addEventListener("hashchange", resolveRoute, false);
+ }
+ ready = true;
+ mountRedraw.mount(root, RouterRoot);
+ resolveRoute();
+ }
+ route.set = function(path, data, options) {
+ if (lastUpdate != null) {
+ options = options || {};
+ options.replace = true;
+ }
+ lastUpdate = null;
+ setPath(path, data, options);
+ };
+ route.get = function() {
+ return currentPath;
+ };
+ route.prefix = "#!";
+ route.Link = {
+ view: function(vnode) {
+ var child = m(vnode.attrs.selector || "a", censor(vnode.attrs, ["options", "params", "selector", "onclick"]), vnode.children);
+ var options, onclick, href;
+ if (child.attrs.disabled = Boolean(child.attrs.disabled)) {
+ child.attrs.href = null;
+ child.attrs["aria-disabled"] = "true";
+ } else {
+ options = vnode.attrs.options;
+ onclick = vnode.attrs.onclick;
+ href = buildPathname(child.attrs.href, vnode.attrs.params);
+ child.attrs.href = route.prefix + href;
+ child.attrs.onclick = function(e) {
+ var result;
+ if (typeof onclick === "function") {
+ result = onclick.call(e.currentTarget, e);
+ } else if (onclick == null || typeof onclick !== "object") {
+ } else if (typeof onclick.handleEvent === "function") {
+ onclick.handleEvent(e);
+ }
+ if (result !== false && !e.defaultPrevented && (e.button === 0 || e.which === 0 || e.which === 1) && (!e.currentTarget.target || e.currentTarget.target === "_self") && !e.ctrlKey && !e.metaKey && !e.shiftKey && !e.altKey) {
+ e.preventDefault();
+ e.redraw = false;
+ route.set(href, null, options);
+ }
+ };
+ }
+ return child;
+ }
+ };
+ route.param = function(key) {
+ return attrs && key != null ? attrs[key] : attrs;
+ };
+ return route;
+ };
+});
+
+// node_modules/mithril/route.js
+var require_route = __commonJS((exports, module) => {
+ var mountRedraw = require_mount_redraw2();
+ module.exports = require_router()(typeof window !== "undefined" ? window : null, mountRedraw);
+});
+
+// node_modules/mithril/index.js
+var require_mithril = __commonJS((exports, module) => {
+ var hyperscript = require_hyperscript2();
+ var request = require_request2();
+ var mountRedraw = require_mount_redraw2();
+ var m = function m() {
+ return hyperscript.apply(this, arguments);
+ };
+ m.m = hyperscript;
+ m.trust = hyperscript.trust;
+ m.fragment = hyperscript.fragment;
+ m.Fragment = "[";
+ m.mount = mountRedraw.mount;
+ m.route = require_route();
+ m.render = require_render2();
+ m.redraw = mountRedraw.redraw;
+ m.request = request.request;
+ m.jsonp = request.jsonp;
+ m.parseQueryString = require_parse();
+ m.buildQueryString = require_build();
+ m.parsePathname = require_parse2();
+ m.buildPathname = require_build2();
+ m.vnode = require_vnode();
+ m.PromisePolyfill = require_polyfill();
+ m.censor = require_censor();
+ module.exports = m;
+});
+
+// src/index.ts
+var import_mithril = __toESM(require_mithril(), 1);
+var App = {
+ view: function() {
+ return import_mithril.default("body", [
+ import_mithril.default("div", "Hello!")
+ ]);
+ }
+};
+import_mithril.default.mount(document.body, App);
diff --git a/frontend/src/components/UserList.ts b/frontend/src/components/UserList.ts
new file mode 100644
index 0000000..b46a122
--- /dev/null
+++ b/frontend/src/components/UserList.ts
@@ -0,0 +1,18 @@
+import m from 'mithril';
+import User from '../models/User';
+
+const users: User[] = [
+ new User('U1'),
+ new User('U2'),
+ new User('U3')
+];
+
+export default const UserList = {
+ getList: function () {
+ return users.map(u => m('li', u.getUsername()));
+ },
+
+ view: function () {
+ return m('li', { id: 'UserList' }, this.getList());
+ }
+};
diff --git a/frontend/src/index.ts b/frontend/src/index.ts
new file mode 100644
index 0000000..0d9f724
--- /dev/null
+++ b/frontend/src/index.ts
@@ -0,0 +1,13 @@
+import m from 'mithril';
+import UserList from './components/UserList';
+
+const App = {
+ view: function() {
+ return m('body', [
+ UserList
+ ]);
+ }
+}
+
+//@ts-ignore This will be rendered and run on the DOM of a web page
+m.mount(document.body, App);
diff --git a/frontend/src/models/User.ts b/frontend/src/models/User.ts
new file mode 100644
index 0000000..d891e09
--- /dev/null
+++ b/frontend/src/models/User.ts
@@ -0,0 +1,12 @@
+export default class User {
+ private username: string;
+
+ public constructor(username: string) {
+ this.username = username;
+ }
+
+ public getUsername(): string {
+ return this.username;
+ }
+}
+
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
new file mode 100644
index 0000000..dcd8fc5
--- /dev/null
+++ b/frontend/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "compilerOptions": {
+ "lib": ["ESNext"],
+ "target": "ESNext",
+ "module": "ESNext",
+ "moduleDetection": "force",
+ "jsx": "react-jsx",
+ "allowJs": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "noEmit": true,
+
+ /* Linting */
+ "skipLibCheck": true,
+ "strict": true,
+ "noFallthroughCasesInSwitch": true,
+ "forceConsistentCasingInFileNames": true
+ }
+}