diff --git a/assets/css/article.css b/assets/css/article.css
new file mode 100644
index 0000000..cbec30d
--- /dev/null
+++ b/assets/css/article.css
@@ -0,0 +1,75 @@
+article {
+ display: grid;
+ grid-template-areas: 'header' 'toc' 'content';
+ grid-template-columns: 100%;
+ grid-template-rows: repeat(3, auto);
+}
+
+article > header {
+ grid-area: header;
+ margin-bottom: 2rem;
+}
+
+article > header > i {
+ color: var(--accent);
+ display: block;
+}
+
+.toc-container {
+ grid-area: toc;
+ display: grid;
+ place-items: center;
+
+ width: fit-content;
+
+ margin: 0 auto;
+ padding: 1rem 4rem;
+ background-color: var(--grey3);
+ border-radius: .5rem;
+ box-shadow: 0 1rem 2rem var(--grey1);
+}
+
+.toc-container > .toc {
+ width: max-content;
+ display: grid;
+}
+
+.toc > * {
+ width: 100%;
+ display: block;
+}
+
+.toc-title {
+ margin-top: 0;
+ font-size: 1.25rem;
+ color: var(--primary);
+}
+
+.toc-h2 {
+ margin-left: .5rem;
+ font-size: .8rem;
+}
+
+.toc-h3 {
+ margin-left: 1rem;
+ font-size: .75rem;
+}
+
+.toc-h4 {
+ margin-left: 1.5rem;
+ font-size: .7rem;
+}
+
+.toc-h5 {
+ margin-left: 2rem;
+ font-size: .65rem;
+}
+
+.toc-h6 {
+ margin-left: 2.5rem;
+ font-size: .6rem;
+}
+
+article > .content {
+ grid-area: content;
+}
diff --git a/assets/css/colors.css b/assets/css/colors.css
new file mode 100644
index 0000000..b934a6a
--- /dev/null
+++ b/assets/css/colors.css
@@ -0,0 +1,109 @@
+:root {
+ /* COLORS */
+ --red: #EF5255;
+ --red1: #BF3638;
+ --red2: #D5484A;
+ --red3: #EF5255;
+ --red4: #FA7A7C;
+ --red5: #FA999A;
+
+ --orange: #EB801B;
+ --orange1: #AF6118;
+ --orange2: #DA7516;
+ --orange3: #EB801B;
+ --orange4: #F99434;
+ --orange5: #F9AE67;
+
+ --yellow: #F4C025;
+ --yellow1: #BD920F;
+ --yellow2: #DFAC11;
+ --yellow3: #F4C025;
+ --yellow4: #FFD147;
+ --yellow5: #FFE38F;
+
+ --pear: #AED651;
+ --pear1: #7D9A37;
+ --pear2: #96BB3E;
+ --pear3: #AED651;
+ --pear4: #C2E571;
+ --pear5: #DBF1A7;
+
+ --green: #72D661;
+ --green1: #53A545;
+ --green2: #61C350;
+ --green3: #72D661;
+ --green4: #93E684;
+ --green5: #BCF0B2;
+
+ --sea: #3DDF89;
+ --sea1: #2AA764;
+ --sea2: #2ACB75;
+ --sea3: #3DDF89;
+ --sea4: #5DEEA1;
+ --sea5: #A9F4CC;
+
+ --cyan: #4CDCDF;
+ --cyan1: #2CA3A5;
+ --cyan2: #2DCACD;
+ --cyan3: #4CDCDF;
+ --cyan4: #6BE8EB;
+ --cyan5: #B7EFF0;
+
+ --blue: #4C9CEF;
+ --blue1: #1C67B5;
+ --blue2: #2A83DF;
+ --blue3: #4C9CEF;
+ --blue4: #74B6FB;
+ --blue5: #A3CEFA;
+
+ --indigo: #4C6DEF;
+ --indigo1: #2143CA;
+ --indigo2: #3457E5;
+ --indigo3: #4C6DEF;
+ --indigo4: #748FFB;
+ --indigo5: #B1C0FC;
+
+ --purple: #967CF4;
+ --purple1: #613FD9;
+ --purple2: #7C5DE9;
+ --purple3: #967CF4;
+ --purple4: #BCAAFD;
+ --purple5: #CFC2FE;
+
+ --magenta: #E175DB;
+ --magenta1: #B63AB0;
+ --magenta2: #D152CB;
+ --magenta3: #E175DB;
+ --magenta4: #EC9AEF;
+ --magenta5: #EFB1F1;
+
+ --pink: #EE588F;
+ --pink1: #D0356D;
+ --pink2: #E2407C;
+ --pink3: #EE588F;
+ --pink4: #FA80AC;
+ --pink5: #FBA7C6;
+
+ --grey1: #00001F;
+ --grey2: #10102F;
+ --grey3: #20203F;
+ --grey4: #30304F;
+ --grey5: #40405F;
+ --grey6: #50506F;
+ --grey7: #60607F;
+ --grey8: #70708F;
+ --grey9: #80809F;
+ --grey10: #9090AF;
+ --grey11: #A0A0BF;
+ --grey12: #B0B0CF;
+ --grey13: #C0C0DF;
+ --grey14: #D0D0EF;
+ --grey15: #E0E0FF;
+
+ /* ALIASES */
+ --primary: var(--sea);
+ --accent: var(--cyan);
+ --accent2: var(--blue);
+ --surface: var(--grey2);
+ --text: var(--grey15);
+}
\ No newline at end of file
diff --git a/assets/css/scaling.css b/assets/css/scaling.css
new file mode 100644
index 0000000..07e45cb
--- /dev/null
+++ b/assets/css/scaling.css
@@ -0,0 +1,66 @@
+@media screen and (min-width: 1px) {
+ :root {
+ font-size: 12px;
+ }
+
+}
+@media screen and (min-width: 300px) {
+ :root {
+ font-size: 13pt;
+ }
+}
+@media screen and (min-width: 400px) {
+ :root {
+ font-size: 14pt;
+ }
+}
+@media screen and (min-width: 500px) {
+ :root {
+ font-size: 15pt;
+ }
+}
+@media screen and (min-width: 600px) {
+ :root {
+ font-size: 16pt;
+ }
+}
+@media screen and (min-width: 700px) {
+ :root {
+ font-size: 17pt;
+ }
+}
+@media screen and (min-width: 802px) {
+ :root {
+ font-size: 12pt;
+ }
+}
+@media screen and (min-width: 1000px) {
+ :root {
+ font-size: 13pt;
+ }
+}
+@media screen and (min-width: 1200px) {
+ :root {
+ font-size: 14pt;
+ }
+}
+@media screen and (min-width: 1500px) {
+ :root {
+ font-size: 15pt;
+ }
+}
+@media screen and (min-width: 1800px) {
+ :root {
+ font-size: 16pt;
+ }
+}
+@media screen and (min-width: 2500px) {
+ :root {
+ font-size: 17pt;
+ }
+}
+@media screen and (min-width: 3000px) {
+ :root {
+ font-size: 19pt;
+ }
+}
diff --git a/assets/css/sitemap.css b/assets/css/sitemap.css
new file mode 100644
index 0000000..0ef2bd5
--- /dev/null
+++ b/assets/css/sitemap.css
@@ -0,0 +1,22 @@
+body {
+ display: flex;
+ flex-direction: column;
+}
+
+.sitemap-container {
+ display: grid;
+ place-items: center;
+
+ width: fit-content;
+
+ margin: 2rem auto;
+ padding: 1rem 4rem;
+ background-color: var(--grey3);
+ border-radius: .5rem;
+ box-shadow: 0 1rem 2rem var(--grey1);
+}
+
+.sitemap-dir > .sitemap-dir {
+ margin: 0 auto;
+ padding: 0 0 .5rem 1rem;
+}
\ No newline at end of file
diff --git a/assets/css/syntax.css b/assets/css/syntax.css
new file mode 100644
index 0000000..0f7eef0
--- /dev/null
+++ b/assets/css/syntax.css
@@ -0,0 +1,152 @@
+.hljs-keyword {
+ color: var(--purple);
+}
+
+.hljs-built_in {
+ color: var(--green);
+}
+
+.hljs-type {
+ color: var(--yellow);
+}
+
+.hljs-literal {
+ color: var(--orange);
+}
+
+.hljs-number {
+ color: var(--blue);
+}
+
+.hljs-punctuation {
+ color: var(--grey14);
+}
+
+.hljs-property {
+ color: var(--cyan);
+}
+
+.hljs-regexp {
+ color: var(--red);
+}
+
+.hljs-string {
+ color: var(--yellow);
+}
+
+.hljs-char.escape {
+ color: var(--cyan);
+}
+
+.hljs-subst {
+ color: var(--text);
+}
+
+.hljs-symbol {
+ color: var(--blue);
+}
+
+.hljs-variable {
+ color: var(--orange);
+}
+
+.hljs-variable.language {
+ color: var(--yellow);
+}
+
+.hljs-variable.constant {
+ color: var(--red);
+}
+
+.hljs-title {
+ color: var(--red);
+}
+
+.hljs-title.class {
+ color: var(--cyan);
+}
+
+.hljs-title.class.inherited {
+ color: var(--purple);
+}
+
+.hljs-title.function {
+ color: var(--blue);
+}
+
+.hljs-params {
+ color: var(--green);
+}
+
+.hljs-comment {
+ color: var(--grey9);
+ font-style: italic;
+}
+
+.hljs-doctag {
+ color: var(--yellow);
+}
+
+.hljs-meta {
+ color: var(--cyan);
+}
+
+.hljs-meta .hljs-keyword {
+ color: var(--indigo);
+}
+
+.hljs-section {
+ color: var(--green);
+}
+
+.hljs-tag {
+ color: var(--red);
+}
+
+.hljs-name {
+ color: var(--blue);
+}
+
+.hljs-attr {
+ color: var(--orange);
+}
+
+.hljs-attribute {
+ color: var(--green);
+}
+
+.hljs-selector-tag {
+ color: var(--red);
+}
+
+.hljs-selector-id {
+ color: var(--blue);
+}
+
+.hljs-selector-class {
+ color: var(--orange);
+}
+
+.hljs-selector-attr {
+ color: var(--purple);
+}
+
+.hljs-selector-pseudo {
+ color: var(--green);
+}
+
+.hljs-template-tag {
+ color: var(--purple);
+}
+
+.hljs-template-variable {
+ color: var(--cyan);
+}
+
+.hljs-addition {
+ color: var(--green);
+}
+
+.hljs-deletion {
+ color: var(--red);
+}
\ No newline at end of file
diff --git a/assets/css/theme.css b/assets/css/theme.css
new file mode 100644
index 0000000..3b286b2
--- /dev/null
+++ b/assets/css/theme.css
@@ -0,0 +1,149 @@
+* {
+ margin: 0;
+ padding: 0;
+ border: 0 none transparent;
+
+ box-sizing: border-box;
+ scroll-behavior: smooth;
+
+ font-family: 'sans-serif';
+ font-size: .85rem;
+ line-height: 1.5;
+
+ color: var(--text);
+}
+
+html {
+ display: grid;
+ place-items: center;
+ width: 100%;
+ background-color: var(--surface);
+}
+
+body {
+ margin: 5vh 0 10vh 0;
+ width: min(95vw, 75ch);
+}
+
+header {
+ color: var(--primary);
+ font-size: 3rem;
+ text-align: center;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: var(--accent);
+ font-weight: normal;
+
+ margin: 1.25em 0 .25em 0;
+}
+
+h1 {
+ color: var(--primary);
+ font-size: 2rem;
+}
+
+h2 {
+ font-size: 1.65rem;
+}
+
+h3 {
+ font-size: 1.35rem;
+}
+
+h4 {
+ font-size: 1rem;
+}
+
+h5 {
+ font-size: .85rem;
+}
+
+h6 {
+ font-size: .75rem;
+}
+
+p {
+ margin: .5em 0 .25em 0;
+ text-align: justify;
+}
+
+a {
+ color: var(--accent2);
+}
+
+blockquote {
+ margin: 1rem;
+ padding: .5rem 1rem;
+
+ border-left: .2rem solid var(--primary);
+ background-color: var(--grey3);
+}
+
+ul, ol {
+ margin: 1rem 0 1rem 2rem;
+}
+
+ul ul, ul ol, ol ol, ol ul {
+ margin: .25rem 0 .25rem 1rem;
+}
+
+table {
+ display: block;
+ width: 100%;
+ overflow-x: auto;
+ white-space: nowrap;
+ border-collapse: collapse;
+}
+
+table tbody {
+ display: table;
+ width: 100%;
+}
+
+tr {
+ width: 200%;
+ background-color: var(--grey3);
+}
+
+tr:nth-child(even) {
+ background-color: var(--grey4);
+}
+
+th {
+ border-bottom: .1rem solid var(--text);
+}
+
+th, td {
+ text-align: left;
+ padding: .25rem 1rem;
+}
+
+code {
+ background-color: var(--grey3);
+ font-family: monospace;
+ padding: .1rem .2rem;
+ margin: 0 .1rem;
+ border-radius: .2rem;
+}
+
+pre > code {
+ margin: 1rem 0;
+ padding: 1rem;
+ border-radius: .5rem;
+ box-shadow: 0 1rem 2rem var(--grey1);
+
+ display: block;
+ overflow-x: auto;
+ white-space: nowrap;
+}
+
+code * {
+ font-family: monospace;
+}
+
+img {
+ margin: 1rem 0;
+ border-radius: .5rem;
+ box-shadow: 0 1rem 2rem var(--grey1);
+}
\ No newline at end of file
diff --git a/assets/images/design-res-promo.svg b/assets/images/design-res-promo.svg
new file mode 100644
index 0000000..8e26ed9
--- /dev/null
+++ b/assets/images/design-res-promo.svg
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config.json b/config.json
new file mode 100644
index 0000000..2ef460a
--- /dev/null
+++ b/config.json
@@ -0,0 +1,7 @@
+{
+ "contentDir": "content",
+ "assetsDir": "assets",
+
+ "serverPort": "8789",
+ "serverName": "qwik"
+}
\ No newline at end of file
diff --git a/content/components/code.njk b/content/components/code.njk
new file mode 100644
index 0000000..495f139
--- /dev/null
+++ b/content/components/code.njk
@@ -0,0 +1,8 @@
+{% macro import(path, lang) %}
+```{{ lang }}
+{% set code %}
+{% include path %}
+{% endset %}
+{{ code | safe | replace(" ", "•") }}
+```
+{% endmacro %}
\ No newline at end of file
diff --git a/content/components/toc.njk b/content/components/toc.njk
new file mode 100644
index 0000000..4dd0e44
--- /dev/null
+++ b/content/components/toc.njk
@@ -0,0 +1,6 @@
+{% macro header(size, text) %}
+
+ <{{ size }}>
+ {{ text }}
+ {{ size }}>
+{% endmacro %}
\ No newline at end of file
diff --git a/content/errors/404.njk b/content/errors/404.njk
new file mode 100644
index 0000000..93e56b5
--- /dev/null
+++ b/content/errors/404.njk
@@ -0,0 +1,15 @@
+
+
+
+ {% include "templates/defaultTags.njk" %}
+ {{ serverName }} - Error 404
+
+
+ Error 404
+
+ The page you are looking for doesn't exist.
+ Consider going to the main page .
+ {{ serverName }}
+
+
+
\ No newline at end of file
diff --git a/content/pages/docs/intro.md b/content/pages/docs/intro.md
new file mode 100644
index 0000000..37e1f59
--- /dev/null
+++ b/content/pages/docs/intro.md
@@ -0,0 +1,97 @@
+%%-
+title: qwik cms
+header: qwik cms intro
+date: 8th August 2021
+-%%
+
+# Introduction
+BurnyLlama started working on this project as a part of [qwik](https://qwik.space).
+We tried to find a good and simple CMS solution, but we couldn't really find something that
+worked for and suited us. We decided to make our own, and that's when the `qwik-cms` repo was created.
+
+## Basic ideas
+We wanted to keep it simple, yet powerful. At first we only wanted to use *include/import statements*,
+but later we came to the realization that you could add other QoL things, like automatically generating
+a table of contents for articles.
+
+We also want to make development of content be as fast as possible. Especially with when it comes to
+writing articles. Writing articles in markdown can feel kinda nice as it (at least imo) saves a lot
+of time compared to writing out HTML.
+
+## Underlying technologies
+Thanks to all the technologies used, the CMS is really hackable and can be used in different ways
+depending on your liking. There are three main ways of creating content:
+1. Normal HTML
+2. Nunjacks (an HTML templating language)
+3. Markdown
+
+
+## Views on bloat
+*This all sounds kinda bloated?*
+I hear you asking... and yes, I am afraid this is a bit bloated (sadly). Although I wouldn't call it
+bloated if you actually use the features. The project does pull in a few dependencies, and making the
+system more modular could potentially make som of those dependencies optional, but as of now we
+depend on:
+* Express - the server framework
+* nunjucks - the templating language that does very heavy lifting in this CMS.
+* nunjucks-markdown - adds support for markdown in nunjucks
+* marked - the actual renderer for the markdown (used by `nunjucks-markdown`)
+* highlight.js - provides syntax highlighting for codeblocks in markdown.
+* jsdom - makes us able to use DOM operations server-side (used to generate the table of contents)
+* chokidar - used to reload nunjucks templates if they change on the disk (without having to restart the server)
+
+So yes, we sure do have a lot of dependencies, but they are all used, so there are no dependencies just "lying around".
+
+# Installation
+The installation process will be quite trivial if you are used to node-based projects.
+
+## Prerequesites
+We will assume that you have `node` and `npm` installed already. Otherwise make sure to install those.
+
+## Process
+The process is really simple:
+```bash
+git clone https://git.qwik.space/BurnyLlama/qwik-cms
+cd qwik-cms
+npm i
+node index.js
+```
+`npm i` installs all needed dependencies.
+
+# Configuration
+The CMS can be configured from `config.json` and the default config looks like this:
+```json
+{
+ "contentDir": "content",
+ "assetsDir": "assets",
+
+ "serverPort": "8789",
+ "serverName": "qwik"
+}
+```
+
+## Explanation
+All of the options are kind of self-explanatory, but anyways:
+
+### contentDir
+Specifies which directory the content is in.
+
+Default: `content`
+
+### assetsDir
+Specifies which directory the assets are in. These items will be statically available on (your site's)
+`/assets/`. I recommend storing CSS, images, etc. here.
+
+Default: `assets`
+
+### serverPort
+The port the server should run on.
+
+Default: `8789`
+
+### serverName
+This can be accessed in any page/template by using `{{ serverName }}`
+
+Default: `qwik`
+
+# Usage
diff --git a/content/pages/sitemap.njk b/content/pages/sitemap.njk
new file mode 100644
index 0000000..9bdf417
--- /dev/null
+++ b/content/pages/sitemap.njk
@@ -0,0 +1,16 @@
+
+
+
+ {% include "templates/defaultTags.njk" %}
+
+ Site Map
+
+
+
+
+ {{ siteMap() | safe }}
+
+
+
\ No newline at end of file
diff --git a/content/templates/article.njk b/content/templates/article.njk
new file mode 100644
index 0000000..7294c78
--- /dev/null
+++ b/content/templates/article.njk
@@ -0,0 +1,30 @@
+
+
+
+ {% include "./defaultTags.njk" %}
+
+
+ {% block head %}
+ {{ serverName }}
+ {% endblock %}
+
+
+
+
+ {% block header %}{% endblock %}
+
+
+
+
+
Table of Contents
+ {% for tocLink in tocLinks %}
+ {{ tocLink | safe }}
+ {% endfor %}
+
+
+
+
+ {% block main %}{% endblock %}
+
+
+
\ No newline at end of file
diff --git a/content/templates/article_md.njk b/content/templates/article_md.njk
new file mode 100644
index 0000000..ccec1f9
--- /dev/null
+++ b/content/templates/article_md.njk
@@ -0,0 +1,31 @@
+
+
+
+ {% include "./defaultTags.njk" %}
+
+
+ {% block head %}
+ {{ serverName }}
+ {% endblock %}
+
+
+
+
+ {% block header %}{% endblock %}
+
+
+
+
+
Table of Contents
+ {% for tocLink in tocLinks %}
+ {{ tocLink | safe }}
+ {% endfor %}
+
+
+
+ {% markdown %}
+ {% block main %}{% endblock %}
+ {% endmarkdown %}
+
+
+
\ No newline at end of file
diff --git a/content/templates/defaultTags.njk b/content/templates/defaultTags.njk
new file mode 100644
index 0000000..af78dfe
--- /dev/null
+++ b/content/templates/defaultTags.njk
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/content/templates/external_md.njk b/content/templates/external_md.njk
new file mode 100644
index 0000000..0d71aaf
--- /dev/null
+++ b/content/templates/external_md.njk
@@ -0,0 +1,30 @@
+
+
+
+ {% include "templates/defaultTags.njk" %}
+
+
+ {{ externalMeta.title if externalMeta.title else serverName }}
+
+
+
+
+ {{ externalMeta.header }}
+ {{ externalMeta.date }}
+
+
+
+
+
Table of Contents
+ {% for tocLink in tocLinks %}
+ {{ tocLink | safe }}
+ {% endfor %}
+
+
+
+ {% markdown %}
+ {{ externalMarkdown | safe }}
+ {% endmarkdown %}
+
+
+
\ No newline at end of file
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..b49297a
--- /dev/null
+++ b/index.js
@@ -0,0 +1,44 @@
+import fs from 'fs'
+import express from 'express'
+
+import njk from 'nunjucks'
+
+import { requestHandler } from './libs/requestHandler.js'
+import { utils } from './libs/utils/utils.js'
+import { nunjacksConfig } from './libs/nunjucksConfig.js'
+
+
+// Load in config
+const ConfigFile = fs.readFileSync('./config.json')
+const Config = JSON.parse(ConfigFile)
+
+
+
+// Create a server object
+const Server = express()
+
+
+
+// Configure the assets directory
+Server.use('/assets', express.static(Config.assetsDir))
+
+// Configure nunjacks
+nunjacksConfig(njk, Server, Config)
+
+// Generate utils
+utils.generate()
+
+
+
+// Send all requests to the requestHandler.
+Server.get('*', (req, res) => requestHandler(req, res, Config))
+
+
+
+// Start the server
+Server.listen(
+ Config.serverPort,
+ () => {
+ console.log(`Started server on ${Config.serverPort}.`)
+ }
+)
\ No newline at end of file
diff --git a/libs/codeHighlighter.js b/libs/codeHighlighter.js
new file mode 100644
index 0000000..7b1a51a
--- /dev/null
+++ b/libs/codeHighlighter.js
@@ -0,0 +1,16 @@
+import hljs from 'highlight.js'
+
+export function highlight(code, lang) {
+ // Check if hljs recognises the language, else assume 'plaintext'.
+ const language = hljs.getLanguage(lang) ? lang : 'plaintext'
+
+ // Highlight it with the corresponding language.
+ return hljs.highlight(
+ // Switch out bullet points (•) to spaces (for proper indentation).
+ code.replace(/•/g, " "), { language })
+ // Replace newlines with tags.
+ .value.replace(/\n/g, " ")
+ // Replace spaces with ' ' to forcefully render them.
+ .replace(/ /g, " "
+ )
+}
\ No newline at end of file
diff --git a/libs/externalContext.js b/libs/externalContext.js
new file mode 100644
index 0000000..0268290
--- /dev/null
+++ b/libs/externalContext.js
@@ -0,0 +1,20 @@
+export function parseExternalContext(externalContext) {
+ // If there's no external context, return nothing.
+ if (!externalContext)
+ return {}
+
+ // Remove start and end tag ↓ Only care about the first "externalConext"
+ externalContext = externalContext[0].replace(/%%-\n|-%%\n/g, "")
+
+ let parsedContext = {}
+ externalContext.split("\n").forEach(line => {
+ // If the line is falsey; leave.
+ if (!line) return
+
+ // Assign properties to parsedContext and give them their corresponding values.
+ line = line.split(/:/)
+ parsedContext[line[0]] = line[1].replace(/^\s/, "")
+ })
+
+ return parsedContext
+}
\ No newline at end of file
diff --git a/libs/generateContext.js b/libs/generateContext.js
new file mode 100644
index 0000000..a8b8d18
--- /dev/null
+++ b/libs/generateContext.js
@@ -0,0 +1,30 @@
+import fs from 'fs'
+import { JSDOM } from 'jsdom'
+import { parseExternalContext } from './externalContext.js'
+
+const ConfigFile = fs.readFileSync('./config.json')
+const Config = JSON.parse(ConfigFile)
+
+function generateToc(dom) {
+ // Get all ToC anchors from the DOM
+ const tocAnchors = dom.window.document.querySelectorAll(".toc-anchor")
+
+ // Generate links to lead to those anvhors.
+ let tocLinks = []
+ tocAnchors.forEach(anchor => tocLinks.push(`${anchor.getAttribute('data-orig-text')} `))
+
+ return tocLinks
+}
+
+export function generateContext(prerenderedNjk, externalContext = undefined) {
+ // Create a 'virtual DOM' for analysis.
+ const dom = new JSDOM(prerenderedNjk)
+
+ // Generate respective parts of the context.
+ return {
+ serverName: Config.serverName,
+ tocLinks: generateToc(dom),
+ externalMeta: externalContext ? parseExternalContext(externalContext) : undefined
+ }
+}
+
diff --git a/libs/markedRenderer.js b/libs/markedRenderer.js
new file mode 100644
index 0000000..a19789b
--- /dev/null
+++ b/libs/markedRenderer.js
@@ -0,0 +1,22 @@
+import { highlight } from "./codeHighlighter.js"
+
+export const markedRenderer = {
+ // Rendering of headings (add an anchor above all headings).
+ heading(text, level) {
+ return `
+
+
+ ${text}
+
+ `
+ },
+
+ // Render code properly, and syntax highlight it.
+ code(code, lang, escaped) {
+ return `
+
+ ${highlight(code, lang)}
+
+ `
+ }
+}
\ No newline at end of file
diff --git a/libs/nunjucksConfig.js b/libs/nunjucksConfig.js
new file mode 100644
index 0000000..d313d63
--- /dev/null
+++ b/libs/nunjucksConfig.js
@@ -0,0 +1,31 @@
+import njkMarkdown from 'nunjucks-markdown'
+import marked from 'marked'
+
+import { markedRenderer } from './markedRenderer.js'
+import { utils } from './utils/utils.js'
+
+
+export function nunjacksConfig(njk, express, Config) {
+ // Configure the nunjucks environment (HTML templating)
+ const njkEnv = njk.configure(
+ Config.contentDir,
+ {
+ autoescape: true, // Automatically escape HTML aka a '<' will become '<'
+ watch: true, // Automatically reload all templates if they change on disk.
+ trimBlocks: true, // Remove trailing newlines from tags
+ lstripBlocks: true, // Automatically remove leading whitespace from tags
+ express: express // Use the express server. (Currently obsolete, I think.)
+ }
+ )
+
+ njkEnv.addGlobal('siteMap', entrypoint => utils.values.siteMap.render(entrypoint ? entrypoint : "/"))
+
+ // Configure marked (markdown parser)
+ marked.use({
+ gfm: true, // Use GitHub formatting?
+ renderer: markedRenderer // Use my own custom rendering for som tags
+ })
+
+ // Let nunjucks use markdown.
+ njkMarkdown.register(njkEnv, marked)
+}
\ No newline at end of file
diff --git a/libs/requestHandler.js b/libs/requestHandler.js
new file mode 100644
index 0000000..4cb0d58
--- /dev/null
+++ b/libs/requestHandler.js
@@ -0,0 +1,21 @@
+import fs from 'fs'
+import { mdRenderer, njkRenderer } from './siteRenderer.js'
+
+
+// Handle all request and try to find a corresponding file/template.
+export function requestHandler(req, res, Config) {
+ // Check for njk files first
+ if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}.njk`))
+ return res.send(njkRenderer(`./${Config.contentDir}/pages/${req.path}.njk`))
+ if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}/index.njk`))
+ return res.send(njkRenderer(`./${Config.contentDir}/pages/${req.path}/index.njk`))
+
+ // Secondly search for markdown
+ if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}.md`))
+ return res.send(mdRenderer(`./${Config.contentDir}/pages/${req.path}.md`))
+ if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}/index.md`))
+ return res.send(mdRenderer(`./${Config.contentDir}/pages/${req.path}/index.md`))
+
+ // If no matching file is found, return a 404 error.
+ return res.status(404).send(njkRenderer(`./${Config.contentDir}/errors/404.njk`))
+}
\ No newline at end of file
diff --git a/libs/siteRenderer.js b/libs/siteRenderer.js
new file mode 100644
index 0000000..984fc01
--- /dev/null
+++ b/libs/siteRenderer.js
@@ -0,0 +1,36 @@
+import fs from 'fs'
+import njk from 'nunjucks'
+import { generateContext } from './generateContext.js'
+
+// Load in config
+const ConfigFile = fs.readFileSync('./config.json')
+const Config = JSON.parse(ConfigFile)
+
+export function njkRenderer(path) {
+ // Read in the template
+ const njkFile = fs.readFileSync(path).toString()
+ // Pre-render it for analysis while rendering context
+ const prerenderedNjk = njk.renderString(njkFile)
+
+ // Generate proper context and make a final render of the template.
+ const context = generateContext(prerenderedNjk)
+ return njk.renderString(njkFile, context)
+}
+
+export function mdRenderer(path) {
+ // Load in the njk template and markdown
+ const njkFile = fs.readFileSync(`${Config.contentDir}/templates/external_md.njk`).toString()
+ const externalMarkdownFile = fs.readFileSync(path).toString()
+
+ // Separate the actual markdown from potential 'externalContext'
+ const externalMarkdown = externalMarkdownFile.replace(/^%%-\n[\S\s]*-%%\n/, "").replace(/```\w*[\s\S]*?```/g, match => match.replace(/ /g, "•"))
+ const externalContext = externalMarkdownFile.match(/^%%-\n[\S\s]*-%%\n/)
+
+ // Pre-render the template for analysis during context generation.
+ const prerenderedNjk = njk.renderString(njkFile, { externalMarkdown })
+
+ // Generate the context and add the externalMarkdown to the context, then render the template.
+ let context = generateContext(prerenderedNjk, externalContext)
+ context.externalMarkdown = externalMarkdown
+ return njk.renderString(njkFile, context)
+}
\ No newline at end of file
diff --git a/libs/utils/siteMap.js b/libs/utils/siteMap.js
new file mode 100644
index 0000000..270a80e
--- /dev/null
+++ b/libs/utils/siteMap.js
@@ -0,0 +1,70 @@
+import fs from 'fs/promises'
+import path from 'path'
+
+async function handlePath(dirName, siteMap) {
+ // Get all directories in the 'dirName'
+ const dirs = await fs.readdir(dirName)
+
+ // For each file in the directory: check if it is a
+ // file or a folder, if a folder recursively run this
+ // function in that folder.
+ for (const dirIndex in dirs) {
+ const file = dirs[dirIndex]
+ const fullPath = path.join(dirName, file)
+ const fileStats = await fs.stat(fullPath)
+
+ if (fileStats.isDirectory())
+ siteMap[fullPath.replace(/^[\s\S]+\/pages/, "")] = {
+ path: fullPath,
+ address: fullPath.replace(/^[\s\S]+\/pages/, ""),
+ type: "directory",
+ children: await handlePath(fullPath, {})
+ }
+ else
+ siteMap[fullPath.replace(/^[\s\S]+\/pages/, "").replace(/\.[a-z]+$/, "")] = {
+ path: fullPath,
+ address: fullPath.replace(/^[\s\S]+\/pages/, "").replace(/\.[a-z]+$/, ""),
+ type: "file"
+ }
+ }
+
+ return siteMap
+}
+
+function renderSiteMap(siteMap, entrypoint) {
+ // Make a template for the sitemap and recursively run
+ // for all directories with children.
+ return `
+
+ `
+}
+
+export async function generateSiteMap(Config) {
+ // Generate a site map and return it and a render-function.
+ const siteMap = await handlePath(`${Config.contentDir}/pages`, {})
+
+ return {
+ siteMap,
+ render: entrypoint => renderSiteMap(siteMap, entrypoint)
+ }
+}
\ No newline at end of file
diff --git a/libs/utils/utils.js b/libs/utils/utils.js
new file mode 100644
index 0000000..1f0dfc9
--- /dev/null
+++ b/libs/utils/utils.js
@@ -0,0 +1,14 @@
+import fs from 'fs'
+import { generateSiteMap } from './siteMap.js'
+
+const ConfigFile = fs.readFileSync('./config.json')
+const Config = JSON.parse(ConfigFile)
+
+// Generate some utilities
+export let utils = {
+ generate: async () =>
+ utils.values = {
+ siteMap: await generateSiteMap(Config)
+ },
+ values: {}
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..07aa252
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1872 @@
+{
+ "name": "qwik-cms",
+ "version": "1.2.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "qwik-cms",
+ "version": "1.2.0",
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "express": "^4.17.1",
+ "highlight.js": "^11.2.0",
+ "jsdom": "^16.7.0",
+ "marked": "^2.1.3",
+ "nunjucks": "^3.2.3",
+ "nunjucks-markdown": "^2.0.1"
+ }
+ },
+ "node_modules/@tootallnate/once": {
+ "version": "1.1.2",
+ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/a-sync-waterfall": {
+ "version": "1.0.1",
+ "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA=="
+ },
+ "node_modules/abab": {
+ "version": "2.0.5",
+ "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q=="
+ },
+ "node_modules/accepts": {
+ "version": "1.3.7",
+ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "dependencies": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.4.1",
+ "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-globals": {
+ "version": "6.0.0",
+ "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==",
+ "dependencies": {
+ "acorn": "^7.1.1",
+ "acorn-walk": "^7.1.1"
+ }
+ },
+ "node_modules/acorn-globals/node_modules/acorn": {
+ "version": "7.4.1",
+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "7.2.0",
+ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "6.0.2",
+ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "dependencies": {
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/agent-base/node_modules/debug": {
+ "version": "4.3.2",
+ "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/agent-base/node_modules/ms": {
+ "version": "2.1.2",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.2",
+ "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "node_modules/asap": {
+ "version": "2.0.6",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "1.19.0",
+ "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+ "dependencies": {
+ "bytes": "3.1.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.7.0",
+ "raw-body": "2.4.0",
+ "type-is": "~1.6.17"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browser-process-hrtime": {
+ "version": "1.0.0",
+ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
+ },
+ "node_modules/bytes": {
+ "version": "3.1.0",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.2",
+ "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/commander": {
+ "version": "5.1.0",
+ "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.3",
+ "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "dependencies": {
+ "safe-buffer": "5.1.2"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.4",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.4.0",
+ "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "node_modules/cssom": {
+ "version": "0.4.4",
+ "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw=="
+ },
+ "node_modules/cssstyle": {
+ "version": "2.3.0",
+ "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
+ "dependencies": {
+ "cssom": "~0.3.6"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cssstyle/node_modules/cssom": {
+ "version": "0.3.8",
+ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
+ },
+ "node_modules/data-urls": {
+ "version": "2.0.0",
+ "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==",
+ "dependencies": {
+ "abab": "^2.0.3",
+ "whatwg-mimetype": "^2.3.0",
+ "whatwg-url": "^8.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/decimal.js": {
+ "version": "10.3.1",
+ "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ=="
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.3",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/depd": {
+ "version": "1.1.2",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.0.4",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ },
+ "node_modules/domexception": {
+ "version": "2.0.1",
+ "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==",
+ "dependencies": {
+ "webidl-conversions": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/domexception/node_modules/webidl-conversions": {
+ "version": "5.0.0",
+ "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "node_modules/escodegen": {
+ "version": "2.0.0",
+ "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==",
+ "dependencies": {
+ "esprima": "^4.0.1",
+ "estraverse": "^5.2.0",
+ "esutils": "^2.0.2",
+ "optionator": "^0.8.1"
+ },
+ "bin": {
+ "escodegen": "bin/escodegen.js",
+ "esgenerate": "bin/esgenerate.js"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "optionalDependencies": {
+ "source-map": "~0.6.1"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.2.0",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.17.1",
+ "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+ "dependencies": {
+ "accepts": "~1.3.7",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.19.0",
+ "content-disposition": "0.5.3",
+ "content-type": "~1.0.4",
+ "cookie": "0.4.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.1.2",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.5",
+ "qs": "6.7.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.1.2",
+ "send": "0.17.1",
+ "serve-static": "1.14.1",
+ "setprototypeof": "1.1.1",
+ "statuses": "~1.5.0",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.1.2",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "3.0.1",
+ "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/highlight.js": {
+ "version": "11.2.0",
+ "integrity": "sha512-JOySjtOEcyG8s4MLR2MNbLUyaXqUunmSnL2kdV/KuGJOmHZuAR5xC54Ko7goAXBWNhf09Vy3B+U7vR62UZ/0iw==",
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/html-encoding-sniffer": {
+ "version": "2.0.1",
+ "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==",
+ "dependencies": {
+ "whatwg-encoding": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "1.7.2",
+ "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+ "dependencies": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/http-proxy-agent": {
+ "version": "4.0.1",
+ "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+ "dependencies": {
+ "@tootallnate/once": "1",
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/http-proxy-agent/node_modules/debug": {
+ "version": "4.3.2",
+ "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/http-proxy-agent/node_modules/ms": {
+ "version": "2.1.2",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "5.0.0",
+ "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
+ "dependencies": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/https-proxy-agent/node_modules/debug": {
+ "version": "4.3.2",
+ "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/https-proxy-agent/node_modules/ms": {
+ "version": "2.1.2",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.3",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.1",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-potential-custom-element-name": {
+ "version": "1.0.1",
+ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
+ },
+ "node_modules/jsdom": {
+ "version": "16.7.0",
+ "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==",
+ "dependencies": {
+ "abab": "^2.0.5",
+ "acorn": "^8.2.4",
+ "acorn-globals": "^6.0.0",
+ "cssom": "^0.4.4",
+ "cssstyle": "^2.3.0",
+ "data-urls": "^2.0.0",
+ "decimal.js": "^10.2.1",
+ "domexception": "^2.0.1",
+ "escodegen": "^2.0.0",
+ "form-data": "^3.0.0",
+ "html-encoding-sniffer": "^2.0.1",
+ "http-proxy-agent": "^4.0.1",
+ "https-proxy-agent": "^5.0.0",
+ "is-potential-custom-element-name": "^1.0.1",
+ "nwsapi": "^2.2.0",
+ "parse5": "6.0.1",
+ "saxes": "^5.0.1",
+ "symbol-tree": "^3.2.4",
+ "tough-cookie": "^4.0.0",
+ "w3c-hr-time": "^1.0.2",
+ "w3c-xmlserializer": "^2.0.0",
+ "webidl-conversions": "^6.1.0",
+ "whatwg-encoding": "^1.0.5",
+ "whatwg-mimetype": "^2.3.0",
+ "whatwg-url": "^8.5.0",
+ "ws": "^7.4.6",
+ "xml-name-validator": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "canvas": "^2.5.0"
+ },
+ "peerDependenciesMeta": {
+ "canvas": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.3.0",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "dependencies": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "node_modules/marked": {
+ "version": "2.1.3",
+ "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==",
+ "bin": {
+ "marked": "bin/marked"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.1",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.48.0",
+ "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.31",
+ "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
+ "dependencies": {
+ "mime-db": "1.48.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.2",
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/nunjucks": {
+ "version": "3.2.3",
+ "integrity": "sha512-psb6xjLj47+fE76JdZwskvwG4MYsQKXUtMsPh6U0YMvmyjRtKRFcxnlXGWglNybtNTNVmGdp94K62/+NjF5FDQ==",
+ "dependencies": {
+ "a-sync-waterfall": "^1.0.0",
+ "asap": "^2.0.3",
+ "commander": "^5.1.0"
+ },
+ "bin": {
+ "nunjucks-precompile": "bin/precompile"
+ },
+ "engines": {
+ "node": ">= 6.9.0"
+ },
+ "peerDependencies": {
+ "chokidar": "^3.3.0"
+ },
+ "peerDependenciesMeta": {
+ "chokidar": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/nunjucks-markdown": {
+ "version": "2.0.1",
+ "integrity": "sha1-1V51Qzo1hQ4sNFZR/j+THtmxVqI=",
+ "peerDependencies": {
+ "nunjucks": "^2.3.0 || ^3.0.0"
+ }
+ },
+ "node_modules/nwsapi": {
+ "version": "2.2.0",
+ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ=="
+ },
+ "node_modules/on-finished": {
+ "version": "2.3.0",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.8.3",
+ "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+ "dependencies": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/parse5": {
+ "version": "6.0.1",
+ "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.7",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.0",
+ "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.1.2",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/psl": {
+ "version": "1.8.0",
+ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
+ },
+ "node_modules/punycode": {
+ "version": "2.1.1",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.7.0",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.4.0",
+ "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+ "dependencies": {
+ "bytes": "3.1.0",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/saxes": {
+ "version": "5.0.1",
+ "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==",
+ "dependencies": {
+ "xmlchars": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.17.1",
+ "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.7.2",
+ "mime": "1.6.0",
+ "ms": "2.1.1",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.1",
+ "statuses": "~1.5.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.1",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ },
+ "node_modules/serve-static": {
+ "version": "1.14.1",
+ "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+ "dependencies": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.17.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.1.1",
+ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "1.5.0",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/symbol-tree": {
+ "version": "3.2.4",
+ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.0",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/tough-cookie": {
+ "version": "4.0.0",
+ "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==",
+ "dependencies": {
+ "psl": "^1.1.33",
+ "punycode": "^2.1.1",
+ "universalify": "^0.1.2"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "2.1.0",
+ "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==",
+ "dependencies": {
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/type-check": {
+ "version": "0.3.2",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dependencies": {
+ "prelude-ls": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "0.1.2",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/w3c-hr-time": {
+ "version": "1.0.2",
+ "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==",
+ "dependencies": {
+ "browser-process-hrtime": "^1.0.0"
+ }
+ },
+ "node_modules/w3c-xmlserializer": {
+ "version": "2.0.0",
+ "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==",
+ "dependencies": {
+ "xml-name-validator": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "6.1.0",
+ "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==",
+ "engines": {
+ "node": ">=10.4"
+ }
+ },
+ "node_modules/whatwg-encoding": {
+ "version": "1.0.5",
+ "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
+ "dependencies": {
+ "iconv-lite": "0.4.24"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "2.3.0",
+ "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
+ },
+ "node_modules/whatwg-url": {
+ "version": "8.7.0",
+ "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==",
+ "dependencies": {
+ "lodash": "^4.7.0",
+ "tr46": "^2.1.0",
+ "webidl-conversions": "^6.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.3",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ws": {
+ "version": "7.5.3",
+ "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==",
+ "engines": {
+ "node": ">=8.3.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xml-name-validator": {
+ "version": "3.0.0",
+ "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
+ },
+ "node_modules/xmlchars": {
+ "version": "2.2.0",
+ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
+ }
+ },
+ "dependencies": {
+ "@tootallnate/once": {
+ "version": "1.1.2"
+ },
+ "a-sync-waterfall": {
+ "version": "1.0.1"
+ },
+ "abab": {
+ "version": "2.0.5"
+ },
+ "accepts": {
+ "version": "1.3.7",
+ "requires": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ }
+ },
+ "acorn": {
+ "version": "8.4.1"
+ },
+ "acorn-globals": {
+ "version": "6.0.0",
+ "requires": {
+ "acorn": "^7.1.1",
+ "acorn-walk": "^7.1.1"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "7.4.1"
+ }
+ }
+ },
+ "acorn-walk": {
+ "version": "7.2.0"
+ },
+ "agent-base": {
+ "version": "6.0.2",
+ "requires": {
+ "debug": "4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.2",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2"
+ }
+ }
+ },
+ "anymatch": {
+ "version": "3.1.2",
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1"
+ },
+ "asap": {
+ "version": "2.0.6"
+ },
+ "asynckit": {
+ "version": "0.4.0"
+ },
+ "binary-extensions": {
+ "version": "2.2.0"
+ },
+ "body-parser": {
+ "version": "1.19.0",
+ "requires": {
+ "bytes": "3.1.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.7.0",
+ "raw-body": "2.4.0",
+ "type-is": "~1.6.17"
+ }
+ },
+ "braces": {
+ "version": "3.0.2",
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "browser-process-hrtime": {
+ "version": "1.0.0"
+ },
+ "bytes": {
+ "version": "3.1.0"
+ },
+ "chokidar": {
+ "version": "3.5.2",
+ "requires": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "fsevents": "~2.3.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ }
+ },
+ "combined-stream": {
+ "version": "1.0.8",
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "commander": {
+ "version": "5.1.0"
+ },
+ "content-disposition": {
+ "version": "0.5.3",
+ "requires": {
+ "safe-buffer": "5.1.2"
+ }
+ },
+ "content-type": {
+ "version": "1.0.4"
+ },
+ "cookie": {
+ "version": "0.4.0"
+ },
+ "cookie-signature": {
+ "version": "1.0.6"
+ },
+ "cssom": {
+ "version": "0.4.4"
+ },
+ "cssstyle": {
+ "version": "2.3.0",
+ "requires": {
+ "cssom": "~0.3.6"
+ },
+ "dependencies": {
+ "cssom": {
+ "version": "0.3.8"
+ }
+ }
+ },
+ "data-urls": {
+ "version": "2.0.0",
+ "requires": {
+ "abab": "^2.0.3",
+ "whatwg-mimetype": "^2.3.0",
+ "whatwg-url": "^8.0.0"
+ }
+ },
+ "debug": {
+ "version": "2.6.9",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "decimal.js": {
+ "version": "10.3.1"
+ },
+ "deep-is": {
+ "version": "0.1.3"
+ },
+ "delayed-stream": {
+ "version": "1.0.0"
+ },
+ "depd": {
+ "version": "1.1.2"
+ },
+ "destroy": {
+ "version": "1.0.4"
+ },
+ "domexception": {
+ "version": "2.0.1",
+ "requires": {
+ "webidl-conversions": "^5.0.0"
+ },
+ "dependencies": {
+ "webidl-conversions": {
+ "version": "5.0.0"
+ }
+ }
+ },
+ "ee-first": {
+ "version": "1.1.1"
+ },
+ "encodeurl": {
+ "version": "1.0.2"
+ },
+ "escape-html": {
+ "version": "1.0.3"
+ },
+ "escodegen": {
+ "version": "2.0.0",
+ "requires": {
+ "esprima": "^4.0.1",
+ "estraverse": "^5.2.0",
+ "esutils": "^2.0.2",
+ "optionator": "^0.8.1",
+ "source-map": "~0.6.1"
+ }
+ },
+ "esprima": {
+ "version": "4.0.1"
+ },
+ "estraverse": {
+ "version": "5.2.0"
+ },
+ "esutils": {
+ "version": "2.0.3"
+ },
+ "etag": {
+ "version": "1.8.1"
+ },
+ "express": {
+ "version": "4.17.1",
+ "requires": {
+ "accepts": "~1.3.7",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.19.0",
+ "content-disposition": "0.5.3",
+ "content-type": "~1.0.4",
+ "cookie": "0.4.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.1.2",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.5",
+ "qs": "6.7.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.1.2",
+ "send": "0.17.1",
+ "serve-static": "1.14.1",
+ "setprototypeof": "1.1.1",
+ "statuses": "~1.5.0",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ }
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6"
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "finalhandler": {
+ "version": "1.1.2",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ }
+ },
+ "form-data": {
+ "version": "3.0.1",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "forwarded": {
+ "version": "0.2.0"
+ },
+ "fresh": {
+ "version": "0.5.2"
+ },
+ "glob-parent": {
+ "version": "5.1.2",
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "highlight.js": {
+ "version": "11.2.0"
+ },
+ "html-encoding-sniffer": {
+ "version": "2.0.1",
+ "requires": {
+ "whatwg-encoding": "^1.0.5"
+ }
+ },
+ "http-errors": {
+ "version": "1.7.2",
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ }
+ },
+ "http-proxy-agent": {
+ "version": "4.0.1",
+ "requires": {
+ "@tootallnate/once": "1",
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.2",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2"
+ }
+ }
+ },
+ "https-proxy-agent": {
+ "version": "5.0.0",
+ "requires": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.2",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2"
+ }
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3"
+ },
+ "ipaddr.js": {
+ "version": "1.9.1"
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1"
+ },
+ "is-glob": {
+ "version": "4.0.1",
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0"
+ },
+ "is-potential-custom-element-name": {
+ "version": "1.0.1"
+ },
+ "jsdom": {
+ "version": "16.7.0",
+ "requires": {
+ "abab": "^2.0.5",
+ "acorn": "^8.2.4",
+ "acorn-globals": "^6.0.0",
+ "cssom": "^0.4.4",
+ "cssstyle": "^2.3.0",
+ "data-urls": "^2.0.0",
+ "decimal.js": "^10.2.1",
+ "domexception": "^2.0.1",
+ "escodegen": "^2.0.0",
+ "form-data": "^3.0.0",
+ "html-encoding-sniffer": "^2.0.1",
+ "http-proxy-agent": "^4.0.1",
+ "https-proxy-agent": "^5.0.0",
+ "is-potential-custom-element-name": "^1.0.1",
+ "nwsapi": "^2.2.0",
+ "parse5": "6.0.1",
+ "saxes": "^5.0.1",
+ "symbol-tree": "^3.2.4",
+ "tough-cookie": "^4.0.0",
+ "w3c-hr-time": "^1.0.2",
+ "w3c-xmlserializer": "^2.0.0",
+ "webidl-conversions": "^6.1.0",
+ "whatwg-encoding": "^1.0.5",
+ "whatwg-mimetype": "^2.3.0",
+ "whatwg-url": "^8.5.0",
+ "ws": "^7.4.6",
+ "xml-name-validator": "^3.0.0"
+ }
+ },
+ "levn": {
+ "version": "0.3.0",
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "lodash": {
+ "version": "4.17.21"
+ },
+ "marked": {
+ "version": "2.1.3"
+ },
+ "media-typer": {
+ "version": "0.3.0"
+ },
+ "merge-descriptors": {
+ "version": "1.0.1"
+ },
+ "methods": {
+ "version": "1.1.2"
+ },
+ "mime": {
+ "version": "1.6.0"
+ },
+ "mime-db": {
+ "version": "1.48.0"
+ },
+ "mime-types": {
+ "version": "2.1.31",
+ "requires": {
+ "mime-db": "1.48.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0"
+ },
+ "negotiator": {
+ "version": "0.6.2"
+ },
+ "normalize-path": {
+ "version": "3.0.0"
+ },
+ "nunjucks": {
+ "version": "3.2.3",
+ "requires": {
+ "a-sync-waterfall": "^1.0.0",
+ "asap": "^2.0.3",
+ "commander": "^5.1.0"
+ }
+ },
+ "nunjucks-markdown": {
+ "version": "2.0.1",
+ "requires": {}
+ },
+ "nwsapi": {
+ "version": "2.2.0"
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "optionator": {
+ "version": "0.8.3",
+ "requires": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.6",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "word-wrap": "~1.2.3"
+ }
+ },
+ "parse5": {
+ "version": "6.0.1"
+ },
+ "parseurl": {
+ "version": "1.3.3"
+ },
+ "path-to-regexp": {
+ "version": "0.1.7"
+ },
+ "picomatch": {
+ "version": "2.3.0"
+ },
+ "prelude-ls": {
+ "version": "1.1.2"
+ },
+ "proxy-addr": {
+ "version": "2.0.7",
+ "requires": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ }
+ },
+ "psl": {
+ "version": "1.8.0"
+ },
+ "punycode": {
+ "version": "2.1.1"
+ },
+ "qs": {
+ "version": "6.7.0"
+ },
+ "range-parser": {
+ "version": "1.2.1"
+ },
+ "raw-body": {
+ "version": "2.4.0",
+ "requires": {
+ "bytes": "3.1.0",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ }
+ },
+ "readdirp": {
+ "version": "3.6.0",
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2"
+ },
+ "safer-buffer": {
+ "version": "2.1.2"
+ },
+ "saxes": {
+ "version": "5.0.1",
+ "requires": {
+ "xmlchars": "^2.2.0"
+ }
+ },
+ "send": {
+ "version": "0.17.1",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.7.2",
+ "mime": "1.6.0",
+ "ms": "2.1.1",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.1",
+ "statuses": "~1.5.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.1"
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.14.1",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.17.1"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.1.1"
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "optional": true
+ },
+ "statuses": {
+ "version": "1.5.0"
+ },
+ "symbol-tree": {
+ "version": "3.2.4"
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "toidentifier": {
+ "version": "1.0.0"
+ },
+ "tough-cookie": {
+ "version": "4.0.0",
+ "requires": {
+ "psl": "^1.1.33",
+ "punycode": "^2.1.1",
+ "universalify": "^0.1.2"
+ }
+ },
+ "tr46": {
+ "version": "2.1.0",
+ "requires": {
+ "punycode": "^2.1.1"
+ }
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "type-is": {
+ "version": "1.6.18",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
+ },
+ "universalify": {
+ "version": "0.1.2"
+ },
+ "unpipe": {
+ "version": "1.0.0"
+ },
+ "utils-merge": {
+ "version": "1.0.1"
+ },
+ "vary": {
+ "version": "1.1.2"
+ },
+ "w3c-hr-time": {
+ "version": "1.0.2",
+ "requires": {
+ "browser-process-hrtime": "^1.0.0"
+ }
+ },
+ "w3c-xmlserializer": {
+ "version": "2.0.0",
+ "requires": {
+ "xml-name-validator": "^3.0.0"
+ }
+ },
+ "webidl-conversions": {
+ "version": "6.1.0"
+ },
+ "whatwg-encoding": {
+ "version": "1.0.5",
+ "requires": {
+ "iconv-lite": "0.4.24"
+ }
+ },
+ "whatwg-mimetype": {
+ "version": "2.3.0"
+ },
+ "whatwg-url": {
+ "version": "8.7.0",
+ "requires": {
+ "lodash": "^4.7.0",
+ "tr46": "^2.1.0",
+ "webidl-conversions": "^6.1.0"
+ }
+ },
+ "word-wrap": {
+ "version": "1.2.3"
+ },
+ "ws": {
+ "version": "7.5.3",
+ "requires": {}
+ },
+ "xml-name-validator": {
+ "version": "3.0.0"
+ },
+ "xmlchars": {
+ "version": "2.2.0"
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..59cb01a
--- /dev/null
+++ b/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "qwik-cms",
+ "version": "1.2.0",
+ "description": "A dead simple CMS. No bullshit.",
+ "main": "index.js",
+ "type": "module",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://git.qwik.space/BurnyLlama/qwik-cms"
+ },
+ "keywords": [
+ "cms"
+ ],
+ "author": "BurnyLlama",
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "express": "^4.17.1",
+ "highlight.js": "^11.2.0",
+ "jsdom": "^16.7.0",
+ "marked": "^2.1.3",
+ "nunjucks": "^3.2.3",
+ "nunjucks-markdown": "^2.0.1"
+ }
+}