From 19297cb6c6ab99bb83f4b042fef72cc6441d9ce0 Mon Sep 17 00:00:00 2001 From: osmarks Date: Tue, 16 Feb 2021 14:26:01 +0000 Subject: [PATCH] search, page parsing, better cmark abstraction --- .gitignore | 5 +- package-lock.json | 135 +++++++++++++++++++++++ src/client.js | 97 +++++++++++++++++ src/domain.nim | 178 +++++++++++++++++++++--------- src/md.nim | 251 +++++++++++++++++++++++++++++++++---------- src/minoteaur.nim | 72 +++++++++---- src/style.sass | 38 +++++-- src/util.nim | 63 +++++++++++ static/client.js | 2 + static/client.js.map | 7 ++ static/style.css | 2 +- static/style.css.map | 2 +- watch-css.sh | 2 +- 13 files changed, 717 insertions(+), 137 deletions(-) create mode 100644 package-lock.json create mode 100644 src/client.js create mode 100644 src/util.nim create mode 100644 static/client.js create mode 100644 static/client.js.map diff --git a/.gitignore b/.gitignore index 457be7f..17981cc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ minoteaur.sqlite3 dump.sql -minoteaur \ No newline at end of file +minoteaur +node_modules +*.fossil +dump.sql \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..dbae0fe --- /dev/null +++ b/package-lock.json @@ -0,0 +1,135 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "esbuild": { + "version": "0.8.39", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.8.39.tgz", + "integrity": "sha512-/do5H74a5ChyeKRWfkDh3EpICXpsz6dWTtFFbotb7BlIHvWqnRrZYDb8IBubOHdEtKzuiksilRO19aBtp3/HHQ==" + }, + "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==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.1.tgz", + "integrity": "sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw==", + "optional": true + }, + "glob-parent": { + "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==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "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==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "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==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "mithril": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mithril/-/mithril-2.0.4.tgz", + "integrity": "sha512-mgw+DMZlhMS4PpprF6dl7ZoeZq5GGcAuWnrg5e12MvaGauc4jzWsDZtVGRCktsiQczOEUr2K5teKbE5k44RlOg==" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "sass": { + "version": "1.32.6", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.6.tgz", + "integrity": "sha512-1bcDHDcSqeFtMr0JXI3xc/CXX6c4p0wHHivJdru8W7waM7a1WjKMm4m/Z5sY7CbVw4Whi2Chpcw6DFfSWwGLzQ==", + "requires": { + "chokidar": ">=2.0.0 <4.0.0" + } + }, + "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==", + "requires": { + "is-number": "^7.0.0" + } + } + } +} diff --git a/src/client.js b/src/client.js new file mode 100644 index 0000000..1f2c955 --- /dev/null +++ b/src/client.js @@ -0,0 +1,97 @@ +import m from "mithril" + +const searchButton = document.querySelector("nav .search") +const mountpoint = document.createElement("div") +document.querySelector("main").insertBefore(mountpoint, document.querySelector(".header")) + +const state = { + showingSearchDialog: false, + searchResults: [], + searchError: null, + searchQuery: "" +} + +const lowercaseFirst = ([first, ...rest]) => first.toLowerCase() + rest.join("") +const uppercaseFirst = ([first, ...rest]) => first.toUpperCase() + rest.join("") +const pageToSlug = page => page.split(/[ _]/).map(lowercaseFirst).join("_") +const slugToPage = slug => slug.split(/[ _]/).map(uppercaseFirst).join(" ") + +const urlForPage = (page, subpage) => { + let p = `/${encodeURIComponent(pageToSlug(page))}` + if (subpage) { p += "/" + subpage } + return p +} + +const handleHTTPError = e => { + if (e.code === 0) { return } + let x = `Server error ${e.code}` + if (e.message) { x += " " + e.message } + alert(x) +} + +const onsearch = ev => { + const query = ev.target.value + state.searchQuery = query + m.request({ + url: "/api/search", + params: { q: query } + }).then(x => { + if (typeof x === "string") { // SQLite syntax error + console.log("ERR", x) + state.searchError = x + } else { + state.searchResults = x + state.searchError = null + } + }, e => handleHTTPError) +} + +const currentPage = slugToPage(decodeURIComponent(/^\/([^/]+)/.exec(location.pathname)[1]).replace(/\+/g, " ")) + +const searchKeyHandler = ev => { + if (ev.keyCode === 13) { // enter key + // not very useful to just navigate to the same page + const otherResults = state.searchResults.filter(r => r.page !== currentPage) + if (otherResults[0]) { location.href = urlForPage(otherResults[0].page) } + } +} + +const SearchDialog = { + view: () => m(".dialog.search", [ + m("h1", "Search"), + m("input[type=search]", { placeholder: "Query", oninput: onsearch, onkeydown: searchKeyHandler, value: state.searchQuery, oncreate: ({ dom }) => dom.focus() }), + state.searchError && m(".error", state.searchError), + m("ul", state.searchResults.map(x => m("li", [ + m(".flex-space", [ m("a.wikilink", { href: urlForPage(x.page) }, x.page), m("", x.rank.toFixed(3)) ]), + m("", x.snippet.map(s => s[0] ? m("span.highlight", s[1]) : s[1])) + ]))) + ]) +} + +const App = { + view: () => m("", state.showingSearchDialog ? m(SearchDialog) : null) +} + +searchButton.addEventListener("click", e => { + state.showingSearchDialog = !state.showingSearchDialog + e.preventDefault() + m.redraw() +}) + +document.body.addEventListener("keydown", e => { + if (e.target === document.body) { // maybe use alt instead? or right shift or something - this just detects unfocused keypresses + if (e.key === "e") { + location.pathname = urlForPage(currentPage, "edit") + } else if (e.key === "v") { + location.pathname = urlForPage(currentPage) + } else if (e.key === "r") { + location.pathname = urlForPage(currentPage, "revisions") + } else if (e.key === "/") { + state.showingSearchDialog = !state.showingSearchDialog + e.preventDefault() + m.redraw() + } + } +}) + +m.mount(mountpoint, App) \ No newline at end of file diff --git a/src/domain.nim b/src/domain.nim index c8531a0..d519c9b 100644 --- a/src/domain.nim +++ b/src/domain.nim @@ -2,8 +2,8 @@ import tiny_sqlite import logging import options import times -import zstd/compress -import zstd/decompress +import zstd/compress as zstd_compress +import zstd/decompress as zstd_decompress import sequtils import strutils except splitWhitespace import json @@ -11,45 +11,75 @@ import std/jsonutils import nimlevenshtein import sugar import unicode +import math -func timeToTimestamp*(t: Time): int64 = toUnix(t) * 1000 + (nanosecond(t) div 1000000) -func timestampToTime*(ts: int64): Time = initTime(ts div 1000, (ts mod 1000) * 1000000) -func timestampToStr*(t: Time): string = intToStr(int(timeToTimestamp(t))) - -# store time as milliseconds -proc toDbValue(t: Time): DbValue = DbValue(kind: sqliteInteger, intVal: timeToTimestamp(t)) -proc fromDbValue(value: DbValue, T: typedesc[Time]): Time = timestampToTime(value.intVal) +import util +from ./md import parsePage let migrations = @[ - """CREATE TABLE pages ( - page TEXT NOT NULL PRIMARY KEY, - updated INTEGER NOT NULL, - created INTEGER NOT NULL - ); - CREATE TABLE revisions ( - page TEXT NOT NULL REFERENCES pages(page), - timestamp INTEGER NOT NULL, - meta TEXT NOT NULL, - fullData BLOB - );""" + #[ + `pages` stores the content of all pages, as well as when they were last updated and created - this is all the information needed to render the current version of a page + It's mildly inefficient space-wise to store the latest content here AND in the revisions table (in compressed form), but dealing with this better would probably require complex logic elsewhere + which I don't think is worth it - I anticipate that media files will be much bigger, and probably significant amounts of old revisions (it would be worth investigating storing compact diffs). + + `revisions` stores all changes to a page, with metadata as JSON (messagepack is generally better, but SQLite can only query JSON) and optionally a separate blob storing larger associated data + (currently, the entire page content, zstd-compressed) + + rowids (INTEGER PRIMARY KEY) are explicitly extant here due to FTS external content requiring them to be stable to work but are not to be used much. + ]# + """ +CREATE TABLE pages ( + uid INTEGER PRIMARY KEY, + page TEXT NOT NULL UNIQUE, + updated INTEGER NOT NULL, + created INTEGER NOT NULL, + content TEXT NOT NULL +); +CREATE TABLE revisions ( + uid INTEGER PRIMARY KEY, + page TEXT NOT NULL REFERENCES pages(page), + timestamp INTEGER NOT NULL, + meta TEXT NOT NULL, + fullData BLOB +); + """, + """ +CREATE VIRTUAL TABLE pages_fts USING fts5 ( + page, content, + tokenize='porter unicode61 remove_diacritics 2', + content=pages, content_rowid=uid +); + """, + """ +CREATE TABLE links ( + uid INTEGER PRIMARY KEY, + from TEXT NOT NULL, + to TEXT NOT NULL, + linkText TEXT NOT NULL, + context TEXT NOT NULL +); + """ ] type - Encoding = enum - encPlain = 0, encZstd = 1 - RevisionType = enum - rtNewContent = 0 - RevisionMeta = object - case typ*: RevisionType - of rtNewContent: + Encoding* {.pure} = enum + Plain = 0, Zstd = 1 + RevisionType* {.pure.} = enum + NewContent = 0 + RevisionMeta* = object + case kind*: RevisionType + of NewContent: encoding*: Encoding editDistance*: Option[int] size*: Option[int] words*: Option[int] - - Revision = object - meta*: Revisionmeta + Revision* = object + meta*: RevisionMeta time*: Time + SearchResult* = object + page*: string + rank*: float + snippet*: seq[(bool, string)] var logger = newConsoleLogger() @@ -67,6 +97,7 @@ type Page = object page*, content*: string created*, updated*: Time + uid*: int64 proc parse*(s: string, T: typedesc): T = fromJson(result, parseJSON(s), Joptions(allowExtraKeys: true, allowMissingKeys: true)) @@ -74,20 +105,26 @@ proc processFullRevisionRow(row: ResultRow): (RevisionMeta, string) = let (metaJSON, full) = row.unpack((string, seq[byte])) let meta = parse(metaJSON, RevisionMeta) var content = cast[string](full) - if meta.encoding == encZstd: - content = cast[string](decompress(content)) + if meta.encoding == Zstd: + content = cast[string](zstd_decompress.decompress(content)) (meta, content) -proc fetchPage*(db: DbConn, page: string, revision: Option[Time] = none(Time)): Option[Page] = - # retrieve row for page - db.one("SELECT updated, created FROM pages WHERE page = ?", page).flatMap(proc(row: ResultRow): Option[Page] = - let (updated, created) = row.unpack((Time, Time)) - let rev = - if revision.isSome: db.one("SELECT meta, fullData FROM revisions WHERE page = ? AND json_extract(meta, '$.typ') = 0 AND timestamp = ?", page, revision) - else: db.one("SELECT meta, fullData FROM revisions WHERE page = ? AND json_extract(meta, '$.typ') = 0 ORDER BY timestamp DESC LIMIT 1", page) +proc fetchPage*(db: DbConn, page: string): Option[Page] = + # retrieve the current version of the page directly + db.one("SELECT uid, updated, created, content FROM pages WHERE page = ?", page).map(proc(row: ResultRow): Page = + let (uid, updated, created, content) = row.unpack((int64, Time, Time, string)) + Page(page: page, created: created, updated: updated, content: content, uid: uid) + ) + +proc fetchPage*(db: DbConn, page: string, revision: Time): Option[Page] = + # retrieve page row + db.one("SELECT uid, updated, created FROM pages WHERE page = ?", page).flatMap(proc(row: ResultRow): Option[Page] = + let (uid, updated, created) = row.unpack((int64, Time, Time)) + # retrieve the older revision + let rev = db.one("SELECT meta, fullData FROM revisions WHERE page = ? AND json_extract(meta, '$.kind') = 0 AND timestamp = ?", page, revision) rev.map(proc(row: ResultRow): Page = let (meta, content) = processFullRevisionRow(row) - Page(page: page, created: created, updated: updated, content: content) + Page(page: page, created: created, updated: updated, content: content, uid: uid) ) ) @@ -102,22 +139,38 @@ func wordCount(s: string): int = break proc updatePage*(db: DbConn, page: string, content: string) = - let previous = fetchPage(db, page).map(p => p.content).get("") + echo parsePage(content) + let previous = fetchPage(db, page) + # if there is no previous content, empty string instead + let previousContent = previous.map(p => p.content).get("") - let compressed = compress(content, level=10) - var enc = encPlain + # use zstandard-compressed version if it is smaller + let compressed = zstd_compress.compress(content, level=10) + var enc = Plain var data = cast[seq[byte]](content) if len(compressed) < len(data): - enc = encZstd + enc = Zstd data = compressed - let meta = $toJson(RevisionMeta(typ: rtNewContent, encoding: enc, - editDistance: some distance(previous, content), size: some len(content), words: some wordCount(content))) + # generate some useful metadata and encode to JSON + let meta = $toJson(RevisionMeta(kind: NewContent, encoding: enc, + editDistance: some distance(previousContent, content), size: some len(content), words: some wordCount(content))) let ts = getTime() + let revisionID = snowflake() + let pageID = previous.map(p => p.uid).get(snowflake()) + # actually write to database db.transaction: - db.exec("INSERT INTO revisions VALUES (?, ?, ?, ?)", page, ts, meta, data) - db.exec("INSERT INTO pages VALUES (?, ?, ?) ON CONFLICT (page) DO UPDATE SET updated = ?", page, ts, ts, ts) + if isSome previous: + # update existing data and remove FTS index entry for it + db.exec("UPDATE pages SET content = ?, updated = ? WHERE uid = ?", content, ts, pageID) + # pages_fts is an external content FTS table, so deletion has to be done like this + db.exec("INSERT INTO pages_fts (pages_fts, rowid, page, content) VALUES ('delete', ?, ?, ?)", pageID, page, previousContent) + else: + db.exec("INSERT INTO pages VALUES (?, ?, ?, ?, ?)", pageID, page, ts, ts, content) + # push to full text search index + db.exec("INSERT INTO pages_fts (rowid, page, content) VALUES (?, ?, ?)", pageID, page, content) + db.exec("INSERT INTO revisions VALUES (?, ?, ?, ?, ?)", revisionID, page, ts, meta, data) proc fetchRevisions*(db: DbConn, page: string): seq[Revision] = db.all("SELECT timestamp, meta FROM revisions WHERE page = ? ORDER BY timestamp DESC", page).map(proc (row: ResultRow): Revision = @@ -131,7 +184,30 @@ proc processRevisionRow(r: ResultRow): Revision = proc adjacentRevisions*(db: DbConn, page: string, ts: Time): (Option[Revision], Option[Revision]) = # revision after given timestamp - let next = db.one("SELECT timestamp, meta FROM revisions WHERE page = ? AND json_extract(meta, '$.typ') = 0 AND timestamp > ? ORDER BY timestamp ASC LIMIT 1", page, ts) + let next = db.one("SELECT timestamp, meta FROM revisions WHERE page = ? AND json_extract(meta, '$.kind') = 0 AND timestamp > ? ORDER BY timestamp ASC LIMIT 1", page, ts) # revision before given timestamp - let prev = db.one("SELECT timestamp, meta FROM revisions WHERE page = ? AND json_extract(meta, '$.typ') = 0 AND timestamp < ? ORDER BY timestamp DESC LIMIT 1", page, ts) - (next.map(processRevisionRow), prev.map(processRevisionRow)) \ No newline at end of file + let prev = db.one("SELECT timestamp, meta FROM revisions WHERE page = ? AND json_extract(meta, '$.kind') = 0 AND timestamp < ? ORDER BY timestamp DESC LIMIT 1", page, ts) + (next.map(processRevisionRow), prev.map(processRevisionRow)) + +proc processSearchRow(row: ResultRow): SearchResult = + let (page, rank, snippet) = row.unpack((string, float, string)) + var pos = 0 + # split snippet up into an array of highlighted/unhighlighted bits + var snips: seq[(bool, string)] = @[] + while true: + let newpos = find(snippet, "", pos) + if newpos == -1: + break + snips.add((false, snippet[pos .. newpos - 1])) + var endpos = find(snippet, "", newpos) + # if no (this *probably* shouldn't happen) then just highlight remaining rest of string + if endpos == -1: + endpos = len(snippet) + snips.add((true, snippet[newpos + len("") .. endpos - 1])) + pos = endpos + len("") + snips.add((false, snippet[pos .. len(snippet) - 1])) + # filter out empty snippet fragments because they're not useful, rescale rank for nicer display + SearchResult(page: page, rank: log10(-rank * 1e7), snippet: snips.filter(x => len(x[1]) > 0)) + +proc search*(db: DbConn, query: string): seq[SearchResult] = + db.all("SELECT page, rank, snippet(pages_fts, 1, '', '', ' ... ', 32) FROM pages_fts WHERE pages_fts MATCH ? AND rank MATCH 'bm25(5.0, 1.0)' ORDER BY rank", query).map(processSearchRow) \ No newline at end of file diff --git a/src/md.nim b/src/md.nim index 1066895..ccec6b5 100644 --- a/src/md.nim +++ b/src/md.nim @@ -1,72 +1,215 @@ import karax/[karaxdsl, vdom] -import cmark/native +import cmark/native as cmark except Node, Parser # the builtin re library would probably be better for this - it can directly take cstrings (so better perf when dealing with the cstrings from cmark) and may be faster # unfortunately it does not expose a findAll thing which returns the *positions* of everything for some weird reason import regex +from strutils import join, find +import unicode +import sets + +from ./util import pageToSlug, slugToPage, autoInitializedThreadvar cmark_gfm_core_extensions_ensure_registered() -func wikilink(page, linkText: string): string = - let vdom = buildHtml(a(href=page, class="wikilink")): text linkText - $vdom +type + Node = object + raw: NodePtr + BorrowedNode = object + raw: NodePtr + Parser = object + raw: ParserPtr -proc pushNodeAfter(ty: NodeType, content: string, pushAfter: NodePtr) = - let node = cmark_node_new(ty) - assert cmark_node_set_literal(node, content) == 1 - assert cmark_node_insert_before(pushAfter, node) == 1 +proc `=copy`(dest: var Node, source: Node) {.error.} +proc `=destroy`(x: var Node) = cmark_node_free(x.raw) +proc `=destroy`(x: var BorrowedNode) = discard -proc renderToHtml*(input: string): string = - let wlRegex = re"\[\[([^:\]]+):?([^\]]+)?\]\]" - let opt = CMARK_OPT_UNSAFE or CMARK_OPT_FOOTNOTES or CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE or CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES +proc `=destroy`(x: var Parser) = cmark_parser_free(x.raw) - let - str: cstring = input - len: csize_t = len(input).csize_t - parser: ParserPtr = cmark_parser_new(opt.cint) +proc borrow(n: Node): BorrowedNode = BorrowedNode(raw: n.raw) + +proc newParser(options: int64, extensions: seq[string]): Parser = + let parser: ParserPtr = cmark_parser_new(options.cint) if parser == nil: raise newException(CatchableError, "failed to initialize parser") - defer: cmark_parser_free(parser) - - for ext in @["table", "strikethrough"]: + # load and enable desired syntax extensions + # these are freed with the parser (probably) + for ext in extensions: let e: cstring = ext let eptr = cmark_find_syntax_extension(e) - if eptr == nil: raise newException(LibraryError, "failed to find extension " & ext) - if cmark_parser_attach_syntax_extension(parser, eptr) == 0: raise newException(CatchableError, "failed to attach extension " & ext) + if eptr == nil: + cmark_parser_free(parser) + raise newException(LibraryError, "failed to find extension " & ext) + if cmark_parser_attach_syntax_extension(parser, eptr) == 0: + cmark_parser_free(parser) + raise newException(CatchableError, "failed to attach extension " & ext) + Parser(raw: parser) - cmark_parser_feed(parser, str, len) - let doc = cmark_parser_finish(parser) - defer: cmark_node_free(doc) - if doc == nil: raise newException(CatchableError, "parsing failed") +proc parse(p: Parser, document: string): Node = + let + str: cstring = document + length = len(document).csize_t + cmark_parser_feed(p.raw, str, length) + let ast = cmark_parser_finish(p.raw) + if ast == nil: raise newException(CatchableError, "parsing failed - should not occur") + Node(raw: ast) - block: - let iter = cmark_iter_new(doc) - defer: cmark_iter_free(iter) - while true: - let evType = cmark_iter_next(iter) - if evType == etDone: break - let node: NodePtr = cmark_iter_get_node(iter) - if cmark_node_get_type(node) == ntText: - let ntext = $cmark_node_get_literal(node) - # check for wikilinks in text node - let matches = findAll(ntext, wlRegex) - # if there are any, put in the appropriate HTML nodes - if len(matches) > 0: - var lastix = 0 - for match in matches: - let page = ntext[match.captures[0][0]] # I don't know why this doesn't use Option. Perhaps sometimes there are somehow > 1 ranges. - # if there is a separate linkText field, use this, otherwise just use the page - let linkText = - if len(match.captures[1]) > 0: ntext[match.captures[1][0]] - else: page - let html = wikilink(page, linkText) - # push text before this onto the tree, as well as the HTML of the wikilink - pushNodeAfter(ntText, ntext[lastix.. 0: + var lastpos = 0 + # I think this does similar things to the snippet highlight code, perhaps it could be factored out somehow + for match in matches: + let page = ntext[match.captures[0][0]] # I don't know why this doesn't use Option. Perhaps sometimes there are somehow > 1 ranges. + # if there is a separate linkText field, use this, otherwise just use the page + let linkText = + if len(match.captures[1]) > 0: ntext[match.captures[1][0]] + else: page + let html = wikilink(page, linkText) + # push text before this onto the tree, as well as the HTML of the wikilink + pushNodeAfter(node, newNode(ntText, ntext[lastpos..= lookaround and laterToks.len >= lookaround: + earlierToks[^lookaround..^1].join(" ") & linkText & laterToks[0..= lookaround and laterToks.len < lookaround: + earlierToks[^(bdlook - laterToks.len)..^1].join(" ") & linkText & laterToks.join(" ") + # mirrored version of previous case + elif earlierToks.len < lookaround and laterToks.len >= lookaround: + earlierToks.join(" ") & linkText & laterToks[0..<(bdlook - earlierToks.len)].join(" ") + # both too short, use all of both + else: earlierToks.join(" ") & linkText & laterToks.join(" ") + +proc parsePage*(input: string): ParsedPage = + let wlRegex = wlRegex() + let opt = CMARK_OPT_UNSAFE or CMARK_OPT_FOOTNOTES or CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE or CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES + + let parser = newParser(opt, @["table", "strikethrough"]) + let doc = parse(parser, input) + + var wikilinks: seq[Link] = @[] + var seenPages: HashSet[string] + + for (evType, node) in cmarkTree(borrow(doc)): + if nodeType(node) == ntText: + let ntext = nodeContent(node) + let matches = findAll(ntext, wlRegex) + if len(matches) > 0: + let paragraph = textContent(findParagraphParent(node)) + var matchEnd = 0 + for match in matches: + echo $match + let page = ntext[match.captures[0][0]] + let linkText = + if len(match.captures[1]) > 0: ntext[match.captures[1][0]] + else: page + + let canonicalPage = slugToPage(page) + if not (canonicalPage in seenPages): + # matches in this text node will not necessarily line up with ones in the surrounding textual contentso look up the wikilink's source in the paragraph + # kind of hacky but should work in any scenario which isn't deliberately constructed pathologically, especially since it will only return stuff after the last link + let fullLink = ntext[match.boundaries] + let matchInParagraph = find(paragraph, fullLink, matchEnd) + matchEnd = matchInParagraph + fullLink.len + let context = linkContext(paragraph, matchInParagraph, matchEnd, 12) + + # add to wikilinks list, and deduplicate + wikilinks.add(Link(page: canonicalPage, text: linkText, context: context)) + seenPages.incl(canonicalPage) + + ParsedPage(links: wikilinks, fullText: textContent(borrow(doc))) \ No newline at end of file diff --git a/src/minoteaur.nim b/src/minoteaur.nim index 5b30f89..a6cf90a 100644 --- a/src/minoteaur.nim +++ b/src/minoteaur.nim @@ -7,10 +7,13 @@ import tiny_sqlite import options import times import sugar +import std/jsonutils import strutils +import prologue/middlewares/csrf from ./domain import nil from ./md import nil +import util let env = loadPrologueEnv(".env") @@ -27,19 +30,24 @@ func base(title: string, navItems: seq[VNode], bodyItems: VNode): string = let vnode = buildHtml(html): head: link(rel="stylesheet", href="/static/style.css") + script(src="/static/client.js", `defer`="true") meta(charset="utf8") meta(name="viewport", content="width=device-width,initial-scale=1.0") title: text title body: main: nav: + a(class="link-button search", href=""): text "Search" for n in navItems: n tdiv(class="header"): h1: text title bodyItems $vnode -domain.migrate(openDatabase("./minoteaur.sqlite3")) +block: + let db = openDatabase("./minoteaur.sqlite3") + domain.migrate(db) + close(db) type AppContext = ref object of Context @@ -49,34 +57,46 @@ type var db {.threadvar.}: Option[DbConn] proc dbMiddleware(): HandlerAsync = + # horrible accursed hack to make exitproc work result = proc(ctx: AppContext) {.async.} = # open new DB connection for thread if there isn't one if db.isNone: - db = some openDatabase("./minoteaur.sqlite3") - # close DB connection on thread exit - onThreadDestruction(proc() = - try: db.get().close() - except: discard) + echo "Opening database connection" + var conn = openDatabase("./minoteaur.sqlite3") + conn.exec("PRAGMA foreign_keys = ON") + db = some conn ctx.db = get db await switch(ctx) +proc headersMiddleware(): HandlerAsync = + result = proc(ctx: AppContext) {.async.} = + await switch(ctx) + ctx.response.setHeader("X-Content-Type-Options", "nosniff") + # user-controlled inline JS/CSS is explicitly turned on + # this does partly defeat the point of a CSP, but this is still able to prevent connecting to other sites unwantedly + ctx.response.setHeader("Content-Security-Policy", "default-src 'self' 'unsafe-inline'; img-src * data:; media-src * data:; form-action 'self'; frame-ancestors 'self'") + ctx.response.setHeader("Referrer-Policy", "origin-when-cross-origin") + proc displayTime(t: Time): string = t.format("uuuu-MM-dd HH:mm:ss", utc()) -func pageUrlFor(ctx: AppContext, route: string, page: string, query: openArray[(string, string)] = @[]): string = ctx.urlFor(route, { "page": encodeUrl(page) }, query) +func pageUrlFor(ctx: AppContext, route: string, page: string, query: openArray[(string, string)] = @[]): string = ctx.urlFor(route, { "page": encodeUrl(pageToSlug(page)) }, query) func pageButton(ctx: AppContext, route: string, page: string, label: string, query: openArray[(string, string)] = @[]): VNode = navButton(label, pageUrlFor(ctx, route, page, query), route) +proc formCsrfToken(ctx: AppContext): VNode = verbatim csrfToken(ctx) + proc edit(ctx: AppContext) {.async.} = - let page = decodeUrl(ctx.getPathParams("page")) + let page = slugToPage(decodeUrl(ctx.getPathParams("page"))) let pageData = domain.fetchPage(ctx.db, page) let html = buildHtml(form(`method`="post", class="edit-form")): - textarea(name="content"): text pageData.map(p => p.content).get("") input(`type`="submit", value="Save", name="action", class="save") + textarea(name="content"): text pageData.map(p => p.content).get("") + formCsrfToken(ctx) let verb = if pageData.isSome: "Editing " else: "Creating " resp base(verb & page, @[pageButton(ctx, "view-page", page, "View"), pageButton(ctx, "page-revisions", page, "Revisions")], html) proc revisions(ctx: AppContext) {.async.} = - let page = decodeUrl(ctx.getPathParams("page")) + let page = slugToPage(decodeUrl(ctx.getPathParams("page"))) let revs = domain.fetchRevisions(ctx.db, page) let html = buildHtml(table(class="rev-table")): @@ -88,7 +108,7 @@ proc revisions(ctx: AppContext) {.async.} = for rev in revs: tr: td(class="ts"): - a(href=ctx.urlFor("view-page", { "page": encodeUrl(page) }, { "ts": domain.timestampToStr(rev.time) })): + a(href=ctx.urlFor("view-page", { "page": pageToSlug(encodeUrl(page)) }, { "ts": timestampToStr(rev.time) })): text displayTime(rev.time) td: text rev.meta.editDistance.map(x => $x).get("") td: text rev.meta.size.map(x => formatSize(x)).get("") @@ -96,20 +116,20 @@ proc revisions(ctx: AppContext) {.async.} = resp base("Revisions of " & page, @[pageButton(ctx, "view-page", page, "View"), pageButton(ctx, "edit-page", page, "Edit")], html) proc handleEdit(ctx: AppContext) {.async.} = - let page = decodeUrl(ctx.getPathParams("page")) + let page = slugToPage(decodeUrl(ctx.getPathParams("page"))) domain.updatePage(ctx.db, page, ctx.getFormParams("content")) - resp redirect(pageUrlFor(ctx, "view-page", page)) + resp redirect(pageUrlFor(ctx, "view-page", page), Http303) proc view(ctx: AppContext) {.async.} = - let page = decodeUrl(ctx.getPathParams("page")) + let page = slugToPage(decodeUrl(ctx.getPathParams("page"))) let rawRevision = ctx.getQueryParams("ts") let viewSource = ctx.getQueryParams("source") != "" - let revisionTs = if rawRevision == "": none(Time) else: some domain.timestampToTime(parseInt rawRevision) + let revisionTs = if rawRevision == "": none(Time) else: some timestampToTime(parseInt rawRevision) let viewingOldRevision = revisionTs.isSome - let pageData = domain.fetchPage(ctx.db, page, revisionTs) + let pageData = if viewingOldRevision: domain.fetchPage(ctx.db, page, get revisionTs) else: domain.fetchPage(ctx.db, page) if pageData.isNone: - resp redirect(pageUrlFor(ctx, "edit-page", page)) + resp redirect(pageUrlFor(ctx, "edit-page", page), Http302) else: let pageData = get pageData let mainBody = if viewSource: buildHtml(pre): text pageData.content else: verbatim md.renderToHtml(pageData.content) @@ -134,18 +154,28 @@ proc view(ctx: AppContext) {.async.} = text displayTime(rts) tdiv(class="md"): mainBody var buttons = @[pageButton(ctx, "edit-page", page, "Edit"), pageButton(ctx, "page-revisions", page, "Revisions"), pageButton(ctx, "view-page", page, "Latest")] - if next.isSome: buttons.add(pageButton(ctx, "next-page", page, "Next", { "ts": domain.timestampToStr (get next).time })) - if prev.isSome: buttons.add(pageButton(ctx, "prev-page", page, "Previous", { "ts": domain.timestampToStr (get prev).time })) + if next.isSome: buttons.add(pageButton(ctx, "next-page", page, "Next", { "ts": timestampToStr (get next).time })) + if prev.isSome: buttons.add(pageButton(ctx, "prev-page", page, "Previous", { "ts": timestampToStr (get prev).time })) resp base(page, buttons, html) -proc favicon(ctx: Context) {.async.} = resp "bee" +proc search(ctx: AppContext) {.async.} = + let query = ctx.getQueryParams("q") + var results: seq[domain.SearchResult] = @[] + try: + if query != "": results = domain.search(ctx.db, query) + except SqliteError as e: # SQLite apparently treats FTS queries containing some things outside of quotes as syntax errors. These should probably be shown to the user. + resp jsonResponse toJson($e.msg) + return + resp jsonResponse toJson(results) +proc favicon(ctx: Context) {.async.} = resp error404() proc index(ctx: Context) {.async.} = resp "bee(s)" var app = newApp(settings = settings) -app.use(@[staticFileMiddleware("static"), sessionMiddleware(settings), extendContextMiddleware(AppContext), dbMiddleware()]) +app.use(@[staticFileMiddleware("static"), sessionMiddleware(settings), extendContextMiddleware(AppContext), dbMiddleware(), headersMiddleware(), csrfMiddleware()]) app.get("/", index) app.get("/favicon.ico", favicon) +app.get("/api/search", search, name="search") app.get("/{page}/edit", edit, name="edit-page") app.get("/{page}/revisions", revisions, name="page-revisions") app.post("/{page}/edit", handleEdit, name="handle-edit") diff --git a/src/style.sass b/src/style.sass index 12d3da3..5e67324 100755 --- a/src/style.sass +++ b/src/style.sass @@ -11,10 +11,11 @@ body min-height: 100vh main - width: 50em + max-width: 50em padding: 0 1em 1em 1em margin-left: auto margin-right: auto + position: relative strong font-weight: 600 @@ -22,7 +23,7 @@ strong h1, h2, h3, h4, h5, h6 &:first-of-type border-bottom: 1px solid gray - margin: 0 + margin: 0 0 0.5em 0 font-weight: 500 a color: inherit @@ -58,9 +59,6 @@ table &.ts white-space: nowrap -.header - margin-bottom: 0.5em - .md margin-top: 0.5em > *, p @@ -74,7 +72,7 @@ nav a.wikilink text-decoration: none - color: #01a049 + color: #0165fc font-style: italic &:hover text-decoration: underline @@ -104,10 +102,36 @@ a.wikilink background-color: #5170d7 &.prev-page background-color: #bc13fe + &.search + background-color: #fac205 + +input[type=search], input[type=text] + border: 1px solid gray + padding: 0.75em + width: 100% .edit-form textarea resize: vertical width: 100% height: 70vh - border: 1px solid gray \ No newline at end of file + border: 1px solid gray + +.highlight + background-color: yellow + +.dialog + width: 100% + background: white + padding: 1em + border: 1px solid gray + +.flex-space + display: flex + justify-content: space-between + +.error + color: red + +img + max-width: 100% \ No newline at end of file diff --git a/src/util.nim b/src/util.nim new file mode 100644 index 0000000..522e26d --- /dev/null +++ b/src/util.nim @@ -0,0 +1,63 @@ +import times +import unicode +import strutils except splitWhitespace +import sequtils +import tiny_sqlite +import random +import math +import times +import options + +func lowercaseFirstLetter(s: string): string = + if len(s) == 0: + return "" + var + rune: Rune + i = 0 + fastRuneAt(s, i, rune, doInc = true) + result = $toLower(rune) & substr(s, i) +func pageToSlug*(page: string): string = page.split({'_', ' '}).map(lowercaseFirstLetter).join("_") +func slugToPage*(slug: string): string = slug.split({'_', ' '}).map(capitalize).join(" ") + +func timeToTimestamp*(t: Time): int64 = toUnix(t) * 1000 + (nanosecond(t) div 1000000) +func timestampToTime*(ts: int64): Time = initTime(ts div 1000, (ts mod 1000) * 1000000) +func timestampToStr*(t: Time): string = intToStr(int(timeToTimestamp(t))) + +# store time as milliseconds +proc toDbValue*(t: Time): DbValue = DbValue(kind: sqliteInteger, intVal: timeToTimestamp(t)) +proc fromDbValue*(value: DbValue, T: typedesc[Time]): Time = timestampToTime(value.intVal) + +# count words, defined as things separated by whitespace which are not purely punctuation characters +# alternative definitions may include dropping number-only words, and/or splitting at full stops too +func wordCount(s: string): int = + for word in splitWhitespace(s): + if len(word) == 0: continue + for bytechar in word: + if not (bytechar in {'[', ']', ':', '.', '!'}): + inc result + break + +template autoInitializedThreadvar*(name: untyped, typ: typedesc, initialize: typed): untyped = + var data* {.threadvar.}: Option[typ] + proc `name`(): typ = + if isSome(data): result = get data + else: + result = initialize + data = some result + +# https://github.com/aisk/simpleflake.nim/blob/master/src/simpleflake.nim - unique 64-bit timestamped ID generation +# not actually identical to that as this has 2 bits less randomness to avoid timestamp overflow issues in 2034 (the application is likely to be replaced by 2139 so the new time is probably fine) +# This is a signed integer for SQLite compatibility +const SIMPLEFLAKE_EPOCH = 946702800 +const SIMPLEFLAKE_RANDOM_LENGTH = 21 + +let now = times.getTime() +autoInitializedThreadvar(threadRNG, Rand, random.initRand(now.toUnix * 1_000_000_000 + now.nanosecond)) + +proc snowflake*(): int64 = + var rng = threadRNG() + let now = times.getTime().toUnixFloat() + var ts = int64((now - SIMPLEFLAKE_EPOCH) * 1000) + let randomBits = int64(rng.rand(2 ^ SIMPLEFLAKE_RANDOM_LENGTH)) + + return ts shl SIMPLEFLAKE_RANDOM_LENGTH or randomBits \ No newline at end of file diff --git a/static/client.js b/static/client.js new file mode 100644 index 0000000..2c3bd64 --- /dev/null +++ b/static/client.js @@ -0,0 +1,2 @@ +(()=>{var Kt=Object.create,Re=Object.defineProperty,Jt=Object.getPrototypeOf,Bt=Object.prototype.hasOwnProperty,Gt=Object.getOwnPropertyNames,Xt=Object.getOwnPropertyDescriptor;var Zt=n=>Re(n,"__esModule",{value:!0});var O=(n,i)=>()=>(i||(i={exports:{}},n(i.exports,i)),i.exports);var Wt=(n,i,u)=>{if(Zt(n),i&&typeof i=="object"||typeof i=="function")for(let c of Gt(i))!Bt.call(n,c)&&c!=="default"&&Re(n,c,{get:()=>i[c],enumerable:!(u=Xt(i,c))||u.enumerable});return n},Yt=n=>n&&n.__esModule?n:Wt(Re(n!=null?Kt(Jt(n)):{},"default",{value:n,enumerable:!0}),n);var Z=O((Lr,Ge)=>{"use strict";function te(n,i,u,c,b,h){return{tag:n,key:i,attrs:u,children:c,text:b,dom:h,domSize:void 0,state:void 0,events:void 0,instance:void 0}}te.normalize=function(n){return Array.isArray(n)?te("[",void 0,void 0,te.normalizeChildren(n),void 0,void 0):n==null||typeof n=="boolean"?null:typeof n=="object"?n:te("#",void 0,void 0,String(n),void 0,void 0)};te.normalizeChildren=function(n){var i=[];if(n.length){for(var u=n[0]!=null&&n[0].key!=null,c=1;c{"use strict";var kt=Z();Xe.exports=function(){var n=arguments[this],i=this+1,u;if(n==null?n={}:(typeof n!="object"||n.tag!=null||Array.isArray(n))&&(n={},i=this),arguments.length===i+1)u=arguments[i],Array.isArray(u)||(u=[u]);else for(u=[];i{"use strict";var We=Z(),vt=Le(),er=/(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g,Ye={},ne={}.hasOwnProperty;function ke(n){for(var i in n)if(ne.call(n,i))return!1;return!0}function tr(n){for(var i,u="div",c=[],b={};i=er.exec(n);){var h=i[1],o=i[2];if(h===""&&o!=="")u=o;else if(h==="#")b.id=o;else if(h===".")c.push(o);else if(i[3][0]==="["){var s=i[6];s&&(s=s.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),i[4]==="class"?c.push(s):b[i[4]]=s===""?s:s||!0}}return c.length>0&&(b.className=c.join(" ")),Ye[n]={tag:u,attrs:b}}function rr(n,i){var u=i.attrs,c=We.normalizeChildren(i.children),b=ne.call(u,"class"),h=b?u.class:u.className;if(i.tag=n.tag,i.attrs=null,i.children=void 0,!ke(n.attrs)&&!ke(u)){var o={};for(var s in u)ne.call(u,s)&&(o[s]=u[s]);u=o}for(var s in n.attrs)ne.call(n.attrs,s)&&s!=="className"&&!ne.call(u,s)&&(u[s]=n.attrs[s]);(h!=null||n.attrs.className!=null)&&(u.className=h!=null?n.attrs.className!=null?String(n.attrs.className)+" "+String(h):h:n.attrs.className!=null?n.attrs.className:null),b&&(u.class=null);for(var s in u)if(ne.call(u,s)&&s!=="key"){i.attrs=u;break}return Array.isArray(c)&&c.length===1&&c[0]!=null&&c[0].tag==="#"?i.text=c[0].children:i.children=c,i}function nr(n){if(n==null||typeof n!="string"&&typeof n!="function"&&typeof n.view!="function")throw Error("The selector must be either a string or a component.");var i=vt.apply(1,arguments);return typeof n=="string"&&(i.children=We.normalizeChildren(i.children),n!=="[")?rr(Ye[n]||tr(n),i):(i.tag=n,i)}Ze.exports=nr});var et=O((_r,ve)=>{"use strict";var ir=Z();ve.exports=function(n){return n==null&&(n=""),ir("<",void 0,void 0,n,void 0,void 0)}});var rt=O((Sr,tt)=>{"use strict";var ar=Z(),fr=Le();tt.exports=function(){var n=fr.apply(0,arguments);return n.tag="[",n.children=ar.normalizeChildren(n.children),n}});var it=O((Mr,nt)=>{"use strict";var Ie=De();Ie.trust=et();Ie.fragment=rt();nt.exports=Ie});var _e=O((Hr,at)=>{"use strict";var S=function(n){if(!(this instanceof S))throw new Error("Promise must be called with `new`");if(typeof n!="function")throw new TypeError("executor must be a function");var i=this,u=[],c=[],b=l(u,!0),h=l(c,!1),o=i._instance={resolvers:u,rejectors:c},s=typeof setImmediate=="function"?setImmediate:setTimeout;function l(g,w){return function E(m){var C;try{if(w&&m!=null&&(typeof m=="object"||typeof m=="function")&&typeof(C=m.then)=="function"){if(m===i)throw new TypeError("Promise can't be resolved w/ itself");y(C.bind(m))}else s(function(){!w&&g.length===0&&console.error("Possible unhandled promise rejection:",m);for(var x=0;x0||C(x)}}var m=E(h);try{g(E(b),m)}catch(C){m(C)}}y(n)};S.prototype.then=function(n,i){var u=this,c=u._instance;function b(l,y,g,w){y.push(function(E){if(typeof l!="function")g(E);else try{h(l(E))}catch(m){o&&o(m)}}),typeof c.retry=="function"&&w===c.state&&c.retry()}var h,o,s=new S(function(l,y){h=l,o=y});return b(n,c.resolvers,h,!0),b(i,c.rejectors,o,!1),s};S.prototype.catch=function(n){return this.then(null,n)};S.prototype.finally=function(n){return this.then(function(i){return S.resolve(n()).then(function(){return i})},function(i){return S.resolve(n()).then(function(){return S.reject(i)})})};S.resolve=function(n){return n instanceof S?n:new S(function(i){i(n)})};S.reject=function(n){return new S(function(i,u){u(n)})};S.all=function(n){return new S(function(i,u){var c=n.length,b=0,h=[];if(n.length===0)i([]);else for(var o=0;o{"use strict";var fe=_e();typeof window!="undefined"?(typeof window.Promise=="undefined"?window.Promise=fe:window.Promise.prototype.finally||(window.Promise.prototype.finally=fe.prototype.finally),he.exports=window.Promise):typeof global!="undefined"?(typeof global.Promise=="undefined"?global.Promise=fe:global.Promise.prototype.finally||(global.Promise.prototype.finally=fe.prototype.finally),he.exports=global.Promise):he.exports=fe});var ut=O((Fr,ft)=>{"use strict";var ie=Z();ft.exports=function(n){var i=n&&n.document,u,c={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"};function b(t){return t.attrs&&t.attrs.xmlns||c[t.tag]}function h(t,e){if(t.state!==e)throw new Error("`vnode.state` must not be modified")}function o(t){var e=t.state;try{return this.apply(e,arguments)}finally{h(t,e)}}function s(){try{return i.activeElement}catch(t){return null}}function l(t,e,r,a,f,p,P){for(var N=r;N'+e.children+"",p=p.firstChild):p.innerHTML=e.children,e.dom=p.firstChild,e.domSize=p.childNodes.length,e.instance=[];for(var P=i.createDocumentFragment(),N;N=p.firstChild;)e.instance.push(N),P.appendChild(N);v(t,P,a)}function m(t,e,r,a,f){var p=i.createDocumentFragment();if(e.children!=null){var P=e.children;l(p,P,0,P.length,r,null,a)}e.dom=p.firstChild,e.domSize=p.childNodes.length,v(t,p,f)}function C(t,e,r,a,f){var p=e.tag,P=e.attrs,N=P&&P.is;a=b(e)||a;var q=a?N?i.createElementNS(a,p,{is:N}):i.createElementNS(a,p):N?i.createElement(p,{is:N}):i.createElement(p);if(e.dom=q,P!=null&&_t(e,P,a),v(t,q,f),!ee(e)&&(e.text!=null&&(e.text!==""?q.textContent=e.text:e.children=[ie("#",void 0,void 0,e.text,void 0,void 0)]),e.children!=null)){var A=e.children;l(q,A,0,A.length,r,null,a),e.tag==="select"&&P!=null&&Mt(e,P)}}function x(t,e){var r;if(typeof t.tag.view=="function"){if(t.state=Object.create(t.tag),r=t.state.view,r.$$reentrantLock$$!=null)return;r.$$reentrantLock$$=!0}else{if(t.state=void 0,r=t.tag,r.$$reentrantLock$$!=null)return;r.$$reentrantLock$$=!0,t.state=t.tag.prototype!=null&&typeof t.tag.prototype.view=="function"?new t.tag(t):t.tag(t)}if(Pe(t.state,t,e),t.attrs!=null&&Pe(t.attrs,t,e),t.instance=ie.normalize(o.call(t.state.view,t)),t.instance===t)throw Error("A view cannot return the vnode it received as argument");r.$$reentrantLock$$=null}function d(t,e,r,a,f){x(e,r),e.instance!=null?(y(t,e.instance,r,a,f),e.dom=e.instance.dom,e.domSize=e.dom!=null?e.instance.domSize:0):e.domSize=0}function T(t,e,r,a,f,p){if(!(e===r||e==null&&r==null))if(e==null||e.length===0)l(t,r,0,r.length,a,f,p);else if(r==null||r.length===0)G(t,e,0,e.length);else{var P=e[0]!=null&&e[0].key!=null,N=r[0]!=null&&r[0].key!=null,q=0,A=0;if(!P)for(;A=A&&_>=q&&(U=e[Q],z=r[_],U.key===z.key);)U!==z&&D(t,U,z,a,f,p),z.dom!=null&&(f=z.dom),Q--,_--;for(;Q>=A&&_>=q&&(V=e[A],L=r[q],V.key===L.key);)A++,q++,V!==L&&D(t,V,L,a,B(e,A,f),p);for(;Q>=A&&_>=q&&!(q===_||V.key!==z.key||U.key!==L.key);)Te=B(e,A,f),J(t,U,Te),U!==L&&D(t,U,L,a,Te,p),++q<=--_&&J(t,V,f),V!==z&&D(t,V,z,a,f,p),z.dom!=null&&(f=z.dom),A++,Q--,U=e[Q],z=r[_],V=e[A],L=r[q];for(;Q>=A&&_>=q&&U.key===z.key;)U!==z&&D(t,U,z,a,f,p),z.dom!=null&&(f=z.dom),Q--,_--,U=e[Q],z=r[_];if(q>_)G(t,e,A,Q+1);else if(A>Q)l(t,r,q,_+1,a,f,p);else{var $t=f,Be=_-q+1,ae=new Array(Be),Ae=0,R=0,je=2147483647,ze=0,oe,Oe;for(R=0;R=q;R--){oe==null&&(oe=X(e,A,Q+1)),z=r[R];var re=oe[z.key];re!=null&&(je=re=q;R--)L=r[R],ae[R-q]===-1?y(t,L,a,p,f):Oe[Ae]===R-q?Ae--:J(t,L,f),L.dom!=null&&(f=r[R].dom);else for(R=_;R>=q;R--)L=r[R],ae[R-q]===-1&&y(t,L,a,p,f),L.dom!=null&&(f=r[R].dom)}}else{var de=e.lengthde&&G(t,e,q,e.length),r.length>de&&l(t,r,q,r.length,a,f,p)}}}function D(t,e,r,a,f,p){var P=e.tag,N=r.tag;if(P===N){if(r.state=e.state,r.events=e.events,Vt(r,e))return;if(typeof P=="string")switch(r.attrs!=null&&Ne(r.attrs,r,a),P){case"#":W(e,r);break;case"<":Y(t,e,r,p,f);break;case"[":I(t,e,r,a,f,p);break;default:j(e,r,a,p)}else H(t,e,r,a,f,p)}else ce(t,e),y(t,r,a,p,f)}function W(t,e){t.children.toString()!==e.children.toString()&&(t.dom.nodeValue=e.children),e.dom=t.dom}function Y(t,e,r,a,f){e.children!==r.children?(Ve(t,e),E(t,r,a,f)):(r.dom=e.dom,r.domSize=e.domSize,r.instance=e.instance)}function I(t,e,r,a,f,p){T(t,e.children,r.children,a,f,p);var P=0,N=r.children;if(r.dom=null,N!=null){for(var q=0;q>>1)+(a>>>1)+(r&a&1);t[e[N]]0&&(K[f]=e[r-1]),e[r]=f)}for(r=e.length,a=e[r-1];r-- >0;)e[r]=a,a=K[a];return K.length=0,e}function B(t,e,r){for(;e-1||t.attrs!=null&&t.attrs.is||e!=="href"&&e!=="list"&&e!=="form"&&e!=="width"&&e!=="height")&&e in t.dom}var Ft=/[A-Z]/g;function Qt(t){return"-"+t.toLowerCase()}function Ce(t){return t[0]==="-"&&t[1]==="-"?t:t==="cssFloat"?"float":t.replace(Ft,Qt)}function Ke(t,e,r){if(e!==r)if(r==null)t.style.cssText="";else if(typeof r!="object")t.style.cssText=r;else if(e==null||typeof e!="object"){t.style.cssText="";for(var a in r){var f=r[a];f!=null&&t.style.setProperty(Ce(a),String(f))}}else{for(var a in r){var f=r[a];f!=null&&(f=String(f))!==String(e[a])&&t.style.setProperty(Ce(a),f)}for(var a in e)e[a]!=null&&r[a]==null&&t.style.removeProperty(Ce(a))}}function Ee(){this._=u}Ee.prototype=Object.create(null),Ee.prototype.handleEvent=function(t){var e=this["on"+t.type],r;typeof e=="function"?r=e.call(t.currentTarget,t):typeof e.handleEvent=="function"&&e.handleEvent(t),this._&&t.redraw!==!1&&(0,this._)(),r===!1&&(t.preventDefault(),t.stopPropagation())};function Je(t,e,r){if(t.events!=null){if(t.events[e]===r)return;r!=null&&(typeof r=="function"||typeof r=="object")?(t.events[e]==null&&t.dom.addEventListener(e.slice(2),t.events,!1),t.events[e]=r):(t.events[e]!=null&&t.dom.removeEventListener(e.slice(2),t.events,!1),t.events[e]=void 0)}else r!=null&&(typeof r=="function"||typeof r=="object")&&(t.events=new Ee,t.dom.addEventListener(e.slice(2),t.events,!1),t.events[e]=r)}function Pe(t,e,r){typeof t.oninit=="function"&&o.call(t.oninit,e),typeof t.oncreate=="function"&&r.push(o.bind(t.oncreate,e))}function Ne(t,e,r){typeof t.onupdate=="function"&&r.push(o.bind(t.onupdate,e))}function Vt(t,e){do{if(t.attrs!=null&&typeof t.attrs.onbeforeupdate=="function"){var r=o.call(t.attrs.onbeforeupdate,t,e);if(r!==void 0&&!r)break}if(typeof t.tag!="string"&&typeof t.state.onbeforeupdate=="function"){var r=o.call(t.state.onbeforeupdate,t,e);if(r!==void 0&&!r)break}return!1}while(!1);return t.dom=e.dom,t.domSize=e.domSize,t.instance=e.instance,t.attrs=e.attrs,t.children=e.children,t.text=e.text,!0}return function(t,e,r){if(!t)throw new TypeError("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.");var a=[],f=s(),p=t.namespaceURI;t.vnodes==null&&(t.textContent=""),e=ie.normalizeChildren(Array.isArray(e)?e:[e]);var P=u;try{u=typeof r=="function"?r:void 0,T(t,t.vnodes,e,a,null,p==="http://www.w3.org/1999/xhtml"?void 0:p)}finally{u=P}t.vnodes=e,f!=null&&s()!==f&&typeof f.focus=="function"&&f.focus();for(var N=0;N{"use strict";lt.exports=ut()(window)});var ot=O((Vr,ct)=>{"use strict";var st=Z();ct.exports=function(n,i,u){var c=[],b=!1,h=!1;function o(){if(b)throw new Error("Nested m.redraw.sync() call");b=!0;for(var y=0;y=0&&(c.splice(w,2),n(y,[],s)),g!=null&&(c.push(y,g),n(y,st(g),s))}return{mount:l,redraw:s}}});var pe=O(($r,ht)=>{"use strict";var ur=Me();ht.exports=ot()(ur,requestAnimationFrame,console)});var He=O((Kr,pt)=>{"use strict";pt.exports=function(n){if(Object.prototype.toString.call(n)!=="[object Object]")return"";var i=[];for(var u in n)c(u,n[u]);return i.join("&");function c(b,h){if(Array.isArray(h))for(var o=0;o{"use strict";mt.exports=Object.assign||function(n,i){i&&Object.keys(i).forEach(function(u){n[u]=i[u]})}});var me=O((Br,yt)=>{"use strict";var lr=He(),cr=Ue();yt.exports=function(n,i){if(/:([^\/\.-]+)(\.{3})?:/.test(n))throw new SyntaxError("Template parameter names *must* be separated");if(i==null)return n;var u=n.indexOf("?"),c=n.indexOf("#"),b=c<0?n.length:c,h=u<0?b:u,o=n.slice(0,h),s={};cr(s,i);var l=o.replace(/:([^\/\.-]+)(\.{3})?/g,function(x,d,T){return delete s[d],i[d]==null?x:T?i[d]:encodeURIComponent(String(i[d]))}),y=l.indexOf("?"),g=l.indexOf("#"),w=g<0?l.length:g,E=y<0?w:y,m=l.slice(0,E);u>=0&&(m+=n.slice(u,b)),y>=0&&(m+=(u<0?"?":"&")+l.slice(y,w));var C=lr(s);return C&&(m+=(u<0&&y<0?"?":"&")+C),c>=0&&(m+=n.slice(c)),g>=0&&(m+=(c<0?"":"&")+l.slice(g)),m}});var wt=O((Gr,gt)=>{"use strict";var sr=me();gt.exports=function(n,i,u){var c=0;function b(s){return new i(s)}b.prototype=i.prototype,b.__proto__=i;function h(s){return function(l,y){typeof l!="string"?(y=l,l=l.url):y==null&&(y={});var g=new i(function(C,x){s(sr(l,y.params),y,function(d){if(typeof y.type=="function")if(Array.isArray(d))for(var T=0;T=200&&I.target.status<300||I.target.status===304||/^file:\/\//i.test(s),H=I.target.response,X;if(C==="json"?!I.target.responseType&&typeof l.extract!="function"&&(H=JSON.parse(I.target.responseText)):(!C||C==="text")&&H==null&&(H=I.target.responseText),typeof l.extract=="function"?(H=l.extract(I.target,l),j=!0):typeof l.deserialize=="function"&&(H=l.deserialize(H)),j)y(H);else{try{X=I.target.responseText}catch(k){X=H}var K=new Error(X);K.code=I.target.status,K.response=H,g(K)}}catch(k){g(k)}},typeof l.config=="function"&&(x=l.config(x,l,s)||x,x!==T&&(D=x.abort,x.abort=function(){d=!0,D.call(this)})),E==null?x.send():typeof l.serialize=="function"?x.send(l.serialize(E)):E instanceof n.FormData?x.send(E):x.send(JSON.stringify(E))}),jsonp:h(function(s,l,y,g){var w=l.callbackName||"_mithril_"+Math.round(Math.random()*1e16)+"_"+c++,E=n.document.createElement("script");n[w]=function(m){delete n[w],E.parentNode.removeChild(E),y(m)},E.onerror=function(){delete n[w],E.parentNode.removeChild(E),g(new Error("JSONP request failed"))},E.src=s+(s.indexOf("?")<0?"?":"&")+encodeURIComponent(l.callbackKey||"callback")+"="+encodeURIComponent(w),n.document.documentElement.appendChild(E)})}}});var xt=O((Xr,bt)=>{"use strict";var or=Se(),hr=pe();bt.exports=wt()(window,or,hr.redraw)});var Fe=O((Zr,qt)=>{"use strict";qt.exports=function(n){if(n===""||n==null)return{};n.charAt(0)==="?"&&(n=n.slice(1));for(var i=n.split("&"),u={},c={},b=0;b-1&&l.pop();for(var g=0;g{"use strict";var pr=Fe();Ct.exports=function(n){var i=n.indexOf("?"),u=n.indexOf("#"),c=u<0?n.length:u,b=i<0?c:i,h=n.slice(0,b).replace(/\/{2,}/g,"/");return h?(h[0]!=="/"&&(h="/"+h),h.length>1&&h[h.length-1]==="/"&&(h=h.slice(0,-1))):h="/",{path:h,params:i<0?{}:pr(n.slice(i+1,c))}}});var Pt=O((Yr,Et)=>{"use strict";var mr=ye();Et.exports=function(n){var i=mr(n),u=Object.keys(i.params),c=[],b=new RegExp("^"+i.path.replace(/:([^\/.-]+)(\.{3}|\.(?!\.)|-)?|[\\^$*+.()|\[\]{}]/g,function(h,o,s){return o==null?"\\"+h:(c.push({k:o,r:s==="..."}),s==="..."?"(.*)":s==="."?"([^/]+)\\.":"([^/]+)"+(s||""))})+"$");return function(h){for(var o=0;o{"use strict";var yr=Z(),gr=De(),wr=Se(),br=me(),dt=ye(),xr=Pt(),Tt=Ue(),Qe={};Nt.exports=function(n,i){var u;function c(w,E,m){if(w=br(w,E),u!=null){u();var C=m?m.state:null,x=m?m.title:null;m&&m.replace?n.history.replaceState(C,x,g.prefix+w):n.history.pushState(C,x,g.prefix+w)}else n.location.href=g.prefix+w}var b=Qe,h,o,s,l,y=g.SKIP={};function g(w,E,m){if(w==null)throw new Error("Ensure the DOM element that was passed to `m.route` is not undefined");var C=0,x=Object.keys(m).map(function(j){if(j[0]!=="/")throw new SyntaxError("Routes must start with a `/`");if(/:([^\/\.-]+)(\.{3})?:/.test(j))throw new SyntaxError("Route parameter names must be separated with either `/`, `.`, or `-`");return{route:j,component:m[j],check:xr(j)}}),d=typeof setImmediate=="function"?setImmediate:setTimeout,T=wr.resolve(),D=!1,W;if(u=null,E!=null){var Y=dt(E);if(!x.some(function(j){return j.check(Y)}))throw new ReferenceError("Default route doesn't match any known routes")}function I(){D=!1;var j=n.location.hash;g.prefix[0]!=="#"&&(j=n.location.search+j,g.prefix[0]!=="?"&&(j=n.location.pathname+j,j[0]!=="/"&&(j="/"+j)));var H=j.concat().replace(/(?:%[a-f89][a-f0-9])+/gim,decodeURIComponent).slice(g.prefix.length),X=dt(H);Tt(X.params,n.history.state);function K(){if(H===E)throw new Error("Could not resolve default route "+E);c(E,null,{replace:!0})}k(0);function k(B){for(;B{"use strict";var qr=pe();jt.exports=At()(window,qr)});var Dt=O((en,Ot)=>{"use strict";var ge=it(),Rt=xt(),Lt=pe(),F=function(){return ge.apply(this,arguments)};F.m=ge;F.trust=ge.trust;F.fragment=ge.fragment;F.mount=Lt.mount;F.route=zt();F.render=Me();F.redraw=Lt.redraw;F.request=Rt.request;F.jsonp=Rt.jsonp;F.parseQueryString=Fe();F.buildQueryString=He();F.parsePathname=ye();F.buildPathname=me();F.vnode=Z();F.PromisePolyfill=_e();Ot.exports=F});var M=Yt(Dt()),Cr=document.querySelector("nav .search"),It=document.createElement("div");document.querySelector("main").insertBefore(It,document.querySelector(".header"));var $={showingSearchDialog:!1,searchResults:[],searchError:null,searchQuery:""},Er=([n,...i])=>n.toLowerCase()+i.join(""),Pr=([n,...i])=>n.toUpperCase()+i.join(""),Nr=n=>n.split(/[ _]/).map(Er).join("_"),dr=n=>n.split(/[ _]/).map(Pr).join(" "),ue=(n,i)=>{let u=`/${encodeURIComponent(Nr(n))}`;return i&&(u+="/"+i),u},Tr=n=>{if(n.code===0)return;let i=`Server error ${n.code}`;n.message&&(i+=" "+n.message),alert(i)},Ar=n=>{let i=n.target.value;$.searchQuery=i,M.default.request({url:"/api/search",params:{q:i}}).then(u=>{typeof u=="string"?(console.log("ERR",u),$.searchError=u):($.searchResults=u,$.searchError=null)},u=>Tr)},we=dr(decodeURIComponent(/^\/([^/]+)/.exec(location.pathname)[1]).replace(/\+/g," ")),jr=n=>{if(n.keyCode===13){let i=$.searchResults.filter(u=>u.page!==we);i[0]&&(location.href=ue(i[0].page))}},zr={view:()=>M.default(".dialog.search",[M.default("h1","Search"),M.default("input[type=search]",{placeholder:"Query",oninput:Ar,onkeydown:jr,value:$.searchQuery,oncreate:({dom:n})=>n.focus()}),$.searchError&&M.default(".error",$.searchError),M.default("ul",$.searchResults.map(n=>M.default("li",[M.default(".flex-space",[M.default("a.wikilink",{href:ue(n.page)},n.page),M.default("",n.rank.toFixed(3))]),M.default("",n.snippet.map(i=>i[0]?M.default("span.highlight",i[1]):i[1]))])))])},Or={view:()=>M.default("",$.showingSearchDialog?M.default(zr):null)};Cr.addEventListener("click",n=>{$.showingSearchDialog=!$.showingSearchDialog,n.preventDefault(),M.default.redraw()});document.body.addEventListener("keydown",n=>{n.target===document.body&&(n.key==="e"?location.pathname=ue(we,"edit"):n.key==="v"?location.pathname=ue(we):n.key==="r"?location.pathname=ue(we,"revisions"):n.key==="/"&&($.showingSearchDialog=!$.showingSearchDialog,n.preventDefault(),M.default.redraw()))});M.default.mount(It,Or);})(); +//# sourceMappingURL=client.js.map diff --git a/static/client.js.map b/static/client.js.map new file mode 100644 index 0000000..44198b3 --- /dev/null +++ b/static/client.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["../node_modules/mithril/render/vnode.js", "../node_modules/mithril/render/hyperscriptVnode.js", "../node_modules/mithril/render/hyperscript.js", "../node_modules/mithril/render/trust.js", "../node_modules/mithril/render/fragment.js", "../node_modules/mithril/hyperscript.js", "../node_modules/mithril/promise/polyfill.js", "../node_modules/mithril/promise/promise.js", "../node_modules/mithril/render/render.js", "../node_modules/mithril/render.js", "../node_modules/mithril/api/mount-redraw.js", "../node_modules/mithril/mount-redraw.js", "../node_modules/mithril/querystring/build.js", "../node_modules/mithril/pathname/assign.js", "../node_modules/mithril/pathname/build.js", "../node_modules/mithril/request/request.js", "../node_modules/mithril/request.js", "../node_modules/mithril/querystring/parse.js", "../node_modules/mithril/pathname/parse.js", "../node_modules/mithril/pathname/compileTemplate.js", "../node_modules/mithril/api/router.js", "../node_modules/mithril/route.js", "../node_modules/mithril/index.js", "../src/client.js"], + "sourcesContent": ["\"use strict\"\n\nfunction Vnode(tag, key, attrs, children, text, dom) {\n\treturn {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: undefined, events: undefined, instance: undefined}\n}\nVnode.normalize = function(node) {\n\tif (Array.isArray(node)) return Vnode(\"[\", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined)\n\tif (node == null || typeof node === \"boolean\") return null\n\tif (typeof node === \"object\") return node\n\treturn Vnode(\"#\", undefined, undefined, String(node), undefined, undefined)\n}\nVnode.normalizeChildren = function(input) {\n\tvar children = []\n\tif (input.length) {\n\t\tvar isKeyed = input[0] != null && input[0].key != null\n\t\t// Note: this is a *very* perf-sensitive check.\n\t\t// Fun fact: merging the loop like this is somehow faster than splitting\n\t\t// it, noticeably so.\n\t\tfor (var i = 1; i < input.length; i++) {\n\t\t\tif ((input[i] != null && input[i].key != null) !== isKeyed) {\n\t\t\t\tthrow new TypeError(\"Vnodes must either always have keys or never have keys!\")\n\t\t\t}\n\t\t}\n\t\tfor (var i = 0; i < input.length; i++) {\n\t\t\tchildren[i] = Vnode.normalize(input[i])\n\t\t}\n\t}\n\treturn children\n}\n\nmodule.exports = Vnode\n", "\"use strict\"\n\nvar Vnode = require(\"../render/vnode\")\n\n// Call via `hyperscriptVnode.apply(startOffset, arguments)`\n//\n// The reason I do it this way, forwarding the arguments and passing the start\n// offset in `this`, is so I don't have to create a temporary array in a\n// performance-critical path.\n//\n// In native ES6, I'd instead add a final `...args` parameter to the\n// `hyperscript` and `fragment` factories and define this as\n// `hyperscriptVnode(...args)`, since modern engines do optimize that away. But\n// ES5 (what Mithril requires thanks to IE support) doesn't give me that luxury,\n// and engines aren't nearly intelligent enough to do either of these:\n//\n// 1. Elide the allocation for `[].slice.call(arguments, 1)` when it's passed to\n// another function only to be indexed.\n// 2. Elide an `arguments` allocation when it's passed to any function other\n// than `Function.prototype.apply` or `Reflect.apply`.\n//\n// In ES6, it'd probably look closer to this (I'd need to profile it, though):\n// module.exports = function(attrs, ...children) {\n// if (attrs == null || typeof attrs === \"object\" && attrs.tag == null && !Array.isArray(attrs)) {\n// if (children.length === 1 && Array.isArray(children[0])) children = children[0]\n// } else {\n// children = children.length === 0 && Array.isArray(attrs) ? attrs : [attrs, ...children]\n// attrs = undefined\n// }\n//\n// if (attrs == null) attrs = {}\n// return Vnode(\"\", attrs.key, attrs, children)\n// }\nmodule.exports = function() {\n\tvar attrs = arguments[this], start = this + 1, children\n\n\tif (attrs == null) {\n\t\tattrs = {}\n\t} else if (typeof attrs !== \"object\" || attrs.tag != null || Array.isArray(attrs)) {\n\t\tattrs = {}\n\t\tstart = this\n\t}\n\n\tif (arguments.length === start + 1) {\n\t\tchildren = arguments[start]\n\t\tif (!Array.isArray(children)) children = [children]\n\t} else {\n\t\tchildren = []\n\t\twhile (start < arguments.length) children.push(arguments[start++])\n\t}\n\n\treturn Vnode(\"\", attrs.key, attrs, children)\n}\n", "\"use strict\"\n\nvar Vnode = require(\"../render/vnode\")\nvar hyperscriptVnode = require(\"./hyperscriptVnode\")\n\nvar selectorParser = /(?:(^|#|\\.)([^#\\.\\[\\]]+))|(\\[(.+?)(?:\\s*=\\s*(\"|'|)((?:\\\\[\"'\\]]|.)*?)\\5)?\\])/g\nvar selectorCache = {}\nvar hasOwn = {}.hasOwnProperty\n\nfunction isEmpty(object) {\n\tfor (var key in object) if (hasOwn.call(object, key)) return false\n\treturn true\n}\n\nfunction compileSelector(selector) {\n\tvar match, tag = \"div\", classes = [], attrs = {}\n\twhile (match = selectorParser.exec(selector)) {\n\t\tvar type = match[1], value = match[2]\n\t\tif (type === \"\" && value !== \"\") tag = value\n\t\telse if (type === \"#\") attrs.id = value\n\t\telse if (type === \".\") classes.push(value)\n\t\telse if (match[3][0] === \"[\") {\n\t\t\tvar attrValue = match[6]\n\t\t\tif (attrValue) attrValue = attrValue.replace(/\\\\([\"'])/g, \"$1\").replace(/\\\\\\\\/g, \"\\\\\")\n\t\t\tif (match[4] === \"class\") classes.push(attrValue)\n\t\t\telse attrs[match[4]] = attrValue === \"\" ? attrValue : attrValue || true\n\t\t}\n\t}\n\tif (classes.length > 0) attrs.className = classes.join(\" \")\n\treturn selectorCache[selector] = {tag: tag, attrs: attrs}\n}\n\nfunction execSelector(state, vnode) {\n\tvar attrs = vnode.attrs\n\tvar children = Vnode.normalizeChildren(vnode.children)\n\tvar hasClass = hasOwn.call(attrs, \"class\")\n\tvar className = hasClass ? attrs.class : attrs.className\n\n\tvnode.tag = state.tag\n\tvnode.attrs = null\n\tvnode.children = undefined\n\n\tif (!isEmpty(state.attrs) && !isEmpty(attrs)) {\n\t\tvar newAttrs = {}\n\n\t\tfor (var key in attrs) {\n\t\t\tif (hasOwn.call(attrs, key)) newAttrs[key] = attrs[key]\n\t\t}\n\n\t\tattrs = newAttrs\n\t}\n\n\tfor (var key in state.attrs) {\n\t\tif (hasOwn.call(state.attrs, key) && key !== \"className\" && !hasOwn.call(attrs, key)){\n\t\t\tattrs[key] = state.attrs[key]\n\t\t}\n\t}\n\tif (className != null || state.attrs.className != null) attrs.className =\n\t\tclassName != null\n\t\t\t? state.attrs.className != null\n\t\t\t\t? String(state.attrs.className) + \" \" + String(className)\n\t\t\t\t: className\n\t\t\t: state.attrs.className != null\n\t\t\t\t? state.attrs.className\n\t\t\t\t: null\n\n\tif (hasClass) attrs.class = null\n\n\tfor (var key in attrs) {\n\t\tif (hasOwn.call(attrs, key) && key !== \"key\") {\n\t\t\tvnode.attrs = attrs\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif (Array.isArray(children) && children.length === 1 && children[0] != null && children[0].tag === \"#\") {\n\t\tvnode.text = children[0].children\n\t} else {\n\t\tvnode.children = children\n\t}\n\n\treturn vnode\n}\n\nfunction hyperscript(selector) {\n\tif (selector == null || typeof selector !== \"string\" && typeof selector !== \"function\" && typeof selector.view !== \"function\") {\n\t\tthrow Error(\"The selector must be either a string or a component.\");\n\t}\n\n\tvar vnode = hyperscriptVnode.apply(1, arguments)\n\n\tif (typeof selector === \"string\") {\n\t\tvnode.children = Vnode.normalizeChildren(vnode.children)\n\t\tif (selector !== \"[\") return execSelector(selectorCache[selector] || compileSelector(selector), vnode)\n\t}\n\n\tvnode.tag = selector\n\treturn vnode\n}\n\nmodule.exports = hyperscript\n", "\"use strict\"\n\nvar Vnode = require(\"../render/vnode\")\n\nmodule.exports = function(html) {\n\tif (html == null) html = \"\"\n\treturn Vnode(\"<\", undefined, undefined, html, undefined, undefined)\n}\n", "\"use strict\"\n\nvar Vnode = require(\"../render/vnode\")\nvar hyperscriptVnode = require(\"./hyperscriptVnode\")\n\nmodule.exports = function() {\n\tvar vnode = hyperscriptVnode.apply(0, arguments)\n\n\tvnode.tag = \"[\"\n\tvnode.children = Vnode.normalizeChildren(vnode.children)\n\treturn vnode\n}\n", "\"use strict\"\n\nvar hyperscript = require(\"./render/hyperscript\")\n\nhyperscript.trust = require(\"./render/trust\")\nhyperscript.fragment = require(\"./render/fragment\")\n\nmodule.exports = hyperscript\n", "\"use strict\"\n/** @constructor */\nvar PromisePolyfill = function(executor) {\n\tif (!(this instanceof PromisePolyfill)) throw new Error(\"Promise must be called with `new`\")\n\tif (typeof executor !== \"function\") throw new TypeError(\"executor must be a function\")\n\n\tvar self = this, resolvers = [], rejectors = [], resolveCurrent = handler(resolvers, true), rejectCurrent = handler(rejectors, false)\n\tvar instance = self._instance = {resolvers: resolvers, rejectors: rejectors}\n\tvar callAsync = typeof setImmediate === \"function\" ? setImmediate : setTimeout\n\tfunction handler(list, shouldAbsorb) {\n\t\treturn function execute(value) {\n\t\t\tvar then\n\t\t\ttry {\n\t\t\t\tif (shouldAbsorb && value != null && (typeof value === \"object\" || typeof value === \"function\") && typeof (then = value.then) === \"function\") {\n\t\t\t\t\tif (value === self) throw new TypeError(\"Promise can't be resolved w/ itself\")\n\t\t\t\t\texecuteOnce(then.bind(value))\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tcallAsync(function() {\n\t\t\t\t\t\tif (!shouldAbsorb && list.length === 0) console.error(\"Possible unhandled promise rejection:\", value)\n\t\t\t\t\t\tfor (var i = 0; i < list.length; i++) list[i](value)\n\t\t\t\t\t\tresolvers.length = 0, rejectors.length = 0\n\t\t\t\t\t\tinstance.state = shouldAbsorb\n\t\t\t\t\t\tinstance.retry = function() {execute(value)}\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (e) {\n\t\t\t\trejectCurrent(e)\n\t\t\t}\n\t\t}\n\t}\n\tfunction executeOnce(then) {\n\t\tvar runs = 0\n\t\tfunction run(fn) {\n\t\t\treturn function(value) {\n\t\t\t\tif (runs++ > 0) return\n\t\t\t\tfn(value)\n\t\t\t}\n\t\t}\n\t\tvar onerror = run(rejectCurrent)\n\t\ttry {then(run(resolveCurrent), onerror)} catch (e) {onerror(e)}\n\t}\n\n\texecuteOnce(executor)\n}\nPromisePolyfill.prototype.then = function(onFulfilled, onRejection) {\n\tvar self = this, instance = self._instance\n\tfunction handle(callback, list, next, state) {\n\t\tlist.push(function(value) {\n\t\t\tif (typeof callback !== \"function\") next(value)\n\t\t\telse try {resolveNext(callback(value))} catch (e) {if (rejectNext) rejectNext(e)}\n\t\t})\n\t\tif (typeof instance.retry === \"function\" && state === instance.state) instance.retry()\n\t}\n\tvar resolveNext, rejectNext\n\tvar promise = new PromisePolyfill(function(resolve, reject) {resolveNext = resolve, rejectNext = reject})\n\thandle(onFulfilled, instance.resolvers, resolveNext, true), handle(onRejection, instance.rejectors, rejectNext, false)\n\treturn promise\n}\nPromisePolyfill.prototype.catch = function(onRejection) {\n\treturn this.then(null, onRejection)\n}\nPromisePolyfill.prototype.finally = function(callback) {\n\treturn this.then(\n\t\tfunction(value) {\n\t\t\treturn PromisePolyfill.resolve(callback()).then(function() {\n\t\t\t\treturn value\n\t\t\t})\n\t\t},\n\t\tfunction(reason) {\n\t\t\treturn PromisePolyfill.resolve(callback()).then(function() {\n\t\t\t\treturn PromisePolyfill.reject(reason);\n\t\t\t})\n\t\t}\n\t)\n}\nPromisePolyfill.resolve = function(value) {\n\tif (value instanceof PromisePolyfill) return value\n\treturn new PromisePolyfill(function(resolve) {resolve(value)})\n}\nPromisePolyfill.reject = function(value) {\n\treturn new PromisePolyfill(function(resolve, reject) {reject(value)})\n}\nPromisePolyfill.all = function(list) {\n\treturn new PromisePolyfill(function(resolve, reject) {\n\t\tvar total = list.length, count = 0, values = []\n\t\tif (list.length === 0) resolve([])\n\t\telse for (var i = 0; i < list.length; i++) {\n\t\t\t(function(i) {\n\t\t\t\tfunction consume(value) {\n\t\t\t\t\tcount++\n\t\t\t\t\tvalues[i] = value\n\t\t\t\t\tif (count === total) resolve(values)\n\t\t\t\t}\n\t\t\t\tif (list[i] != null && (typeof list[i] === \"object\" || typeof list[i] === \"function\") && typeof list[i].then === \"function\") {\n\t\t\t\t\tlist[i].then(consume, reject)\n\t\t\t\t}\n\t\t\t\telse consume(list[i])\n\t\t\t})(i)\n\t\t}\n\t})\n}\nPromisePolyfill.race = function(list) {\n\treturn new PromisePolyfill(function(resolve, reject) {\n\t\tfor (var i = 0; i < list.length; i++) {\n\t\t\tlist[i].then(resolve, reject)\n\t\t}\n\t})\n}\n\nmodule.exports = PromisePolyfill\n", "\"use strict\"\n\nvar PromisePolyfill = require(\"./polyfill\")\n\nif (typeof window !== \"undefined\") {\n\tif (typeof window.Promise === \"undefined\") {\n\t\twindow.Promise = PromisePolyfill\n\t} else if (!window.Promise.prototype.finally) {\n\t\twindow.Promise.prototype.finally = PromisePolyfill.prototype.finally\n\t}\n\tmodule.exports = window.Promise\n} else if (typeof global !== \"undefined\") {\n\tif (typeof global.Promise === \"undefined\") {\n\t\tglobal.Promise = PromisePolyfill\n\t} else if (!global.Promise.prototype.finally) {\n\t\tglobal.Promise.prototype.finally = PromisePolyfill.prototype.finally\n\t}\n\tmodule.exports = global.Promise\n} else {\n\tmodule.exports = PromisePolyfill\n}\n", "\"use strict\"\n\nvar Vnode = require(\"../render/vnode\")\n\nmodule.exports = function($window) {\n\tvar $doc = $window && $window.document\n\tvar currentRedraw\n\n\tvar nameSpace = {\n\t\tsvg: \"http://www.w3.org/2000/svg\",\n\t\tmath: \"http://www.w3.org/1998/Math/MathML\"\n\t}\n\n\tfunction getNameSpace(vnode) {\n\t\treturn vnode.attrs && vnode.attrs.xmlns || nameSpace[vnode.tag]\n\t}\n\n\t//sanity check to discourage people from doing `vnode.state = ...`\n\tfunction checkState(vnode, original) {\n\t\tif (vnode.state !== original) throw new Error(\"`vnode.state` must not be modified\")\n\t}\n\n\t//Note: the hook is passed as the `this` argument to allow proxying the\n\t//arguments without requiring a full array allocation to do so. It also\n\t//takes advantage of the fact the current `vnode` is the first argument in\n\t//all lifecycle methods.\n\tfunction callHook(vnode) {\n\t\tvar original = vnode.state\n\t\ttry {\n\t\t\treturn this.apply(original, arguments)\n\t\t} finally {\n\t\t\tcheckState(vnode, original)\n\t\t}\n\t}\n\n\t// IE11 (at least) throws an UnspecifiedError when accessing document.activeElement when\n\t// inside an iframe. Catch and swallow this error, and heavy-handidly return null.\n\tfunction activeElement() {\n\t\ttry {\n\t\t\treturn $doc.activeElement\n\t\t} catch (e) {\n\t\t\treturn null\n\t\t}\n\t}\n\t//create\n\tfunction createNodes(parent, vnodes, start, end, hooks, nextSibling, ns) {\n\t\tfor (var i = start; i < end; i++) {\n\t\t\tvar vnode = vnodes[i]\n\t\t\tif (vnode != null) {\n\t\t\t\tcreateNode(parent, vnode, hooks, ns, nextSibling)\n\t\t\t}\n\t\t}\n\t}\n\tfunction createNode(parent, vnode, hooks, ns, nextSibling) {\n\t\tvar tag = vnode.tag\n\t\tif (typeof tag === \"string\") {\n\t\t\tvnode.state = {}\n\t\t\tif (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)\n\t\t\tswitch (tag) {\n\t\t\t\tcase \"#\": createText(parent, vnode, nextSibling); break\n\t\t\t\tcase \"<\": createHTML(parent, vnode, ns, nextSibling); break\n\t\t\t\tcase \"[\": createFragment(parent, vnode, hooks, ns, nextSibling); break\n\t\t\t\tdefault: createElement(parent, vnode, hooks, ns, nextSibling)\n\t\t\t}\n\t\t}\n\t\telse createComponent(parent, vnode, hooks, ns, nextSibling)\n\t}\n\tfunction createText(parent, vnode, nextSibling) {\n\t\tvnode.dom = $doc.createTextNode(vnode.children)\n\t\tinsertNode(parent, vnode.dom, nextSibling)\n\t}\n\tvar possibleParents = {caption: \"table\", thead: \"table\", tbody: \"table\", tfoot: \"table\", tr: \"tbody\", th: \"tr\", td: \"tr\", colgroup: \"table\", col: \"colgroup\"}\n\tfunction createHTML(parent, vnode, ns, nextSibling) {\n\t\tvar match = vnode.children.match(/^\\s*?<(\\w+)/im) || []\n\t\t// not using the proper parent makes the child element(s) vanish.\n\t\t// var div = document.createElement(\"div\")\n\t\t// div.innerHTML = \"ij\"\n\t\t// console.log(div.innerHTML)\n\t\t// --> \"ij\", no in sight.\n\t\tvar temp = $doc.createElement(possibleParents[match[1]] || \"div\")\n\t\tif (ns === \"http://www.w3.org/2000/svg\") {\n\t\t\ttemp.innerHTML = \"\" + vnode.children + \"\"\n\t\t\ttemp = temp.firstChild\n\t\t} else {\n\t\t\ttemp.innerHTML = vnode.children\n\t\t}\n\t\tvnode.dom = temp.firstChild\n\t\tvnode.domSize = temp.childNodes.length\n\t\t// Capture nodes to remove, so we don't confuse them.\n\t\tvnode.instance = []\n\t\tvar fragment = $doc.createDocumentFragment()\n\t\tvar child\n\t\twhile (child = temp.firstChild) {\n\t\t\tvnode.instance.push(child)\n\t\t\tfragment.appendChild(child)\n\t\t}\n\t\tinsertNode(parent, fragment, nextSibling)\n\t}\n\tfunction createFragment(parent, vnode, hooks, ns, nextSibling) {\n\t\tvar fragment = $doc.createDocumentFragment()\n\t\tif (vnode.children != null) {\n\t\t\tvar children = vnode.children\n\t\t\tcreateNodes(fragment, children, 0, children.length, hooks, null, ns)\n\t\t}\n\t\tvnode.dom = fragment.firstChild\n\t\tvnode.domSize = fragment.childNodes.length\n\t\tinsertNode(parent, fragment, nextSibling)\n\t}\n\tfunction createElement(parent, vnode, hooks, ns, nextSibling) {\n\t\tvar tag = vnode.tag\n\t\tvar attrs = vnode.attrs\n\t\tvar is = attrs && attrs.is\n\n\t\tns = getNameSpace(vnode) || ns\n\n\t\tvar element = ns ?\n\t\t\tis ? $doc.createElementNS(ns, tag, {is: is}) : $doc.createElementNS(ns, tag) :\n\t\t\tis ? $doc.createElement(tag, {is: is}) : $doc.createElement(tag)\n\t\tvnode.dom = element\n\n\t\tif (attrs != null) {\n\t\t\tsetAttrs(vnode, attrs, ns)\n\t\t}\n\n\t\tinsertNode(parent, element, nextSibling)\n\n\t\tif (!maybeSetContentEditable(vnode)) {\n\t\t\tif (vnode.text != null) {\n\t\t\t\tif (vnode.text !== \"\") element.textContent = vnode.text\n\t\t\t\telse vnode.children = [Vnode(\"#\", undefined, undefined, vnode.text, undefined, undefined)]\n\t\t\t}\n\t\t\tif (vnode.children != null) {\n\t\t\t\tvar children = vnode.children\n\t\t\t\tcreateNodes(element, children, 0, children.length, hooks, null, ns)\n\t\t\t\tif (vnode.tag === \"select\" && attrs != null) setLateSelectAttrs(vnode, attrs)\n\t\t\t}\n\t\t}\n\t}\n\tfunction initComponent(vnode, hooks) {\n\t\tvar sentinel\n\t\tif (typeof vnode.tag.view === \"function\") {\n\t\t\tvnode.state = Object.create(vnode.tag)\n\t\t\tsentinel = vnode.state.view\n\t\t\tif (sentinel.$$reentrantLock$$ != null) return\n\t\t\tsentinel.$$reentrantLock$$ = true\n\t\t} else {\n\t\t\tvnode.state = void 0\n\t\t\tsentinel = vnode.tag\n\t\t\tif (sentinel.$$reentrantLock$$ != null) return\n\t\t\tsentinel.$$reentrantLock$$ = true\n\t\t\tvnode.state = (vnode.tag.prototype != null && typeof vnode.tag.prototype.view === \"function\") ? new vnode.tag(vnode) : vnode.tag(vnode)\n\t\t}\n\t\tinitLifecycle(vnode.state, vnode, hooks)\n\t\tif (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)\n\t\tvnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode))\n\t\tif (vnode.instance === vnode) throw Error(\"A view cannot return the vnode it received as argument\")\n\t\tsentinel.$$reentrantLock$$ = null\n\t}\n\tfunction createComponent(parent, vnode, hooks, ns, nextSibling) {\n\t\tinitComponent(vnode, hooks)\n\t\tif (vnode.instance != null) {\n\t\t\tcreateNode(parent, vnode.instance, hooks, ns, nextSibling)\n\t\t\tvnode.dom = vnode.instance.dom\n\t\t\tvnode.domSize = vnode.dom != null ? vnode.instance.domSize : 0\n\t\t}\n\t\telse {\n\t\t\tvnode.domSize = 0\n\t\t}\n\t}\n\n\t//update\n\t/**\n\t * @param {Element|Fragment} parent - the parent element\n\t * @param {Vnode[] | null} old - the list of vnodes of the last `render()` call for\n\t * this part of the tree\n\t * @param {Vnode[] | null} vnodes - as above, but for the current `render()` call.\n\t * @param {Function[]} hooks - an accumulator of post-render hooks (oncreate/onupdate)\n\t * @param {Element | null} nextSibling - the next DOM node if we're dealing with a\n\t * fragment that is not the last item in its\n\t * parent\n\t * @param {'svg' | 'math' | String | null} ns) - the current XML namespace, if any\n\t * @returns void\n\t */\n\t// This function diffs and patches lists of vnodes, both keyed and unkeyed.\n\t//\n\t// We will:\n\t//\n\t// 1. describe its general structure\n\t// 2. focus on the diff algorithm optimizations\n\t// 3. discuss DOM node operations.\n\n\t// ## Overview:\n\t//\n\t// The updateNodes() function:\n\t// - deals with trivial cases\n\t// - determines whether the lists are keyed or unkeyed based on the first non-null node\n\t// of each list.\n\t// - diffs them and patches the DOM if needed (that's the brunt of the code)\n\t// - manages the leftovers: after diffing, are there:\n\t// - old nodes left to remove?\n\t// \t - new nodes to insert?\n\t// \t deal with them!\n\t//\n\t// The lists are only iterated over once, with an exception for the nodes in `old` that\n\t// are visited in the fourth part of the diff and in the `removeNodes` loop.\n\n\t// ## Diffing\n\t//\n\t// Reading https://github.com/localvoid/ivi/blob/ddc09d06abaef45248e6133f7040d00d3c6be853/packages/ivi/src/vdom/implementation.ts#L617-L837\n\t// may be good for context on longest increasing subsequence-based logic for moving nodes.\n\t//\n\t// In order to diff keyed lists, one has to\n\t//\n\t// 1) match nodes in both lists, per key, and update them accordingly\n\t// 2) create the nodes present in the new list, but absent in the old one\n\t// 3) remove the nodes present in the old list, but absent in the new one\n\t// 4) figure out what nodes in 1) to move in order to minimize the DOM operations.\n\t//\n\t// To achieve 1) one can create a dictionary of keys => index (for the old list), then iterate\n\t// over the new list and for each new vnode, find the corresponding vnode in the old list using\n\t// the map.\n\t// 2) is achieved in the same step: if a new node has no corresponding entry in the map, it is new\n\t// and must be created.\n\t// For the removals, we actually remove the nodes that have been updated from the old list.\n\t// The nodes that remain in that list after 1) and 2) have been performed can be safely removed.\n\t// The fourth step is a bit more complex and relies on the longest increasing subsequence (LIS)\n\t// algorithm.\n\t//\n\t// the longest increasing subsequence is the list of nodes that can remain in place. Imagine going\n\t// from `1,2,3,4,5` to `4,5,1,2,3` where the numbers are not necessarily the keys, but the indices\n\t// corresponding to the keyed nodes in the old list (keyed nodes `e,d,c,b,a` => `b,a,e,d,c` would\n\t// match the above lists, for example).\n\t//\n\t// In there are two increasing subsequences: `4,5` and `1,2,3`, the latter being the longest. We\n\t// can update those nodes without moving them, and only call `insertNode` on `4` and `5`.\n\t//\n\t// @localvoid adapted the algo to also support node deletions and insertions (the `lis` is actually\n\t// the longest increasing subsequence *of old nodes still present in the new list*).\n\t//\n\t// It is a general algorithm that is fireproof in all circumstances, but it requires the allocation\n\t// and the construction of a `key => oldIndex` map, and three arrays (one with `newIndex => oldIndex`,\n\t// the `LIS` and a temporary one to create the LIS).\n\t//\n\t// So we cheat where we can: if the tails of the lists are identical, they are guaranteed to be part of\n\t// the LIS and can be updated without moving them.\n\t//\n\t// If two nodes are swapped, they are guaranteed not to be part of the LIS, and must be moved (with\n\t// the exception of the last node if the list is fully reversed).\n\t//\n\t// ## Finding the next sibling.\n\t//\n\t// `updateNode()` and `createNode()` expect a nextSibling parameter to perform DOM operations.\n\t// When the list is being traversed top-down, at any index, the DOM nodes up to the previous\n\t// vnode reflect the content of the new list, whereas the rest of the DOM nodes reflect the old\n\t// list. The next sibling must be looked for in the old list using `getNextSibling(... oldStart + 1 ...)`.\n\t//\n\t// In the other scenarios (swaps, upwards traversal, map-based diff),\n\t// the new vnodes list is traversed upwards. The DOM nodes at the bottom of the list reflect the\n\t// bottom part of the new vnodes list, and we can use the `v.dom` value of the previous node\n\t// as the next sibling (cached in the `nextSibling` variable).\n\n\n\t// ## DOM node moves\n\t//\n\t// In most scenarios `updateNode()` and `createNode()` perform the DOM operations. However,\n\t// this is not the case if the node moved (second and fourth part of the diff algo). We move\n\t// the old DOM nodes before updateNode runs because it enables us to use the cached `nextSibling`\n\t// variable rather than fetching it using `getNextSibling()`.\n\t//\n\t// The fourth part of the diff currently inserts nodes unconditionally, leading to issues\n\t// like #1791 and #1999. We need to be smarter about those situations where adjascent old\n\t// nodes remain together in the new list in a way that isn't covered by parts one and\n\t// three of the diff algo.\n\n\tfunction updateNodes(parent, old, vnodes, hooks, nextSibling, ns) {\n\t\tif (old === vnodes || old == null && vnodes == null) return\n\t\telse if (old == null || old.length === 0) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, ns)\n\t\telse if (vnodes == null || vnodes.length === 0) removeNodes(parent, old, 0, old.length)\n\t\telse {\n\t\t\tvar isOldKeyed = old[0] != null && old[0].key != null\n\t\t\tvar isKeyed = vnodes[0] != null && vnodes[0].key != null\n\t\t\tvar start = 0, oldStart = 0\n\t\t\tif (!isOldKeyed) while (oldStart < old.length && old[oldStart] == null) oldStart++\n\t\t\tif (!isKeyed) while (start < vnodes.length && vnodes[start] == null) start++\n\t\t\tif (isKeyed === null && isOldKeyed == null) return // both lists are full of nulls\n\t\t\tif (isOldKeyed !== isKeyed) {\n\t\t\t\tremoveNodes(parent, old, oldStart, old.length)\n\t\t\t\tcreateNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns)\n\t\t\t} else if (!isKeyed) {\n\t\t\t\t// Don't index past the end of either list (causes deopts).\n\t\t\t\tvar commonLength = old.length < vnodes.length ? old.length : vnodes.length\n\t\t\t\t// Rewind if necessary to the first non-null index on either side.\n\t\t\t\t// We could alternatively either explicitly create or remove nodes when `start !== oldStart`\n\t\t\t\t// but that would be optimizing for sparse lists which are more rare than dense ones.\n\t\t\t\tstart = start < oldStart ? start : oldStart\n\t\t\t\tfor (; start < commonLength; start++) {\n\t\t\t\t\to = old[start]\n\t\t\t\t\tv = vnodes[start]\n\t\t\t\t\tif (o === v || o == null && v == null) continue\n\t\t\t\t\telse if (o == null) createNode(parent, v, hooks, ns, getNextSibling(old, start + 1, nextSibling))\n\t\t\t\t\telse if (v == null) removeNode(parent, o)\n\t\t\t\t\telse updateNode(parent, o, v, hooks, getNextSibling(old, start + 1, nextSibling), ns)\n\t\t\t\t}\n\t\t\t\tif (old.length > commonLength) removeNodes(parent, old, start, old.length)\n\t\t\t\tif (vnodes.length > commonLength) createNodes(parent, vnodes, start, vnodes.length, hooks, nextSibling, ns)\n\t\t\t} else {\n\t\t\t\t// keyed diff\n\t\t\t\tvar oldEnd = old.length - 1, end = vnodes.length - 1, map, o, v, oe, ve, topSibling\n\n\t\t\t\t// bottom-up\n\t\t\t\twhile (oldEnd >= oldStart && end >= start) {\n\t\t\t\t\toe = old[oldEnd]\n\t\t\t\t\tve = vnodes[end]\n\t\t\t\t\tif (oe.key !== ve.key) break\n\t\t\t\t\tif (oe !== ve) updateNode(parent, oe, ve, hooks, nextSibling, ns)\n\t\t\t\t\tif (ve.dom != null) nextSibling = ve.dom\n\t\t\t\t\toldEnd--, end--\n\t\t\t\t}\n\t\t\t\t// top-down\n\t\t\t\twhile (oldEnd >= oldStart && end >= start) {\n\t\t\t\t\to = old[oldStart]\n\t\t\t\t\tv = vnodes[start]\n\t\t\t\t\tif (o.key !== v.key) break\n\t\t\t\t\toldStart++, start++\n\t\t\t\t\tif (o !== v) updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), ns)\n\t\t\t\t}\n\t\t\t\t// swaps and list reversals\n\t\t\t\twhile (oldEnd >= oldStart && end >= start) {\n\t\t\t\t\tif (start === end) break\n\t\t\t\t\tif (o.key !== ve.key || oe.key !== v.key) break\n\t\t\t\t\ttopSibling = getNextSibling(old, oldStart, nextSibling)\n\t\t\t\t\tmoveNodes(parent, oe, topSibling)\n\t\t\t\t\tif (oe !== v) updateNode(parent, oe, v, hooks, topSibling, ns)\n\t\t\t\t\tif (++start <= --end) moveNodes(parent, o, nextSibling)\n\t\t\t\t\tif (o !== ve) updateNode(parent, o, ve, hooks, nextSibling, ns)\n\t\t\t\t\tif (ve.dom != null) nextSibling = ve.dom\n\t\t\t\t\toldStart++; oldEnd--\n\t\t\t\t\toe = old[oldEnd]\n\t\t\t\t\tve = vnodes[end]\n\t\t\t\t\to = old[oldStart]\n\t\t\t\t\tv = vnodes[start]\n\t\t\t\t}\n\t\t\t\t// bottom up once again\n\t\t\t\twhile (oldEnd >= oldStart && end >= start) {\n\t\t\t\t\tif (oe.key !== ve.key) break\n\t\t\t\t\tif (oe !== ve) updateNode(parent, oe, ve, hooks, nextSibling, ns)\n\t\t\t\t\tif (ve.dom != null) nextSibling = ve.dom\n\t\t\t\t\toldEnd--, end--\n\t\t\t\t\toe = old[oldEnd]\n\t\t\t\t\tve = vnodes[end]\n\t\t\t\t}\n\t\t\t\tif (start > end) removeNodes(parent, old, oldStart, oldEnd + 1)\n\t\t\t\telse if (oldStart > oldEnd) createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns)\n\t\t\t\telse {\n\t\t\t\t\t// inspired by ivi https://github.com/ivijs/ivi/ by Boris Kaul\n\t\t\t\t\tvar originalNextSibling = nextSibling, vnodesLength = end - start + 1, oldIndices = new Array(vnodesLength), li=0, i=0, pos = 2147483647, matched = 0, map, lisIndices\n\t\t\t\t\tfor (i = 0; i < vnodesLength; i++) oldIndices[i] = -1\n\t\t\t\t\tfor (i = end; i >= start; i--) {\n\t\t\t\t\t\tif (map == null) map = getKeyMap(old, oldStart, oldEnd + 1)\n\t\t\t\t\t\tve = vnodes[i]\n\t\t\t\t\t\tvar oldIndex = map[ve.key]\n\t\t\t\t\t\tif (oldIndex != null) {\n\t\t\t\t\t\t\tpos = (oldIndex < pos) ? oldIndex : -1 // becomes -1 if nodes were re-ordered\n\t\t\t\t\t\t\toldIndices[i-start] = oldIndex\n\t\t\t\t\t\t\toe = old[oldIndex]\n\t\t\t\t\t\t\told[oldIndex] = null\n\t\t\t\t\t\t\tif (oe !== ve) updateNode(parent, oe, ve, hooks, nextSibling, ns)\n\t\t\t\t\t\t\tif (ve.dom != null) nextSibling = ve.dom\n\t\t\t\t\t\t\tmatched++\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tnextSibling = originalNextSibling\n\t\t\t\t\tif (matched !== oldEnd - oldStart + 1) removeNodes(parent, old, oldStart, oldEnd + 1)\n\t\t\t\t\tif (matched === 0) createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns)\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (pos === -1) {\n\t\t\t\t\t\t\t// the indices of the indices of the items that are part of the\n\t\t\t\t\t\t\t// longest increasing subsequence in the oldIndices list\n\t\t\t\t\t\t\tlisIndices = makeLisIndices(oldIndices)\n\t\t\t\t\t\t\tli = lisIndices.length - 1\n\t\t\t\t\t\t\tfor (i = end; i >= start; i--) {\n\t\t\t\t\t\t\t\tv = vnodes[i]\n\t\t\t\t\t\t\t\tif (oldIndices[i-start] === -1) createNode(parent, v, hooks, ns, nextSibling)\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tif (lisIndices[li] === i - start) li--\n\t\t\t\t\t\t\t\t\telse moveNodes(parent, v, nextSibling)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (v.dom != null) nextSibling = vnodes[i].dom\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tfor (i = end; i >= start; i--) {\n\t\t\t\t\t\t\t\tv = vnodes[i]\n\t\t\t\t\t\t\t\tif (oldIndices[i-start] === -1) createNode(parent, v, hooks, ns, nextSibling)\n\t\t\t\t\t\t\t\tif (v.dom != null) nextSibling = vnodes[i].dom\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfunction updateNode(parent, old, vnode, hooks, nextSibling, ns) {\n\t\tvar oldTag = old.tag, tag = vnode.tag\n\t\tif (oldTag === tag) {\n\t\t\tvnode.state = old.state\n\t\t\tvnode.events = old.events\n\t\t\tif (shouldNotUpdate(vnode, old)) return\n\t\t\tif (typeof oldTag === \"string\") {\n\t\t\t\tif (vnode.attrs != null) {\n\t\t\t\t\tupdateLifecycle(vnode.attrs, vnode, hooks)\n\t\t\t\t}\n\t\t\t\tswitch (oldTag) {\n\t\t\t\t\tcase \"#\": updateText(old, vnode); break\n\t\t\t\t\tcase \"<\": updateHTML(parent, old, vnode, ns, nextSibling); break\n\t\t\t\t\tcase \"[\": updateFragment(parent, old, vnode, hooks, nextSibling, ns); break\n\t\t\t\t\tdefault: updateElement(old, vnode, hooks, ns)\n\t\t\t\t}\n\t\t\t}\n\t\t\telse updateComponent(parent, old, vnode, hooks, nextSibling, ns)\n\t\t}\n\t\telse {\n\t\t\tremoveNode(parent, old)\n\t\t\tcreateNode(parent, vnode, hooks, ns, nextSibling)\n\t\t}\n\t}\n\tfunction updateText(old, vnode) {\n\t\tif (old.children.toString() !== vnode.children.toString()) {\n\t\t\told.dom.nodeValue = vnode.children\n\t\t}\n\t\tvnode.dom = old.dom\n\t}\n\tfunction updateHTML(parent, old, vnode, ns, nextSibling) {\n\t\tif (old.children !== vnode.children) {\n\t\t\tremoveHTML(parent, old)\n\t\t\tcreateHTML(parent, vnode, ns, nextSibling)\n\t\t}\n\t\telse {\n\t\t\tvnode.dom = old.dom\n\t\t\tvnode.domSize = old.domSize\n\t\t\tvnode.instance = old.instance\n\t\t}\n\t}\n\tfunction updateFragment(parent, old, vnode, hooks, nextSibling, ns) {\n\t\tupdateNodes(parent, old.children, vnode.children, hooks, nextSibling, ns)\n\t\tvar domSize = 0, children = vnode.children\n\t\tvnode.dom = null\n\t\tif (children != null) {\n\t\t\tfor (var i = 0; i < children.length; i++) {\n\t\t\t\tvar child = children[i]\n\t\t\t\tif (child != null && child.dom != null) {\n\t\t\t\t\tif (vnode.dom == null) vnode.dom = child.dom\n\t\t\t\t\tdomSize += child.domSize || 1\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (domSize !== 1) vnode.domSize = domSize\n\t\t}\n\t}\n\tfunction updateElement(old, vnode, hooks, ns) {\n\t\tvar element = vnode.dom = old.dom\n\t\tns = getNameSpace(vnode) || ns\n\n\t\tif (vnode.tag === \"textarea\") {\n\t\t\tif (vnode.attrs == null) vnode.attrs = {}\n\t\t\tif (vnode.text != null) {\n\t\t\t\tvnode.attrs.value = vnode.text //FIXME handle multiple children\n\t\t\t\tvnode.text = undefined\n\t\t\t}\n\t\t}\n\t\tupdateAttrs(vnode, old.attrs, vnode.attrs, ns)\n\t\tif (!maybeSetContentEditable(vnode)) {\n\t\t\tif (old.text != null && vnode.text != null && vnode.text !== \"\") {\n\t\t\t\tif (old.text.toString() !== vnode.text.toString()) old.dom.firstChild.nodeValue = vnode.text\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (old.text != null) old.children = [Vnode(\"#\", undefined, undefined, old.text, undefined, old.dom.firstChild)]\n\t\t\t\tif (vnode.text != null) vnode.children = [Vnode(\"#\", undefined, undefined, vnode.text, undefined, undefined)]\n\t\t\t\tupdateNodes(element, old.children, vnode.children, hooks, null, ns)\n\t\t\t}\n\t\t}\n\t}\n\tfunction updateComponent(parent, old, vnode, hooks, nextSibling, ns) {\n\t\tvnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode))\n\t\tif (vnode.instance === vnode) throw Error(\"A view cannot return the vnode it received as argument\")\n\t\tupdateLifecycle(vnode.state, vnode, hooks)\n\t\tif (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks)\n\t\tif (vnode.instance != null) {\n\t\t\tif (old.instance == null) createNode(parent, vnode.instance, hooks, ns, nextSibling)\n\t\t\telse updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, ns)\n\t\t\tvnode.dom = vnode.instance.dom\n\t\t\tvnode.domSize = vnode.instance.domSize\n\t\t}\n\t\telse if (old.instance != null) {\n\t\t\tremoveNode(parent, old.instance)\n\t\t\tvnode.dom = undefined\n\t\t\tvnode.domSize = 0\n\t\t}\n\t\telse {\n\t\t\tvnode.dom = old.dom\n\t\t\tvnode.domSize = old.domSize\n\t\t}\n\t}\n\tfunction getKeyMap(vnodes, start, end) {\n\t\tvar map = Object.create(null)\n\t\tfor (; start < end; start++) {\n\t\t\tvar vnode = vnodes[start]\n\t\t\tif (vnode != null) {\n\t\t\t\tvar key = vnode.key\n\t\t\t\tif (key != null) map[key] = start\n\t\t\t}\n\t\t}\n\t\treturn map\n\t}\n\t// Lifted from ivi https://github.com/ivijs/ivi/\n\t// takes a list of unique numbers (-1 is special and can\n\t// occur multiple times) and returns an array with the indices\n\t// of the items that are part of the longest increasing\n\t// subsequece\n\tvar lisTemp = []\n\tfunction makeLisIndices(a) {\n\t\tvar result = [0]\n\t\tvar u = 0, v = 0, i = 0\n\t\tvar il = lisTemp.length = a.length\n\t\tfor (var i = 0; i < il; i++) lisTemp[i] = a[i]\n\t\tfor (var i = 0; i < il; ++i) {\n\t\t\tif (a[i] === -1) continue\n\t\t\tvar j = result[result.length - 1]\n\t\t\tif (a[j] < a[i]) {\n\t\t\t\tlisTemp[i] = j\n\t\t\t\tresult.push(i)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tu = 0\n\t\t\tv = result.length - 1\n\t\t\twhile (u < v) {\n\t\t\t\t// Fast integer average without overflow.\n\t\t\t\t// eslint-disable-next-line no-bitwise\n\t\t\t\tvar c = (u >>> 1) + (v >>> 1) + (u & v & 1)\n\t\t\t\tif (a[result[c]] < a[i]) {\n\t\t\t\t\tu = c + 1\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tv = c\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (a[i] < a[result[u]]) {\n\t\t\t\tif (u > 0) lisTemp[i] = result[u - 1]\n\t\t\t\tresult[u] = i\n\t\t\t}\n\t\t}\n\t\tu = result.length\n\t\tv = result[u - 1]\n\t\twhile (u-- > 0) {\n\t\t\tresult[u] = v\n\t\t\tv = lisTemp[v]\n\t\t}\n\t\tlisTemp.length = 0\n\t\treturn result\n\t}\n\n\tfunction getNextSibling(vnodes, i, nextSibling) {\n\t\tfor (; i < vnodes.length; i++) {\n\t\t\tif (vnodes[i] != null && vnodes[i].dom != null) return vnodes[i].dom\n\t\t}\n\t\treturn nextSibling\n\t}\n\n\t// This covers a really specific edge case:\n\t// - Parent node is keyed and contains child\n\t// - Child is removed, returns unresolved promise in `onbeforeremove`\n\t// - Parent node is moved in keyed diff\n\t// - Remaining children still need moved appropriately\n\t//\n\t// Ideally, I'd track removed nodes as well, but that introduces a lot more\n\t// complexity and I'm not exactly interested in doing that.\n\tfunction moveNodes(parent, vnode, nextSibling) {\n\t\tvar frag = $doc.createDocumentFragment()\n\t\tmoveChildToFrag(parent, frag, vnode)\n\t\tinsertNode(parent, frag, nextSibling)\n\t}\n\tfunction moveChildToFrag(parent, frag, vnode) {\n\t\t// Dodge the recursion overhead in a few of the most common cases.\n\t\twhile (vnode.dom != null && vnode.dom.parentNode === parent) {\n\t\t\tif (typeof vnode.tag !== \"string\") {\n\t\t\t\tvnode = vnode.instance\n\t\t\t\tif (vnode != null) continue\n\t\t\t} else if (vnode.tag === \"<\") {\n\t\t\t\tfor (var i = 0; i < vnode.instance.length; i++) {\n\t\t\t\t\tfrag.appendChild(vnode.instance[i])\n\t\t\t\t}\n\t\t\t} else if (vnode.tag !== \"[\") {\n\t\t\t\t// Don't recurse for text nodes *or* elements, just fragments\n\t\t\t\tfrag.appendChild(vnode.dom)\n\t\t\t} else if (vnode.children.length === 1) {\n\t\t\t\tvnode = vnode.children[0]\n\t\t\t\tif (vnode != null) continue\n\t\t\t} else {\n\t\t\t\tfor (var i = 0; i < vnode.children.length; i++) {\n\t\t\t\t\tvar child = vnode.children[i]\n\t\t\t\t\tif (child != null) moveChildToFrag(parent, frag, child)\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\n\tfunction insertNode(parent, dom, nextSibling) {\n\t\tif (nextSibling != null) parent.insertBefore(dom, nextSibling)\n\t\telse parent.appendChild(dom)\n\t}\n\n\tfunction maybeSetContentEditable(vnode) {\n\t\tif (vnode.attrs == null || (\n\t\t\tvnode.attrs.contenteditable == null && // attribute\n\t\t\tvnode.attrs.contentEditable == null // property\n\t\t)) return false\n\t\tvar children = vnode.children\n\t\tif (children != null && children.length === 1 && children[0].tag === \"<\") {\n\t\t\tvar content = children[0].children\n\t\t\tif (vnode.dom.innerHTML !== content) vnode.dom.innerHTML = content\n\t\t}\n\t\telse if (vnode.text != null || children != null && children.length !== 0) throw new Error(\"Child node of a contenteditable must be trusted\")\n\t\treturn true\n\t}\n\n\t//remove\n\tfunction removeNodes(parent, vnodes, start, end) {\n\t\tfor (var i = start; i < end; i++) {\n\t\t\tvar vnode = vnodes[i]\n\t\t\tif (vnode != null) removeNode(parent, vnode)\n\t\t}\n\t}\n\tfunction removeNode(parent, vnode) {\n\t\tvar mask = 0\n\t\tvar original = vnode.state\n\t\tvar stateResult, attrsResult\n\t\tif (typeof vnode.tag !== \"string\" && typeof vnode.state.onbeforeremove === \"function\") {\n\t\t\tvar result = callHook.call(vnode.state.onbeforeremove, vnode)\n\t\t\tif (result != null && typeof result.then === \"function\") {\n\t\t\t\tmask = 1\n\t\t\t\tstateResult = result\n\t\t\t}\n\t\t}\n\t\tif (vnode.attrs && typeof vnode.attrs.onbeforeremove === \"function\") {\n\t\t\tvar result = callHook.call(vnode.attrs.onbeforeremove, vnode)\n\t\t\tif (result != null && typeof result.then === \"function\") {\n\t\t\t\t// eslint-disable-next-line no-bitwise\n\t\t\t\tmask |= 2\n\t\t\t\tattrsResult = result\n\t\t\t}\n\t\t}\n\t\tcheckState(vnode, original)\n\n\t\t// If we can, try to fast-path it and avoid all the overhead of awaiting\n\t\tif (!mask) {\n\t\t\tonremove(vnode)\n\t\t\tremoveChild(parent, vnode)\n\t\t} else {\n\t\t\tif (stateResult != null) {\n\t\t\t\tvar next = function () {\n\t\t\t\t\t// eslint-disable-next-line no-bitwise\n\t\t\t\t\tif (mask & 1) { mask &= 2; if (!mask) reallyRemove() }\n\t\t\t\t}\n\t\t\t\tstateResult.then(next, next)\n\t\t\t}\n\t\t\tif (attrsResult != null) {\n\t\t\t\tvar next = function () {\n\t\t\t\t\t// eslint-disable-next-line no-bitwise\n\t\t\t\t\tif (mask & 2) { mask &= 1; if (!mask) reallyRemove() }\n\t\t\t\t}\n\t\t\t\tattrsResult.then(next, next)\n\t\t\t}\n\t\t}\n\n\t\tfunction reallyRemove() {\n\t\t\tcheckState(vnode, original)\n\t\t\tonremove(vnode)\n\t\t\tremoveChild(parent, vnode)\n\t\t}\n\t}\n\tfunction removeHTML(parent, vnode) {\n\t\tfor (var i = 0; i < vnode.instance.length; i++) {\n\t\t\tparent.removeChild(vnode.instance[i])\n\t\t}\n\t}\n\tfunction removeChild(parent, vnode) {\n\t\t// Dodge the recursion overhead in a few of the most common cases.\n\t\twhile (vnode.dom != null && vnode.dom.parentNode === parent) {\n\t\t\tif (typeof vnode.tag !== \"string\") {\n\t\t\t\tvnode = vnode.instance\n\t\t\t\tif (vnode != null) continue\n\t\t\t} else if (vnode.tag === \"<\") {\n\t\t\t\tremoveHTML(parent, vnode)\n\t\t\t} else {\n\t\t\t\tif (vnode.tag !== \"[\") {\n\t\t\t\t\tparent.removeChild(vnode.dom)\n\t\t\t\t\tif (!Array.isArray(vnode.children)) break\n\t\t\t\t}\n\t\t\t\tif (vnode.children.length === 1) {\n\t\t\t\t\tvnode = vnode.children[0]\n\t\t\t\t\tif (vnode != null) continue\n\t\t\t\t} else {\n\t\t\t\t\tfor (var i = 0; i < vnode.children.length; i++) {\n\t\t\t\t\t\tvar child = vnode.children[i]\n\t\t\t\t\t\tif (child != null) removeChild(parent, child)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\tfunction onremove(vnode) {\n\t\tif (typeof vnode.tag !== \"string\" && typeof vnode.state.onremove === \"function\") callHook.call(vnode.state.onremove, vnode)\n\t\tif (vnode.attrs && typeof vnode.attrs.onremove === \"function\") callHook.call(vnode.attrs.onremove, vnode)\n\t\tif (typeof vnode.tag !== \"string\") {\n\t\t\tif (vnode.instance != null) onremove(vnode.instance)\n\t\t} else {\n\t\t\tvar children = vnode.children\n\t\t\tif (Array.isArray(children)) {\n\t\t\t\tfor (var i = 0; i < children.length; i++) {\n\t\t\t\t\tvar child = children[i]\n\t\t\t\t\tif (child != null) onremove(child)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t//attrs\n\tfunction setAttrs(vnode, attrs, ns) {\n\t\tfor (var key in attrs) {\n\t\t\tsetAttr(vnode, key, null, attrs[key], ns)\n\t\t}\n\t}\n\tfunction setAttr(vnode, key, old, value, ns) {\n\t\tif (key === \"key\" || key === \"is\" || value == null || isLifecycleMethod(key) || (old === value && !isFormAttribute(vnode, key)) && typeof value !== \"object\") return\n\t\tif (key[0] === \"o\" && key[1] === \"n\") return updateEvent(vnode, key, value)\n\t\tif (key.slice(0, 6) === \"xlink:\") vnode.dom.setAttributeNS(\"http://www.w3.org/1999/xlink\", key.slice(6), value)\n\t\telse if (key === \"style\") updateStyle(vnode.dom, old, value)\n\t\telse if (hasPropertyKey(vnode, key, ns)) {\n\t\t\tif (key === \"value\") {\n\t\t\t\t// Only do the coercion if we're actually going to check the value.\n\t\t\t\t/* eslint-disable no-implicit-coercion */\n\t\t\t\t//setting input[value] to same value by typing on focused element moves cursor to end in Chrome\n\t\t\t\tif ((vnode.tag === \"input\" || vnode.tag === \"textarea\") && vnode.dom.value === \"\" + value && vnode.dom === activeElement()) return\n\t\t\t\t//setting select[value] to same value while having select open blinks select dropdown in Chrome\n\t\t\t\tif (vnode.tag === \"select\" && old !== null && vnode.dom.value === \"\" + value) return\n\t\t\t\t//setting option[value] to same value while having select open blinks select dropdown in Chrome\n\t\t\t\tif (vnode.tag === \"option\" && old !== null && vnode.dom.value === \"\" + value) return\n\t\t\t\t/* eslint-enable no-implicit-coercion */\n\t\t\t}\n\t\t\t// If you assign an input type that is not supported by IE 11 with an assignment expression, an error will occur.\n\t\t\tif (vnode.tag === \"input\" && key === \"type\") vnode.dom.setAttribute(key, value)\n\t\t\telse vnode.dom[key] = value\n\t\t} else {\n\t\t\tif (typeof value === \"boolean\") {\n\t\t\t\tif (value) vnode.dom.setAttribute(key, \"\")\n\t\t\t\telse vnode.dom.removeAttribute(key)\n\t\t\t}\n\t\t\telse vnode.dom.setAttribute(key === \"className\" ? \"class\" : key, value)\n\t\t}\n\t}\n\tfunction removeAttr(vnode, key, old, ns) {\n\t\tif (key === \"key\" || key === \"is\" || old == null || isLifecycleMethod(key)) return\n\t\tif (key[0] === \"o\" && key[1] === \"n\" && !isLifecycleMethod(key)) updateEvent(vnode, key, undefined)\n\t\telse if (key === \"style\") updateStyle(vnode.dom, old, null)\n\t\telse if (\n\t\t\thasPropertyKey(vnode, key, ns)\n\t\t\t&& key !== \"className\"\n\t\t\t&& !(key === \"value\" && (\n\t\t\t\tvnode.tag === \"option\"\n\t\t\t\t|| vnode.tag === \"select\" && vnode.dom.selectedIndex === -1 && vnode.dom === activeElement()\n\t\t\t))\n\t\t\t&& !(vnode.tag === \"input\" && key === \"type\")\n\t\t) {\n\t\t\tvnode.dom[key] = null\n\t\t} else {\n\t\t\tvar nsLastIndex = key.indexOf(\":\")\n\t\t\tif (nsLastIndex !== -1) key = key.slice(nsLastIndex + 1)\n\t\t\tif (old !== false) vnode.dom.removeAttribute(key === \"className\" ? \"class\" : key)\n\t\t}\n\t}\n\tfunction setLateSelectAttrs(vnode, attrs) {\n\t\tif (\"value\" in attrs) {\n\t\t\tif(attrs.value === null) {\n\t\t\t\tif (vnode.dom.selectedIndex !== -1) vnode.dom.value = null\n\t\t\t} else {\n\t\t\t\tvar normalized = \"\" + attrs.value // eslint-disable-line no-implicit-coercion\n\t\t\t\tif (vnode.dom.value !== normalized || vnode.dom.selectedIndex === -1) {\n\t\t\t\t\tvnode.dom.value = normalized\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (\"selectedIndex\" in attrs) setAttr(vnode, \"selectedIndex\", null, attrs.selectedIndex, undefined)\n\t}\n\tfunction updateAttrs(vnode, old, attrs, ns) {\n\t\tif (attrs != null) {\n\t\t\tfor (var key in attrs) {\n\t\t\t\tsetAttr(vnode, key, old && old[key], attrs[key], ns)\n\t\t\t}\n\t\t}\n\t\tvar val\n\t\tif (old != null) {\n\t\t\tfor (var key in old) {\n\t\t\t\tif (((val = old[key]) != null) && (attrs == null || attrs[key] == null)) {\n\t\t\t\t\tremoveAttr(vnode, key, val, ns)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfunction isFormAttribute(vnode, attr) {\n\t\treturn attr === \"value\" || attr === \"checked\" || attr === \"selectedIndex\" || attr === \"selected\" && vnode.dom === activeElement() || vnode.tag === \"option\" && vnode.dom.parentNode === $doc.activeElement\n\t}\n\tfunction isLifecycleMethod(attr) {\n\t\treturn attr === \"oninit\" || attr === \"oncreate\" || attr === \"onupdate\" || attr === \"onremove\" || attr === \"onbeforeremove\" || attr === \"onbeforeupdate\"\n\t}\n\tfunction hasPropertyKey(vnode, key, ns) {\n\t\t// Filter out namespaced keys\n\t\treturn ns === undefined && (\n\t\t\t// If it's a custom element, just keep it.\n\t\t\tvnode.tag.indexOf(\"-\") > -1 || vnode.attrs != null && vnode.attrs.is ||\n\t\t\t// If it's a normal element, let's try to avoid a few browser bugs.\n\t\t\tkey !== \"href\" && key !== \"list\" && key !== \"form\" && key !== \"width\" && key !== \"height\"// && key !== \"type\"\n\t\t\t// Defer the property check until *after* we check everything.\n\t\t) && key in vnode.dom\n\t}\n\n\t//style\n\tvar uppercaseRegex = /[A-Z]/g\n\tfunction toLowerCase(capital) { return \"-\" + capital.toLowerCase() }\n\tfunction normalizeKey(key) {\n\t\treturn key[0] === \"-\" && key[1] === \"-\" ? key :\n\t\t\tkey === \"cssFloat\" ? \"float\" :\n\t\t\t\tkey.replace(uppercaseRegex, toLowerCase)\n\t}\n\tfunction updateStyle(element, old, style) {\n\t\tif (old === style) {\n\t\t\t// Styles are equivalent, do nothing.\n\t\t} else if (style == null) {\n\t\t\t// New style is missing, just clear it.\n\t\t\telement.style.cssText = \"\"\n\t\t} else if (typeof style !== \"object\") {\n\t\t\t// New style is a string, let engine deal with patching.\n\t\t\telement.style.cssText = style\n\t\t} else if (old == null || typeof old !== \"object\") {\n\t\t\t// `old` is missing or a string, `style` is an object.\n\t\t\telement.style.cssText = \"\"\n\t\t\t// Add new style properties\n\t\t\tfor (var key in style) {\n\t\t\t\tvar value = style[key]\n\t\t\t\tif (value != null) element.style.setProperty(normalizeKey(key), String(value))\n\t\t\t}\n\t\t} else {\n\t\t\t// Both old & new are (different) objects.\n\t\t\t// Update style properties that have changed\n\t\t\tfor (var key in style) {\n\t\t\t\tvar value = style[key]\n\t\t\t\tif (value != null && (value = String(value)) !== String(old[key])) {\n\t\t\t\t\telement.style.setProperty(normalizeKey(key), value)\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Remove style properties that no longer exist\n\t\t\tfor (var key in old) {\n\t\t\t\tif (old[key] != null && style[key] == null) {\n\t\t\t\t\telement.style.removeProperty(normalizeKey(key))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Here's an explanation of how this works:\n\t// 1. The event names are always (by design) prefixed by `on`.\n\t// 2. The EventListener interface accepts either a function or an object\n\t// with a `handleEvent` method.\n\t// 3. The object does not inherit from `Object.prototype`, to avoid\n\t// any potential interference with that (e.g. setters).\n\t// 4. The event name is remapped to the handler before calling it.\n\t// 5. In function-based event handlers, `ev.target === this`. We replicate\n\t// that below.\n\t// 6. In function-based event handlers, `return false` prevents the default\n\t// action and stops event propagation. We replicate that below.\n\tfunction EventDict() {\n\t\t// Save this, so the current redraw is correctly tracked.\n\t\tthis._ = currentRedraw\n\t}\n\tEventDict.prototype = Object.create(null)\n\tEventDict.prototype.handleEvent = function (ev) {\n\t\tvar handler = this[\"on\" + ev.type]\n\t\tvar result\n\t\tif (typeof handler === \"function\") result = handler.call(ev.currentTarget, ev)\n\t\telse if (typeof handler.handleEvent === \"function\") handler.handleEvent(ev)\n\t\tif (this._ && ev.redraw !== false) (0, this._)()\n\t\tif (result === false) {\n\t\t\tev.preventDefault()\n\t\t\tev.stopPropagation()\n\t\t}\n\t}\n\n\t//event\n\tfunction updateEvent(vnode, key, value) {\n\t\tif (vnode.events != null) {\n\t\t\tif (vnode.events[key] === value) return\n\t\t\tif (value != null && (typeof value === \"function\" || typeof value === \"object\")) {\n\t\t\t\tif (vnode.events[key] == null) vnode.dom.addEventListener(key.slice(2), vnode.events, false)\n\t\t\t\tvnode.events[key] = value\n\t\t\t} else {\n\t\t\t\tif (vnode.events[key] != null) vnode.dom.removeEventListener(key.slice(2), vnode.events, false)\n\t\t\t\tvnode.events[key] = undefined\n\t\t\t}\n\t\t} else if (value != null && (typeof value === \"function\" || typeof value === \"object\")) {\n\t\t\tvnode.events = new EventDict()\n\t\t\tvnode.dom.addEventListener(key.slice(2), vnode.events, false)\n\t\t\tvnode.events[key] = value\n\t\t}\n\t}\n\n\t//lifecycle\n\tfunction initLifecycle(source, vnode, hooks) {\n\t\tif (typeof source.oninit === \"function\") callHook.call(source.oninit, vnode)\n\t\tif (typeof source.oncreate === \"function\") hooks.push(callHook.bind(source.oncreate, vnode))\n\t}\n\tfunction updateLifecycle(source, vnode, hooks) {\n\t\tif (typeof source.onupdate === \"function\") hooks.push(callHook.bind(source.onupdate, vnode))\n\t}\n\tfunction shouldNotUpdate(vnode, old) {\n\t\tdo {\n\t\t\tif (vnode.attrs != null && typeof vnode.attrs.onbeforeupdate === \"function\") {\n\t\t\t\tvar force = callHook.call(vnode.attrs.onbeforeupdate, vnode, old)\n\t\t\t\tif (force !== undefined && !force) break\n\t\t\t}\n\t\t\tif (typeof vnode.tag !== \"string\" && typeof vnode.state.onbeforeupdate === \"function\") {\n\t\t\t\tvar force = callHook.call(vnode.state.onbeforeupdate, vnode, old)\n\t\t\t\tif (force !== undefined && !force) break\n\t\t\t}\n\t\t\treturn false\n\t\t} while (false); // eslint-disable-line no-constant-condition\n\t\tvnode.dom = old.dom\n\t\tvnode.domSize = old.domSize\n\t\tvnode.instance = old.instance\n\t\t// One would think having the actual latest attributes would be ideal,\n\t\t// but it doesn't let us properly diff based on our current internal\n\t\t// representation. We have to save not only the old DOM info, but also\n\t\t// the attributes used to create it, as we diff *that*, not against the\n\t\t// DOM directly (with a few exceptions in `setAttr`). And, of course, we\n\t\t// need to save the children and text as they are conceptually not\n\t\t// unlike special \"attributes\" internally.\n\t\tvnode.attrs = old.attrs\n\t\tvnode.children = old.children\n\t\tvnode.text = old.text\n\t\treturn true\n\t}\n\n\treturn function(dom, vnodes, redraw) {\n\t\tif (!dom) throw new TypeError(\"Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.\")\n\t\tvar hooks = []\n\t\tvar active = activeElement()\n\t\tvar namespace = dom.namespaceURI\n\n\t\t// First time rendering into a node clears it out\n\t\tif (dom.vnodes == null) dom.textContent = \"\"\n\n\t\tvnodes = Vnode.normalizeChildren(Array.isArray(vnodes) ? vnodes : [vnodes])\n\t\tvar prevRedraw = currentRedraw\n\t\ttry {\n\t\t\tcurrentRedraw = typeof redraw === \"function\" ? redraw : undefined\n\t\t\tupdateNodes(dom, dom.vnodes, vnodes, hooks, null, namespace === \"http://www.w3.org/1999/xhtml\" ? undefined : namespace)\n\t\t} finally {\n\t\t\tcurrentRedraw = prevRedraw\n\t\t}\n\t\tdom.vnodes = vnodes\n\t\t// `document.activeElement` can return null: https://html.spec.whatwg.org/multipage/interaction.html#dom-document-activeelement\n\t\tif (active != null && activeElement() !== active && typeof active.focus === \"function\") active.focus()\n\t\tfor (var i = 0; i < hooks.length; i++) hooks[i]()\n\t}\n}\n", "\"use strict\"\n\nmodule.exports = require(\"./render/render\")(window)\n", "\"use strict\"\n\nvar Vnode = require(\"../render/vnode\")\n\nmodule.exports = function(render, schedule, console) {\n\tvar subscriptions = []\n\tvar rendering = false\n\tvar pending = false\n\n\tfunction sync() {\n\t\tif (rendering) throw new Error(\"Nested m.redraw.sync() call\")\n\t\trendering = true\n\t\tfor (var i = 0; i < subscriptions.length; i += 2) {\n\t\t\ttry { render(subscriptions[i], Vnode(subscriptions[i + 1]), redraw) }\n\t\t\tcatch (e) { console.error(e) }\n\t\t}\n\t\trendering = false\n\t}\n\n\tfunction redraw() {\n\t\tif (!pending) {\n\t\t\tpending = true\n\t\t\tschedule(function() {\n\t\t\t\tpending = false\n\t\t\t\tsync()\n\t\t\t})\n\t\t}\n\t}\n\n\tredraw.sync = sync\n\n\tfunction mount(root, component) {\n\t\tif (component != null && component.view == null && typeof component !== \"function\") {\n\t\t\tthrow new TypeError(\"m.mount(element, component) expects a component, not a vnode\")\n\t\t}\n\n\t\tvar index = subscriptions.indexOf(root)\n\t\tif (index >= 0) {\n\t\t\tsubscriptions.splice(index, 2)\n\t\t\trender(root, [], redraw)\n\t\t}\n\n\t\tif (component != null) {\n\t\t\tsubscriptions.push(root, component)\n\t\t\trender(root, Vnode(component), redraw)\n\t\t}\n\t}\n\n\treturn {mount: mount, redraw: redraw}\n}\n", "\"use strict\"\n\nvar render = require(\"./render\")\n\nmodule.exports = require(\"./api/mount-redraw\")(render, requestAnimationFrame, console)\n", "\"use strict\"\n\nmodule.exports = function(object) {\n\tif (Object.prototype.toString.call(object) !== \"[object Object]\") return \"\"\n\n\tvar args = []\n\tfor (var key in object) {\n\t\tdestructure(key, object[key])\n\t}\n\n\treturn args.join(\"&\")\n\n\tfunction destructure(key, value) {\n\t\tif (Array.isArray(value)) {\n\t\t\tfor (var i = 0; i < value.length; i++) {\n\t\t\t\tdestructure(key + \"[\" + i + \"]\", value[i])\n\t\t\t}\n\t\t}\n\t\telse if (Object.prototype.toString.call(value) === \"[object Object]\") {\n\t\t\tfor (var i in value) {\n\t\t\t\tdestructure(key + \"[\" + i + \"]\", value[i])\n\t\t\t}\n\t\t}\n\t\telse args.push(encodeURIComponent(key) + (value != null && value !== \"\" ? \"=\" + encodeURIComponent(value) : \"\"))\n\t}\n}\n", "\"use strict\"\n\nmodule.exports = Object.assign || function(target, source) {\n\tif(source) Object.keys(source).forEach(function(key) { target[key] = source[key] })\n}\n", "\"use strict\"\n\nvar buildQueryString = require(\"../querystring/build\")\nvar assign = require(\"./assign\")\n\n// Returns `path` from `template` + `params`\nmodule.exports = function(template, params) {\n\tif ((/:([^\\/\\.-]+)(\\.{3})?:/).test(template)) {\n\t\tthrow new SyntaxError(\"Template parameter names *must* be separated\")\n\t}\n\tif (params == null) return template\n\tvar queryIndex = template.indexOf(\"?\")\n\tvar hashIndex = template.indexOf(\"#\")\n\tvar queryEnd = hashIndex < 0 ? template.length : hashIndex\n\tvar pathEnd = queryIndex < 0 ? queryEnd : queryIndex\n\tvar path = template.slice(0, pathEnd)\n\tvar query = {}\n\n\tassign(query, params)\n\n\tvar resolved = path.replace(/:([^\\/\\.-]+)(\\.{3})?/g, function(m, key, variadic) {\n\t\tdelete query[key]\n\t\t// If no such parameter exists, don't interpolate it.\n\t\tif (params[key] == null) return m\n\t\t// Escape normal parameters, but not variadic ones.\n\t\treturn variadic ? params[key] : encodeURIComponent(String(params[key]))\n\t})\n\n\t// In case the template substitution adds new query/hash parameters.\n\tvar newQueryIndex = resolved.indexOf(\"?\")\n\tvar newHashIndex = resolved.indexOf(\"#\")\n\tvar newQueryEnd = newHashIndex < 0 ? resolved.length : newHashIndex\n\tvar newPathEnd = newQueryIndex < 0 ? newQueryEnd : newQueryIndex\n\tvar result = resolved.slice(0, newPathEnd)\n\n\tif (queryIndex >= 0) result += template.slice(queryIndex, queryEnd)\n\tif (newQueryIndex >= 0) result += (queryIndex < 0 ? \"?\" : \"&\") + resolved.slice(newQueryIndex, newQueryEnd)\n\tvar querystring = buildQueryString(query)\n\tif (querystring) result += (queryIndex < 0 && newQueryIndex < 0 ? \"?\" : \"&\") + querystring\n\tif (hashIndex >= 0) result += template.slice(hashIndex)\n\tif (newHashIndex >= 0) result += (hashIndex < 0 ? \"\" : \"&\") + resolved.slice(newHashIndex)\n\treturn result\n}\n", "\"use strict\"\n\nvar buildPathname = require(\"../pathname/build\")\n\nmodule.exports = function($window, Promise, oncompletion) {\n\tvar callbackCount = 0\n\n\tfunction PromiseProxy(executor) {\n\t\treturn new Promise(executor)\n\t}\n\n\t// In case the global Promise is some userland library's where they rely on\n\t// `foo instanceof this.constructor`, `this.constructor.resolve(value)`, or\n\t// similar. Let's *not* break them.\n\tPromiseProxy.prototype = Promise.prototype\n\tPromiseProxy.__proto__ = Promise // eslint-disable-line no-proto\n\n\tfunction makeRequest(factory) {\n\t\treturn function(url, args) {\n\t\t\tif (typeof url !== \"string\") { args = url; url = url.url }\n\t\t\telse if (args == null) args = {}\n\t\t\tvar promise = new Promise(function(resolve, reject) {\n\t\t\t\tfactory(buildPathname(url, args.params), args, function (data) {\n\t\t\t\t\tif (typeof args.type === \"function\") {\n\t\t\t\t\t\tif (Array.isArray(data)) {\n\t\t\t\t\t\t\tfor (var i = 0; i < data.length; i++) {\n\t\t\t\t\t\t\t\tdata[i] = new args.type(data[i])\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse data = new args.type(data)\n\t\t\t\t\t}\n\t\t\t\t\tresolve(data)\n\t\t\t\t}, reject)\n\t\t\t})\n\t\t\tif (args.background === true) return promise\n\t\t\tvar count = 0\n\t\t\tfunction complete() {\n\t\t\t\tif (--count === 0 && typeof oncompletion === \"function\") oncompletion()\n\t\t\t}\n\n\t\t\treturn wrap(promise)\n\n\t\t\tfunction wrap(promise) {\n\t\t\t\tvar then = promise.then\n\t\t\t\t// Set the constructor, so engines know to not await or resolve\n\t\t\t\t// this as a native promise. At the time of writing, this is\n\t\t\t\t// only necessary for V8, but their behavior is the correct\n\t\t\t\t// behavior per spec. See this spec issue for more details:\n\t\t\t\t// https://github.com/tc39/ecma262/issues/1577. Also, see the\n\t\t\t\t// corresponding comment in `request/tests/test-request.js` for\n\t\t\t\t// a bit more background on the issue at hand.\n\t\t\t\tpromise.constructor = PromiseProxy\n\t\t\t\tpromise.then = function() {\n\t\t\t\t\tcount++\n\t\t\t\t\tvar next = then.apply(promise, arguments)\n\t\t\t\t\tnext.then(complete, function(e) {\n\t\t\t\t\t\tcomplete()\n\t\t\t\t\t\tif (count === 0) throw e\n\t\t\t\t\t})\n\t\t\t\t\treturn wrap(next)\n\t\t\t\t}\n\t\t\t\treturn promise\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction hasHeader(args, name) {\n\t\tfor (var key in args.headers) {\n\t\t\tif ({}.hasOwnProperty.call(args.headers, key) && name.test(key)) return true\n\t\t}\n\t\treturn false\n\t}\n\n\treturn {\n\t\trequest: makeRequest(function(url, args, resolve, reject) {\n\t\t\tvar method = args.method != null ? args.method.toUpperCase() : \"GET\"\n\t\t\tvar body = args.body\n\t\t\tvar assumeJSON = (args.serialize == null || args.serialize === JSON.serialize) && !(body instanceof $window.FormData)\n\t\t\tvar responseType = args.responseType || (typeof args.extract === \"function\" ? \"\" : \"json\")\n\n\t\t\tvar xhr = new $window.XMLHttpRequest(), aborted = false\n\t\t\tvar original = xhr, replacedAbort\n\t\t\tvar abort = xhr.abort\n\n\t\t\txhr.abort = function() {\n\t\t\t\taborted = true\n\t\t\t\tabort.call(this)\n\t\t\t}\n\n\t\t\txhr.open(method, url, args.async !== false, typeof args.user === \"string\" ? args.user : undefined, typeof args.password === \"string\" ? args.password : undefined)\n\n\t\t\tif (assumeJSON && body != null && !hasHeader(args, /^content-type$/i)) {\n\t\t\t\txhr.setRequestHeader(\"Content-Type\", \"application/json; charset=utf-8\")\n\t\t\t}\n\t\t\tif (typeof args.deserialize !== \"function\" && !hasHeader(args, /^accept$/i)) {\n\t\t\t\txhr.setRequestHeader(\"Accept\", \"application/json, text/*\")\n\t\t\t}\n\t\t\tif (args.withCredentials) xhr.withCredentials = args.withCredentials\n\t\t\tif (args.timeout) xhr.timeout = args.timeout\n\t\t\txhr.responseType = responseType\n\n\t\t\tfor (var key in args.headers) {\n\t\t\t\tif ({}.hasOwnProperty.call(args.headers, key)) {\n\t\t\t\t\txhr.setRequestHeader(key, args.headers[key])\n\t\t\t\t}\n\t\t\t}\n\n\t\t\txhr.onreadystatechange = function(ev) {\n\t\t\t\t// Don't throw errors on xhr.abort().\n\t\t\t\tif (aborted) return\n\n\t\t\t\tif (ev.target.readyState === 4) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvar success = (ev.target.status >= 200 && ev.target.status < 300) || ev.target.status === 304 || (/^file:\\/\\//i).test(url)\n\t\t\t\t\t\t// When the response type isn't \"\" or \"text\",\n\t\t\t\t\t\t// `xhr.responseText` is the wrong thing to use.\n\t\t\t\t\t\t// Browsers do the right thing and throw here, and we\n\t\t\t\t\t\t// should honor that and do the right thing by\n\t\t\t\t\t\t// preferring `xhr.response` where possible/practical.\n\t\t\t\t\t\tvar response = ev.target.response, message\n\n\t\t\t\t\t\tif (responseType === \"json\") {\n\t\t\t\t\t\t\t// For IE and Edge, which don't implement\n\t\t\t\t\t\t\t// `responseType: \"json\"`.\n\t\t\t\t\t\t\tif (!ev.target.responseType && typeof args.extract !== \"function\") response = JSON.parse(ev.target.responseText)\n\t\t\t\t\t\t} else if (!responseType || responseType === \"text\") {\n\t\t\t\t\t\t\t// Only use this default if it's text. If a parsed\n\t\t\t\t\t\t\t// document is needed on old IE and friends (all\n\t\t\t\t\t\t\t// unsupported), the user should use a custom\n\t\t\t\t\t\t\t// `config` instead. They're already using this at\n\t\t\t\t\t\t\t// their own risk.\n\t\t\t\t\t\t\tif (response == null) response = ev.target.responseText\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (typeof args.extract === \"function\") {\n\t\t\t\t\t\t\tresponse = args.extract(ev.target, args)\n\t\t\t\t\t\t\tsuccess = true\n\t\t\t\t\t\t} else if (typeof args.deserialize === \"function\") {\n\t\t\t\t\t\t\tresponse = args.deserialize(response)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (success) resolve(response)\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\ttry { message = ev.target.responseText }\n\t\t\t\t\t\t\tcatch (e) { message = response }\n\t\t\t\t\t\t\tvar error = new Error(message)\n\t\t\t\t\t\t\terror.code = ev.target.status\n\t\t\t\t\t\t\terror.response = response\n\t\t\t\t\t\t\treject(error)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch (e) {\n\t\t\t\t\t\treject(e)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (typeof args.config === \"function\") {\n\t\t\t\txhr = args.config(xhr, args, url) || xhr\n\n\t\t\t\t// Propagate the `abort` to any replacement XHR as well.\n\t\t\t\tif (xhr !== original) {\n\t\t\t\t\treplacedAbort = xhr.abort\n\t\t\t\t\txhr.abort = function() {\n\t\t\t\t\t\taborted = true\n\t\t\t\t\t\treplacedAbort.call(this)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (body == null) xhr.send()\n\t\t\telse if (typeof args.serialize === \"function\") xhr.send(args.serialize(body))\n\t\t\telse if (body instanceof $window.FormData) xhr.send(body)\n\t\t\telse xhr.send(JSON.stringify(body))\n\t\t}),\n\t\tjsonp: makeRequest(function(url, args, resolve, reject) {\n\t\t\tvar callbackName = args.callbackName || \"_mithril_\" + Math.round(Math.random() * 1e16) + \"_\" + callbackCount++\n\t\t\tvar script = $window.document.createElement(\"script\")\n\t\t\t$window[callbackName] = function(data) {\n\t\t\t\tdelete $window[callbackName]\n\t\t\t\tscript.parentNode.removeChild(script)\n\t\t\t\tresolve(data)\n\t\t\t}\n\t\t\tscript.onerror = function() {\n\t\t\t\tdelete $window[callbackName]\n\t\t\t\tscript.parentNode.removeChild(script)\n\t\t\t\treject(new Error(\"JSONP request failed\"))\n\t\t\t}\n\t\t\tscript.src = url + (url.indexOf(\"?\") < 0 ? \"?\" : \"&\") +\n\t\t\t\tencodeURIComponent(args.callbackKey || \"callback\") + \"=\" +\n\t\t\t\tencodeURIComponent(callbackName)\n\t\t\t$window.document.documentElement.appendChild(script)\n\t\t}),\n\t}\n}\n", "\"use strict\"\n\nvar PromisePolyfill = require(\"./promise/promise\")\nvar mountRedraw = require(\"./mount-redraw\")\n\nmodule.exports = require(\"./request/request\")(window, PromisePolyfill, mountRedraw.redraw)\n", "\"use strict\"\n\nmodule.exports = function(string) {\n\tif (string === \"\" || string == null) return {}\n\tif (string.charAt(0) === \"?\") string = string.slice(1)\n\n\tvar entries = string.split(\"&\"), counters = {}, data = {}\n\tfor (var i = 0; i < entries.length; i++) {\n\t\tvar entry = entries[i].split(\"=\")\n\t\tvar key = decodeURIComponent(entry[0])\n\t\tvar value = entry.length === 2 ? decodeURIComponent(entry[1]) : \"\"\n\n\t\tif (value === \"true\") value = true\n\t\telse if (value === \"false\") value = false\n\n\t\tvar levels = key.split(/\\]\\[?|\\[/)\n\t\tvar cursor = data\n\t\tif (key.indexOf(\"[\") > -1) levels.pop()\n\t\tfor (var j = 0; j < levels.length; j++) {\n\t\t\tvar level = levels[j], nextLevel = levels[j + 1]\n\t\t\tvar isNumber = nextLevel == \"\" || !isNaN(parseInt(nextLevel, 10))\n\t\t\tif (level === \"\") {\n\t\t\t\tvar key = levels.slice(0, j).join()\n\t\t\t\tif (counters[key] == null) {\n\t\t\t\t\tcounters[key] = Array.isArray(cursor) ? cursor.length : 0\n\t\t\t\t}\n\t\t\t\tlevel = counters[key]++\n\t\t\t}\n\t\t\t// Disallow direct prototype pollution\n\t\t\telse if (level === \"__proto__\") break\n\t\t\tif (j === levels.length - 1) cursor[level] = value\n\t\t\telse {\n\t\t\t\t// Read own properties exclusively to disallow indirect\n\t\t\t\t// prototype pollution\n\t\t\t\tvar desc = Object.getOwnPropertyDescriptor(cursor, level)\n\t\t\t\tif (desc != null) desc = desc.value\n\t\t\t\tif (desc == null) cursor[level] = desc = isNumber ? [] : {}\n\t\t\t\tcursor = desc\n\t\t\t}\n\t\t}\n\t}\n\treturn data\n}\n", "\"use strict\"\n\nvar parseQueryString = require(\"../querystring/parse\")\n\n// Returns `{path, params}` from `url`\nmodule.exports = function(url) {\n\tvar queryIndex = url.indexOf(\"?\")\n\tvar hashIndex = url.indexOf(\"#\")\n\tvar queryEnd = hashIndex < 0 ? url.length : hashIndex\n\tvar pathEnd = queryIndex < 0 ? queryEnd : queryIndex\n\tvar path = url.slice(0, pathEnd).replace(/\\/{2,}/g, \"/\")\n\n\tif (!path) path = \"/\"\n\telse {\n\t\tif (path[0] !== \"/\") path = \"/\" + path\n\t\tif (path.length > 1 && path[path.length - 1] === \"/\") path = path.slice(0, -1)\n\t}\n\treturn {\n\t\tpath: path,\n\t\tparams: queryIndex < 0\n\t\t\t? {}\n\t\t\t: parseQueryString(url.slice(queryIndex + 1, queryEnd)),\n\t}\n}\n", "\"use strict\"\n\nvar parsePathname = require(\"./parse\")\n\n// Compiles a template into a function that takes a resolved path (without query\n// strings) and returns an object containing the template parameters with their\n// parsed values. This expects the input of the compiled template to be the\n// output of `parsePathname`. Note that it does *not* remove query parameters\n// specified in the template.\nmodule.exports = function(template) {\n\tvar templateData = parsePathname(template)\n\tvar templateKeys = Object.keys(templateData.params)\n\tvar keys = []\n\tvar regexp = new RegExp(\"^\" + templateData.path.replace(\n\t\t// I escape literal text so people can use things like `:file.:ext` or\n\t\t// `:lang-:locale` in routes. This is all merged into one pass so I\n\t\t// don't also accidentally escape `-` and make it harder to detect it to\n\t\t// ban it from template parameters.\n\t\t/:([^\\/.-]+)(\\.{3}|\\.(?!\\.)|-)?|[\\\\^$*+.()|\\[\\]{}]/g,\n\t\tfunction(m, key, extra) {\n\t\t\tif (key == null) return \"\\\\\" + m\n\t\t\tkeys.push({k: key, r: extra === \"...\"})\n\t\t\tif (extra === \"...\") return \"(.*)\"\n\t\t\tif (extra === \".\") return \"([^/]+)\\\\.\"\n\t\t\treturn \"([^/]+)\" + (extra || \"\")\n\t\t}\n\t) + \"$\")\n\treturn function(data) {\n\t\t// First, check the params. Usually, there isn't any, and it's just\n\t\t// checking a static set.\n\t\tfor (var i = 0; i < templateKeys.length; i++) {\n\t\t\tif (templateData.params[templateKeys[i]] !== data.params[templateKeys[i]]) return false\n\t\t}\n\t\t// If no interpolations exist, let's skip all the ceremony\n\t\tif (!keys.length) return regexp.test(data.path)\n\t\tvar values = regexp.exec(data.path)\n\t\tif (values == null) return false\n\t\tfor (var i = 0; i < keys.length; i++) {\n\t\t\tdata.params[keys[i].k] = keys[i].r ? values[i + 1] : decodeURIComponent(values[i + 1])\n\t\t}\n\t\treturn true\n\t}\n}\n", "\"use strict\"\n\nvar Vnode = require(\"../render/vnode\")\nvar m = require(\"../render/hyperscript\")\nvar Promise = require(\"../promise/promise\")\n\nvar buildPathname = require(\"../pathname/build\")\nvar parsePathname = require(\"../pathname/parse\")\nvar compileTemplate = require(\"../pathname/compileTemplate\")\nvar assign = require(\"../pathname/assign\")\n\nvar sentinel = {}\n\nmodule.exports = function($window, mountRedraw) {\n\tvar fireAsync\n\n\tfunction setPath(path, data, options) {\n\t\tpath = buildPathname(path, data)\n\t\tif (fireAsync != null) {\n\t\t\tfireAsync()\n\t\t\tvar state = options ? options.state : null\n\t\t\tvar title = options ? options.title : null\n\t\t\tif (options && options.replace) $window.history.replaceState(state, title, route.prefix + path)\n\t\t\telse $window.history.pushState(state, title, route.prefix + path)\n\t\t}\n\t\telse {\n\t\t\t$window.location.href = route.prefix + path\n\t\t}\n\t}\n\n\tvar currentResolver = sentinel, component, attrs, currentPath, lastUpdate\n\n\tvar SKIP = route.SKIP = {}\n\n\tfunction route(root, defaultRoute, routes) {\n\t\tif (root == null) throw new Error(\"Ensure the DOM element that was passed to `m.route` is not undefined\")\n\t\t// 0 = start\n\t\t// 1 = init\n\t\t// 2 = ready\n\t\tvar state = 0\n\n\t\tvar compiled = Object.keys(routes).map(function(route) {\n\t\t\tif (route[0] !== \"/\") throw new SyntaxError(\"Routes must start with a `/`\")\n\t\t\tif ((/:([^\\/\\.-]+)(\\.{3})?:/).test(route)) {\n\t\t\t\tthrow new SyntaxError(\"Route parameter names must be separated with either `/`, `.`, or `-`\")\n\t\t\t}\n\t\t\treturn {\n\t\t\t\troute: route,\n\t\t\t\tcomponent: routes[route],\n\t\t\t\tcheck: compileTemplate(route),\n\t\t\t}\n\t\t})\n\t\tvar callAsync = typeof setImmediate === \"function\" ? setImmediate : setTimeout\n\t\tvar p = Promise.resolve()\n\t\tvar scheduled = false\n\t\tvar onremove\n\n\t\tfireAsync = null\n\n\t\tif (defaultRoute != null) {\n\t\t\tvar defaultData = parsePathname(defaultRoute)\n\n\t\t\tif (!compiled.some(function (i) { return i.check(defaultData) })) {\n\t\t\t\tthrow new ReferenceError(\"Default route doesn't match any known routes\")\n\t\t\t}\n\t\t}\n\n\t\tfunction resolveRoute() {\n\t\t\tscheduled = false\n\t\t\t// Consider the pathname holistically. The prefix might even be invalid,\n\t\t\t// but that's not our problem.\n\t\t\tvar prefix = $window.location.hash\n\t\t\tif (route.prefix[0] !== \"#\") {\n\t\t\t\tprefix = $window.location.search + prefix\n\t\t\t\tif (route.prefix[0] !== \"?\") {\n\t\t\t\t\tprefix = $window.location.pathname + prefix\n\t\t\t\t\tif (prefix[0] !== \"/\") prefix = \"/\" + prefix\n\t\t\t\t}\n\t\t\t}\n\t\t\t// This seemingly useless `.concat()` speeds up the tests quite a bit,\n\t\t\t// since the representation is consistently a relatively poorly\n\t\t\t// optimized cons string.\n\t\t\tvar path = prefix.concat()\n\t\t\t\t.replace(/(?:%[a-f89][a-f0-9])+/gim, decodeURIComponent)\n\t\t\t\t.slice(route.prefix.length)\n\t\t\tvar data = parsePathname(path)\n\n\t\t\tassign(data.params, $window.history.state)\n\n\t\t\tfunction fail() {\n\t\t\t\tif (path === defaultRoute) throw new Error(\"Could not resolve default route \" + defaultRoute)\n\t\t\t\tsetPath(defaultRoute, null, {replace: true})\n\t\t\t}\n\n\t\t\tloop(0)\n\t\t\tfunction loop(i) {\n\t\t\t\t// 0 = init\n\t\t\t\t// 1 = scheduled\n\t\t\t\t// 2 = done\n\t\t\t\tfor (; i < compiled.length; i++) {\n\t\t\t\t\tif (compiled[i].check(data)) {\n\t\t\t\t\t\tvar payload = compiled[i].component\n\t\t\t\t\t\tvar matchedRoute = compiled[i].route\n\t\t\t\t\t\tvar localComp = payload\n\t\t\t\t\t\tvar update = lastUpdate = function(comp) {\n\t\t\t\t\t\t\tif (update !== lastUpdate) return\n\t\t\t\t\t\t\tif (comp === SKIP) return loop(i + 1)\n\t\t\t\t\t\t\tcomponent = comp != null && (typeof comp.view === \"function\" || typeof comp === \"function\")? comp : \"div\"\n\t\t\t\t\t\t\tattrs = data.params, currentPath = path, lastUpdate = null\n\t\t\t\t\t\t\tcurrentResolver = payload.render ? payload : null\n\t\t\t\t\t\t\tif (state === 2) mountRedraw.redraw()\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tstate = 2\n\t\t\t\t\t\t\t\tmountRedraw.redraw.sync()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// There's no understating how much I *wish* I could\n\t\t\t\t\t\t// use `async`/`await` here...\n\t\t\t\t\t\tif (payload.view || typeof payload === \"function\") {\n\t\t\t\t\t\t\tpayload = {}\n\t\t\t\t\t\t\tupdate(localComp)\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (payload.onmatch) {\n\t\t\t\t\t\t\tp.then(function () {\n\t\t\t\t\t\t\t\treturn payload.onmatch(data.params, path, matchedRoute)\n\t\t\t\t\t\t\t}).then(update, fail)\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse update(\"div\")\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfail()\n\t\t\t}\n\t\t}\n\n\t\t// Set it unconditionally so `m.route.set` and `m.route.Link` both work,\n\t\t// even if neither `pushState` nor `hashchange` are supported. It's\n\t\t// cleared if `hashchange` is used, since that makes it automatically\n\t\t// async.\n\t\tfireAsync = function() {\n\t\t\tif (!scheduled) {\n\t\t\t\tscheduled = true\n\t\t\t\tcallAsync(resolveRoute)\n\t\t\t}\n\t\t}\n\n\t\tif (typeof $window.history.pushState === \"function\") {\n\t\t\tonremove = function() {\n\t\t\t\t$window.removeEventListener(\"popstate\", fireAsync, false)\n\t\t\t}\n\t\t\t$window.addEventListener(\"popstate\", fireAsync, false)\n\t\t} else if (route.prefix[0] === \"#\") {\n\t\t\tfireAsync = null\n\t\t\tonremove = function() {\n\t\t\t\t$window.removeEventListener(\"hashchange\", resolveRoute, false)\n\t\t\t}\n\t\t\t$window.addEventListener(\"hashchange\", resolveRoute, false)\n\t\t}\n\n\t\treturn mountRedraw.mount(root, {\n\t\t\tonbeforeupdate: function() {\n\t\t\t\tstate = state ? 2 : 1\n\t\t\t\treturn !(!state || sentinel === currentResolver)\n\t\t\t},\n\t\t\toncreate: resolveRoute,\n\t\t\tonremove: onremove,\n\t\t\tview: function() {\n\t\t\t\tif (!state || sentinel === currentResolver) return\n\t\t\t\t// Wrap in a fragment to preserve existing key semantics\n\t\t\t\tvar vnode = [Vnode(component, attrs.key, attrs)]\n\t\t\t\tif (currentResolver) vnode = currentResolver.render(vnode[0])\n\t\t\t\treturn vnode\n\t\t\t},\n\t\t})\n\t}\n\troute.set = function(path, data, options) {\n\t\tif (lastUpdate != null) {\n\t\t\toptions = options || {}\n\t\t\toptions.replace = true\n\t\t}\n\t\tlastUpdate = null\n\t\tsetPath(path, data, options)\n\t}\n\troute.get = function() {return currentPath}\n\troute.prefix = \"#!\"\n\troute.Link = {\n\t\tview: function(vnode) {\n\t\t\tvar options = vnode.attrs.options\n\t\t\t// Remove these so they don't get overwritten\n\t\t\tvar attrs = {}, onclick, href\n\t\t\tassign(attrs, vnode.attrs)\n\t\t\t// The first two are internal, but the rest are magic attributes\n\t\t\t// that need censored to not screw up rendering.\n\t\t\tattrs.selector = attrs.options = attrs.key = attrs.oninit =\n\t\t\tattrs.oncreate = attrs.onbeforeupdate = attrs.onupdate =\n\t\t\tattrs.onbeforeremove = attrs.onremove = null\n\n\t\t\t// Do this now so we can get the most current `href` and `disabled`.\n\t\t\t// Those attributes may also be specified in the selector, and we\n\t\t\t// should honor that.\n\t\t\tvar child = m(vnode.attrs.selector || \"a\", attrs, vnode.children)\n\n\t\t\t// Let's provide a *right* way to disable a route link, rather than\n\t\t\t// letting people screw up accessibility on accident.\n\t\t\t//\n\t\t\t// The attribute is coerced so users don't get surprised over\n\t\t\t// `disabled: 0` resulting in a button that's somehow routable\n\t\t\t// despite being visibly disabled.\n\t\t\tif (child.attrs.disabled = Boolean(child.attrs.disabled)) {\n\t\t\t\tchild.attrs.href = null\n\t\t\t\tchild.attrs[\"aria-disabled\"] = \"true\"\n\t\t\t\t// If you *really* do want to do this on a disabled link, use\n\t\t\t\t// an `oncreate` hook to add it.\n\t\t\t\tchild.attrs.onclick = null\n\t\t\t} else {\n\t\t\t\tonclick = child.attrs.onclick\n\t\t\t\thref = child.attrs.href\n\t\t\t\tchild.attrs.href = route.prefix + href\n\t\t\t\tchild.attrs.onclick = function(e) {\n\t\t\t\t\tvar result\n\t\t\t\t\tif (typeof onclick === \"function\") {\n\t\t\t\t\t\tresult = onclick.call(e.currentTarget, e)\n\t\t\t\t\t} else if (onclick == null || typeof onclick !== \"object\") {\n\t\t\t\t\t\t// do nothing\n\t\t\t\t\t} else if (typeof onclick.handleEvent === \"function\") {\n\t\t\t\t\t\tonclick.handleEvent(e)\n\t\t\t\t\t}\n\n\t\t\t\t\t// Adapted from React Router's implementation:\n\t\t\t\t\t// https://github.com/ReactTraining/react-router/blob/520a0acd48ae1b066eb0b07d6d4d1790a1d02482/packages/react-router-dom/modules/Link.js\n\t\t\t\t\t//\n\t\t\t\t\t// Try to be flexible and intuitive in how we handle links.\n\t\t\t\t\t// Fun fact: links aren't as obvious to get right as you\n\t\t\t\t\t// would expect. There's a lot more valid ways to click a\n\t\t\t\t\t// link than this, and one might want to not simply click a\n\t\t\t\t\t// link, but right click or command-click it to copy the\n\t\t\t\t\t// link target, etc. Nope, this isn't just for blind people.\n\t\t\t\t\tif (\n\t\t\t\t\t\t// Skip if `onclick` prevented default\n\t\t\t\t\t\tresult !== false && !e.defaultPrevented &&\n\t\t\t\t\t\t// Ignore everything but left clicks\n\t\t\t\t\t\t(e.button === 0 || e.which === 0 || e.which === 1) &&\n\t\t\t\t\t\t// Let the browser handle `target=_blank`, etc.\n\t\t\t\t\t\t(!e.currentTarget.target || e.currentTarget.target === \"_self\") &&\n\t\t\t\t\t\t// No modifier keys\n\t\t\t\t\t\t!e.ctrlKey && !e.metaKey && !e.shiftKey && !e.altKey\n\t\t\t\t\t) {\n\t\t\t\t\t\te.preventDefault()\n\t\t\t\t\t\te.redraw = false\n\t\t\t\t\t\troute.set(href, null, options)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn child\n\t\t},\n\t}\n\troute.param = function(key) {\n\t\treturn attrs && key != null ? attrs[key] : attrs\n\t}\n\n\treturn route\n}\n", "\"use strict\"\n\nvar mountRedraw = require(\"./mount-redraw\")\n\nmodule.exports = require(\"./api/router\")(window, mountRedraw)\n", "\"use strict\"\n\nvar hyperscript = require(\"./hyperscript\")\nvar request = require(\"./request\")\nvar mountRedraw = require(\"./mount-redraw\")\n\nvar m = function m() { return hyperscript.apply(this, arguments) }\nm.m = hyperscript\nm.trust = hyperscript.trust\nm.fragment = hyperscript.fragment\nm.mount = mountRedraw.mount\nm.route = require(\"./route\")\nm.render = require(\"./render\")\nm.redraw = mountRedraw.redraw\nm.request = request.request\nm.jsonp = request.jsonp\nm.parseQueryString = require(\"./querystring/parse\")\nm.buildQueryString = require(\"./querystring/build\")\nm.parsePathname = require(\"./pathname/parse\")\nm.buildPathname = require(\"./pathname/build\")\nm.vnode = require(\"./render/vnode\")\nm.PromisePolyfill = require(\"./promise/polyfill\")\n\nmodule.exports = m\n", "import m from \"mithril\"\n\nconst searchButton = document.querySelector(\"nav .search\")\nconst mountpoint = document.createElement(\"div\")\ndocument.querySelector(\"main\").insertBefore(mountpoint, document.querySelector(\".header\"))\n\nconst state = {\n showingSearchDialog: false,\n searchResults: [],\n searchError: null,\n searchQuery: \"\"\n}\n\nconst lowercaseFirst = ([first, ...rest]) => first.toLowerCase() + rest.join(\"\")\nconst uppercaseFirst = ([first, ...rest]) => first.toUpperCase() + rest.join(\"\")\nconst pageToSlug = page => page.split(/[ _]/).map(lowercaseFirst).join(\"_\")\nconst slugToPage = slug => slug.split(/[ _]/).map(uppercaseFirst).join(\" \")\n\nconst urlForPage = (page, subpage) => {\n let p = `/${encodeURIComponent(pageToSlug(page))}`\n if (subpage) { p += \"/\" + subpage }\n return p\n}\n\nconst handleHTTPError = e => {\n if (e.code === 0) { return }\n let x = `Server error ${e.code}`\n if (e.message) { x += \" \" + e.message }\n alert(x)\n}\n\nconst onsearch = ev => {\n const query = ev.target.value\n state.searchQuery = query\n m.request({\n url: \"/api/search\",\n params: { q: query }\n }).then(x => {\n if (typeof x === \"string\") { // SQLite syntax error\n console.log(\"ERR\", x)\n state.searchError = x\n } else {\n state.searchResults = x\n state.searchError = null\n }\n }, e => handleHTTPError)\n}\n\nconst currentPage = slugToPage(decodeURIComponent(/^\\/([^/]+)/.exec(location.pathname)[1]).replace(/\\+/g, \" \"))\n\nconst searchKeyHandler = ev => {\n if (ev.keyCode === 13) { // enter key\n // not very useful to just navigate to the same page\n const otherResults = state.searchResults.filter(r => r.page !== currentPage)\n if (otherResults[0]) { location.href = urlForPage(otherResults[0].page) }\n }\n}\n\nconst SearchDialog = {\n view: () => m(\".dialog.search\", [\n m(\"h1\", \"Search\"),\n m(\"input[type=search]\", { placeholder: \"Query\", oninput: onsearch, onkeydown: searchKeyHandler, value: state.searchQuery, oncreate: ({ dom }) => dom.focus() }),\n state.searchError && m(\".error\", state.searchError),\n m(\"ul\", state.searchResults.map(x => m(\"li\", [\n m(\".flex-space\", [ m(\"a.wikilink\", { href: urlForPage(x.page) }, x.page), m(\"\", x.rank.toFixed(3)) ]),\n m(\"\", x.snippet.map(s => s[0] ? m(\"span.highlight\", s[1]) : s[1]))\n ])))\n ])\n}\n\nconst App = {\n view: () => m(\"\", state.showingSearchDialog ? m(SearchDialog) : null)\n}\n\nsearchButton.addEventListener(\"click\", e => {\n state.showingSearchDialog = !state.showingSearchDialog\n e.preventDefault()\n m.redraw()\n})\n\ndocument.body.addEventListener(\"keydown\", e => {\n if (e.target === document.body) { // maybe use alt instead? or right shift or something - this just detects unfocused keypresses\n if (e.key === \"e\") {\n location.pathname = urlForPage(currentPage, \"edit\")\n } else if (e.key === \"v\") {\n location.pathname = urlForPage(currentPage)\n } else if (e.key === \"r\") {\n location.pathname = urlForPage(currentPage, \"revisions\")\n } else if (e.key === \"/\") {\n state.showingSearchDialog = !state.showingSearchDialog\n e.preventDefault()\n m.redraw()\n }\n }\n})\n\nm.mount(mountpoint, App)"], + "mappings": "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", + "names": [] +} diff --git a/static/style.css b/static/style.css index 64238a0..d442ba8 100644 --- a/static/style.css +++ b/static/style.css @@ -1 +1 @@ -html{scrollbar-color:#000 #d3d3d3}*{box-sizing:border-box}body{font-family:"Fira Sans","Noto Sans","Segoe UI",Verdana,sans-serif;font-weight:300;margin:0;min-height:100vh}main{width:50em;padding:0 1em 1em 1em;margin-left:auto;margin-right:auto}strong{font-weight:600}h1,h2,h3,h4,h5,h6{margin:0;font-weight:500}h1:first-of-type,h2:first-of-type,h3:first-of-type,h4:first-of-type,h5:first-of-type,h6:first-of-type{border-bottom:1px solid gray}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{color:inherit}:not(pre)>code{background:#000;color:#fff;padding:.3em}ul,ol{padding-left:1em}ul{list-style-type:square}blockquote{border-left:.3em solid #000;padding-left:.3em}table{border-collapse:collapse}table th{background:#000;color:#fff;font-weight:normal}table td,table th{padding:.2em .5em}table td{border:1px solid gray}.rev-table{width:100%}.rev-table td{border:none}.rev-table td.ts{white-space:nowrap}.header{margin-bottom:.5em}.md{margin-top:.5em}.md>*,.md p{margin:0 0 .5em 0}nav{margin-bottom:.5em}.timestamp{color:gray}a.wikilink{text-decoration:none;color:#01a049;font-style:italic}a.wikilink:hover{text-decoration:underline}.link-button,button,input[type=submit]{border:none;padding:.75em;background:gray;text-align:center;text-decoration:none;color:#000;display:inline-block;font-size:1rem}.link-button:hover,button:hover,input[type=submit]:hover{background-image:linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2))}.link-button.view-page,button.view-page,input[type=submit].view-page{background-color:#76cd26}.link-button.edit-page,button.edit-page,input[type=submit].edit-page{background-color:#75bbfd}.link-button.page-revisions,button.page-revisions,input[type=submit].page-revisions{background-color:#f97306}.link-button.save,button.save,input[type=submit].save{background-color:#06c2ac}.link-button.next-page,button.next-page,input[type=submit].next-page{background-color:#5170d7}.link-button.prev-page,button.prev-page,input[type=submit].prev-page{background-color:#bc13fe}.edit-form textarea{resize:vertical;width:100%;height:70vh;border:1px solid gray}/*# sourceMappingURL=style.css.map */ +html{scrollbar-color:#000 #d3d3d3}*{box-sizing:border-box}body{font-family:"Fira Sans","Noto Sans","Segoe UI",Verdana,sans-serif;font-weight:300;margin:0;min-height:100vh}main{max-width:50em;padding:0 1em 1em 1em;margin-left:auto;margin-right:auto;position:relative}strong{font-weight:600}h1,h2,h3,h4,h5,h6{margin:0 0 .5em 0;font-weight:500}h1:first-of-type,h2:first-of-type,h3:first-of-type,h4:first-of-type,h5:first-of-type,h6:first-of-type{border-bottom:1px solid gray}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{color:inherit}:not(pre)>code{background:#000;color:#fff;padding:.3em}ul,ol{padding-left:1em}ul{list-style-type:square}blockquote{border-left:.3em solid #000;padding-left:.3em}table{border-collapse:collapse}table th{background:#000;color:#fff;font-weight:normal}table td,table th{padding:.2em .5em}table td{border:1px solid gray}.rev-table{width:100%}.rev-table td{border:none}.rev-table td.ts{white-space:nowrap}.md{margin-top:.5em}.md>*,.md p{margin:0 0 .5em 0}nav{margin-bottom:.5em}.timestamp{color:gray}a.wikilink{text-decoration:none;color:#0165fc;font-style:italic}a.wikilink:hover{text-decoration:underline}.link-button,button,input[type=submit]{border:none;padding:.75em;background:gray;text-align:center;text-decoration:none;color:#000;display:inline-block;font-size:1rem}.link-button:hover,button:hover,input[type=submit]:hover{background-image:linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2))}.link-button.view-page,button.view-page,input[type=submit].view-page{background-color:#76cd26}.link-button.edit-page,button.edit-page,input[type=submit].edit-page{background-color:#75bbfd}.link-button.page-revisions,button.page-revisions,input[type=submit].page-revisions{background-color:#f97306}.link-button.save,button.save,input[type=submit].save{background-color:#06c2ac}.link-button.next-page,button.next-page,input[type=submit].next-page{background-color:#5170d7}.link-button.prev-page,button.prev-page,input[type=submit].prev-page{background-color:#bc13fe}.link-button.search,button.search,input[type=submit].search{background-color:#fac205}input[type=search],input[type=text]{border:1px solid gray;padding:.75em;width:100%}.edit-form textarea{resize:vertical;width:100%;height:70vh;border:1px solid gray}.highlight{background-color:#ff0}.dialog{width:100%;background:#fff;padding:1em;border:1px solid gray}.flex-space{display:flex;justify-content:space-between}.error{color:red}img{max-width:100%}/*# sourceMappingURL=style.css.map */ diff --git a/static/style.css.map b/static/style.css.map index e66394e..1bad354 100644 --- a/static/style.css.map +++ b/static/style.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["../src/style.sass"],"names":[],"mappings":"AAAA,KACI,6BAEJ,EACI,sBAEJ,KACI,kEACA,gBACA,SACA,iBAEJ,KACI,WACA,sBACA,iBACA,kBAEJ,OACI,gBAEJ,kBAGI,SACA,gBAHA,sGACI,6BAGJ,8BACI,cAER,eACI,gBACA,WACA,aAEJ,MACI,iBACJ,GACI,uBACJ,WACI,4BACA,kBACJ,MACI,yBAEA,SACI,gBACA,WACA,mBACJ,kBACI,kBACJ,SACI,sBAER,WACI,WACA,cACI,YACA,iBACI,mBAEZ,QACI,mBAEJ,IACI,gBACA,YACI,kBAER,IACI,mBAEJ,WACI,WAEJ,WACI,qBACA,cACA,kBACA,iBACI,0BAER,uCACI,YACA,cACA,gBACA,kBACA,qBACA,WACA,qBACA,eACA,yDAEI,yEAEJ,qEACI,yBACJ,qEACI,yBACJ,oFACI,yBACJ,sDACI,yBACJ,qEACI,yBACJ,qEACI,yBAGJ,oBACI,gBACA,WACA,YACA","file":"style.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["../src/style.sass"],"names":[],"mappings":"AAAA,KACI,6BAEJ,EACI,sBAEJ,KACI,kEACA,gBACA,SACA,iBAEJ,KACI,eACA,sBACA,iBACA,kBACA,kBAEJ,OACI,gBAEJ,kBAGI,kBACA,gBAHA,sGACI,6BAGJ,8BACI,cAER,eACI,gBACA,WACA,aAEJ,MACI,iBACJ,GACI,uBACJ,WACI,4BACA,kBACJ,MACI,yBAEA,SACI,gBACA,WACA,mBACJ,kBACI,kBACJ,SACI,sBAER,WACI,WACA,cACI,YACA,iBACI,mBAEZ,IACI,gBACA,YACI,kBAER,IACI,mBAEJ,WACI,WAEJ,WACI,qBACA,cACA,kBACA,iBACI,0BAER,uCACI,YACA,cACA,gBACA,kBACA,qBACA,WACA,qBACA,eACA,yDAEI,yEAEJ,qEACI,yBACJ,qEACI,yBACJ,oFACI,yBACJ,sDACI,yBACJ,qEACI,yBACJ,qEACI,yBACJ,4DACI,yBAER,oCACI,sBACA,cACA,WAGA,oBACI,gBACA,WACA,YACA,sBAER,WACI,sBAEJ,QACI,WACA,gBACA,YACA,sBAEJ,YACI,aACA,8BAEJ,OACI,UAEJ,IACI","file":"style.css"} \ No newline at end of file diff --git a/watch-css.sh b/watch-css.sh index 9a1e4f6..acc1739 100755 --- a/watch-css.sh +++ b/watch-css.sh @@ -1,2 +1,2 @@ #!/bin/sh -npx sass --watch -s compressed src/style.sass:static/style.css \ No newline at end of file +npx -p sass sass --watch -s compressed src/style.sass:static/style.css & npx esbuild --bundle src/client.js --outfile=static/client.js --sourcemap --minify --watch \ No newline at end of file