refactor(code): better code syntax highlighting
+ 795
- 7
@@ -1,5 +1,5 @@
 {
-  "_generatedAtUnix": 1663691805572,
+  "_generatedAtUnix": 1663697509607,
   "_hashAlgorithm": "sha1",
   "_version": 2,
   "islands": {

...
@@ -50,7 +50,7 @@
       "pathSource": "./app/views/auth/RegisterView.tsx"
     },
     "RepositoryBrowserView": {
-      "hash": "e6493e8fedabe1f0835eee239ce726dad7f19af6",
+      "hash": "e967bf293d4df2b6f04816b5104a6395a454b655",
       "pathSource": "./app/views/repository/RepositoryBrowserView.tsx"
     },
     "RepositoryCreateView": {

new file
app/components/Code.tsx
@@ -0,0 +1,75 @@
+// 3rd-party
+import React, { VFC, useMemo } from "react";
+import Prism from "prismjs";
+import loadLanguages from "prismjs/components/";
+import styled, { css } from "styled-components";
+// app
+import type { AppThemeScheme, WithThemeSchemeProp } from "../types";
+import { NamedColors } from "../utils/style";
+
+interface CodeProps {
+  code: string;
+  language: string;
+  [x: string]: unknown;
+}
+
+if (typeof window === "undefined") {
+  loadLanguages();
+}
+
+export const Code: VFC<CodeProps & WithThemeSchemeProp> = ({
+  code,
+  language,
+  themeScheme,
+  ...props
+}) => {
+  const innerHtml = useMemo(
+    () => ({
+      __html: Prism.highlight(code, Prism.languages[language], language),
+    }),
+    [code, language]
+  );
+
+  // the extra space before language is important so SSR matches CSR
+  return (
+    <StylePreTag
+      data-language={language}
+      className={` language-${language} line-numbers`}
+      themeScheme={themeScheme}
+    >
+      <StyledCodeTag {...props} dangerouslySetInnerHTML={innerHtml} />
+    </StylePreTag>
+  );
+};
+
+export const getThemedCodeCss = (themeScheme: AppThemeScheme): JSX.Element =>
+  themeScheme === "light" ? (
+    <style>{`code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}`}</style>
+  ) : (
+    <style>{`code[class*=language-],pre[class*=language-]{color:#fff;background:0 0;text-shadow:0 -.1em .2em #000;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}:not(pre)>code[class*=language-],pre[class*=language-]{background:#4c3f33}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border:.3em solid #7a6651;border-radius:.5em;box-shadow:1px 1px .5em #000 inset}:not(pre)>code[class*=language-]{padding:.15em .2em .05em;border-radius:.3em;border:.13em solid #7a6651;box-shadow:1px 1px .3em -.1em #000 inset;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#997f66}.token.punctuation{opacity:.7}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.number,.token.property,.token.symbol,.token.tag{color:#d1939e}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#bce051}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f4b73d}.token.atrule,.token.attr-value,.token.keyword{color:#d1939e}.token.important,.token.regex{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.deleted{color:red}`}</style>
+  );
+
+const StylePreTag = styled.pre<WithThemeSchemeProp>`
+  width: 100%;
+
+  border-radius: 8px !important;
+  box-shadow: none !important;
+  text-shadow: none !important;
+
+  ${({ themeScheme }) => css`
+    background-color: ${NamedColors.CARD[themeScheme]} !important;
+    border: 1px solid ${NamedColors.BORDER_DEFAULT[themeScheme]} !important;
+  `};
+`;
+
+const StyledCodeTag = styled.code`
+  display: block;
+
+  min-height: 20px;
+  width: 100%;
+  padding: 2px 4px;
+
+  font-size: 16px;
+  white-space: break-spaces;
+  border: none;
+`;

app/components/index.ts
@@ -1,5 +1,6 @@
 export { Button, ButtonAnchor } from "./Button.styled";
 export { Card } from "./Card.styled";
+export { Code, getThemedCodeCss } from "./Code";
 export { Grid } from "./Grid";
 export * as Icons from "./icons";
 export { Layout } from "./Layout";

@@ -80,6 +80,7 @@ async function main(): Promise<AppServer> {
     externalDependencies: {
       "cross-fetch": "CrossFetch",
       "markdown-to-jsx": "MarkdownToJSX",
+      prismjs: "Prism",
     },
     baseHeadTags: [
       {

app/views/repository/RepositoryBrowserView.tsx
@@ -6,7 +6,7 @@ import React from "react";
 import type { Organization, Repository, User } from "@prisma/client";
 // app
 import type { CommonProps, RepositoryFileContent } from "../../types";
-import { Layout, PageWrapper } from "../../components";
+import { Code, Layout, PageWrapper, getThemedCodeCss } from "../../components";
 
 export interface RepositoryBrowserViewProps extends CommonProps {
   currentUser: null | User;

...
@@ -37,10 +37,13 @@ const RepositoryBrowserView: ReactView<RepositoryBrowserViewProps> = ({
           {" / "}
           {path}
         </h1>
-        <div>
-          <code>
-            <pre>{fileContent.content}</pre>
-          </code>
+        <div style={{ width: "100%" }}>
+          {getThemedCodeCss(commonProps.themeScheme)}
+          <Code
+            code={fileContent.content}
+            language={"ts"}
+            themeScheme={commonProps.themeScheme}
+          />
         </div>
       </PageWrapper>
     </Layout>

new file
public/.deps/prismjs.development.js
@@ -0,0 +1,696 @@
+/* https://jasonrivers.github.io/prism/download.html?themes=prism&languages=markup+css+clike+javascript+bash+c+python+sql+http&plugins=line-numbers */
+self =
+  typeof window !== "undefined"
+    ? window // if in browser
+    : typeof WorkerGlobalScope !== "undefined" &&
+      self instanceof WorkerGlobalScope
+    ? self // if in worker
+    : {}; // if in node js
+
+/**
+ * Prism: Lightweight, robust, elegant syntax highlighting
+ * MIT license http://www.opensource.org/licenses/mit-license.php/
+ * @author Lea Verou http://lea.verou.me
+ */
+
+var Prism = (function () {
+  // Private helper vars
+  var lang = /\blang(?:uage)?-(?!\*)(\w+)\b/i;
+
+  var _ = (self.Prism = {
+    util: {
+      encode: function (tokens) {
+        if (tokens instanceof Token) {
+          return new Token(tokens.type, _.util.encode(tokens.content));
+        } else if (_.util.type(tokens) === "Array") {
+          return tokens.map(_.util.encode);
+        } else {
+          return tokens
+            .replace(/&/g, "&amp;")
+            .replace(/</g, "&lt;")
+            .replace(/\u00a0/g, " ");
+        }
+      },
+
+      type: function (o) {
+        return Object.prototype.toString.call(o).match(/\[object (\w+)\]/)[1];
+      },
+
+      // Deep clone a language definition (e.g. to extend it)
+      clone: function (o) {
+        var type = _.util.type(o);
+
+        switch (type) {
+          case "Object":
+            var clone = {};
+
+            for (var key in o) {
+              if (o.hasOwnProperty(key)) {
+                clone[key] = _.util.clone(o[key]);
+              }
+            }
+
+            return clone;
+
+          case "Array":
+            return o.slice();
+        }
+
+        return o;
+      },
+    },
+
+    languages: {
+      extend: function (id, redef) {
+        var lang = _.util.clone(_.languages[id]);
+
+        for (var key in redef) {
+          lang[key] = redef[key];
+        }
+
+        return lang;
+      },
+
+      // Insert a token before another token in a language literal
+      insertBefore: function (inside, before, insert, root) {
+        root = root || _.languages;
+        var grammar = root[inside];
+        var ret = {};
+
+        for (var token in grammar) {
+          if (grammar.hasOwnProperty(token)) {
+            if (token == before) {
+              for (var newToken in insert) {
+                if (insert.hasOwnProperty(newToken)) {
+                  ret[newToken] = insert[newToken];
+                }
+              }
+            }
+
+            ret[token] = grammar[token];
+          }
+        }
+
+        return (root[inside] = ret);
+      },
+
+      // Traverse a language definition with Depth First Search
+      DFS: function (o, callback) {
+        for (var i in o) {
+          callback.call(o, i, o[i]);
+
+          if (_.util.type(o) === "Object") {
+            _.languages.DFS(o[i], callback);
+          }
+        }
+      },
+    },
+
+    highlightAll: function (async, callback) {
+      var elements = document.querySelectorAll(
+        'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
+      );
+
+      for (var i = 0, element; (element = elements[i++]); ) {
+        _.highlightElement(element, async === true, callback);
+      }
+    },
+
+    highlightElement: function (element, async, callback) {
+      // Find language
+      var language,
+        grammar,
+        parent = element;
+
+      while (parent && !lang.test(parent.className)) {
+        parent = parent.parentNode;
+      }
+
+      if (parent) {
+        language = (parent.className.match(lang) || [, ""])[1];
+        grammar = _.languages[language];
+      }
+
+      if (!grammar) {
+        return;
+      }
+
+      // Set language on the element, if not present
+      element.className =
+        element.className.replace(lang, "").replace(/\s+/g, " ") +
+        " language-" +
+        language;
+
+      // Set language on the parent, for styling
+      parent = element.parentNode;
+
+      if (/pre/i.test(parent.nodeName)) {
+        parent.className =
+          parent.className.replace(lang, "").replace(/\s+/g, " ") +
+          " language-" +
+          language;
+      }
+
+      var code = element.textContent;
+
+      if (!code) {
+        return;
+      }
+
+      var env = {
+        element: element,
+        language: language,
+        grammar: grammar,
+        code: code,
+      };
+
+      _.hooks.run("before-highlight", env);
+
+      if (async && self.Worker) {
+        var worker = new Worker(_.filename);
+
+        worker.onmessage = function (evt) {
+          env.highlightedCode = Token.stringify(JSON.parse(evt.data), language);
+
+          _.hooks.run("before-insert", env);
+
+          env.element.innerHTML = env.highlightedCode;
+
+          callback && callback.call(env.element);
+          _.hooks.run("after-highlight", env);
+        };
+
+        worker.postMessage(
+          JSON.stringify({
+            language: env.language,
+            code: env.code,
+          })
+        );
+      } else {
+        env.highlightedCode = _.highlight(env.code, env.grammar, env.language);
+
+        _.hooks.run("before-insert", env);
+
+        env.element.innerHTML = env.highlightedCode;
+
+        callback && callback.call(element);
+
+        _.hooks.run("after-highlight", env);
+      }
+    },
+
+    highlight: function (text, grammar, language) {
+      var tokens = _.tokenize(text, grammar);
+      return Token.stringify(_.util.encode(tokens), language);
+    },
+
+    tokenize: function (text, grammar, language) {
+      var Token = _.Token;
+
+      var strarr = [text];
+
+      var rest = grammar.rest;
+
+      if (rest) {
+        for (var token in rest) {
+          grammar[token] = rest[token];
+        }
+
+        delete grammar.rest;
+      }
+
+      tokenloop: for (var token in grammar) {
+        if (!grammar.hasOwnProperty(token) || !grammar[token]) {
+          continue;
+        }
+
+        var pattern = grammar[token],
+          inside = pattern.inside,
+          lookbehind = !!pattern.lookbehind,
+          lookbehindLength = 0;
+
+        pattern = pattern.pattern || pattern;
+
+        for (var i = 0; i < strarr.length; i++) {
+          // Don’t cache length as it changes during the loop
+
+          var str = strarr[i];
+
+          if (strarr.length > text.length) {
+            // Something went terribly wrong, ABORT, ABORT!
+            break tokenloop;
+          }
+
+          if (str instanceof Token) {
+            continue;
+          }
+
+          pattern.lastIndex = 0;
+
+          var match = pattern.exec(str);
+
+          if (match) {
+            if (lookbehind) {
+              lookbehindLength = match[1].length;
+            }
+
+            var from = match.index - 1 + lookbehindLength,
+              match = match[0].slice(lookbehindLength),
+              len = match.length,
+              to = from + len,
+              before = str.slice(0, from + 1),
+              after = str.slice(to + 1);
+
+            var args = [i, 1];
+
+            if (before) {
+              args.push(before);
+            }
+
+            var wrapped = new Token(
+              token,
+              inside ? _.tokenize(match, inside) : match
+            );
+
+            args.push(wrapped);
+
+            if (after) {
+              args.push(after);
+            }
+
+            Array.prototype.splice.apply(strarr, args);
+          }
+        }
+      }
+
+      return strarr;
+    },
+
+    hooks: {
+      all: {},
+
+      add: function (name, callback) {
+        var hooks = _.hooks.all;
+
+        hooks[name] = hooks[name] || [];
+
+        hooks[name].push(callback);
+      },
+
+      run: function (name, env) {
+        var callbacks = _.hooks.all[name];
+
+        if (!callbacks || !callbacks.length) {
+          return;
+        }
+
+        for (var i = 0, callback; (callback = callbacks[i++]); ) {
+          callback(env);
+        }
+      },
+    },
+  });
+
+  var Token = (_.Token = function (type, content) {
+    this.type = type;
+    this.content = content;
+  });
+
+  Token.stringify = function (o, language, parent) {
+    if (typeof o == "string") {
+      return o;
+    }
+
+    if (Object.prototype.toString.call(o) == "[object Array]") {
+      return o
+        .map(function (element) {
+          return Token.stringify(element, language, o);
+        })
+        .join("");
+    }
+
+    var env = {
+      type: o.type,
+      content: Token.stringify(o.content, language, parent),
+      tag: "span",
+      classes: ["token", o.type],
+      attributes: {},
+      language: language,
+      parent: parent,
+    };
+
+    if (env.type == "comment") {
+      env.attributes["spellcheck"] = "true";
+    }
+
+    _.hooks.run("wrap", env);
+
+    var attributes = "";
+
+    for (var name in env.attributes) {
+      attributes += name + '="' + (env.attributes[name] || "") + '"';
+    }
+
+    return (
+      "<" +
+      env.tag +
+      ' class="' +
+      env.classes.join(" ") +
+      '" ' +
+      attributes +
+      ">" +
+      env.content +
+      "</" +
+      env.tag +
+      ">"
+    );
+  };
+
+  if (!self.document) {
+    if (!self.addEventListener) {
+      // in Node.js
+      return self.Prism;
+    }
+    // In worker
+    self.addEventListener(
+      "message",
+      function (evt) {
+        var message = JSON.parse(evt.data),
+          lang = message.language,
+          code = message.code;
+
+        self.postMessage(JSON.stringify(_.tokenize(code, _.languages[lang])));
+        self.close();
+      },
+      false
+    );
+
+    return self.Prism;
+  }
+
+  // Get current script and highlight
+  var script = document.getElementsByTagName("script");
+
+  script = script[script.length - 1];
+
+  if (script) {
+    _.filename = script.src;
+
+    if (document.addEventListener && !script.hasAttribute("data-manual")) {
+      document.addEventListener("DOMContentLoaded", _.highlightAll);
+    }
+  }
+
+  return self.Prism;
+})();
+
+if (typeof module !== "undefined" && module.exports) {
+  module.exports = Prism;
+}
+Prism.languages.markup = {
+  comment: /<!--[\w\W]*?-->/g,
+  prolog: /<\?.+?\?>/,
+  doctype: /<!DOCTYPE.+?>/,
+  cdata: /<!\[CDATA\[[\w\W]*?]]>/i,
+  tag: {
+    pattern:
+      /<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/gi,
+    inside: {
+      tag: {
+        pattern: /^<\/?[\w:-]+/i,
+        inside: {
+          punctuation: /^<\/?/,
+          namespace: /^[\w-]+?:/,
+        },
+      },
+      "attr-value": {
+        pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,
+        inside: {
+          punctuation: /=|>|"/g,
+        },
+      },
+      punctuation: /\/?>/g,
+      "attr-name": {
+        pattern: /[\w:-]+/g,
+        inside: {
+          namespace: /^[\w-]+?:/,
+        },
+      },
+    },
+  },
+  entity: /\&#?[\da-z]{1,8};/gi,
+};
+
+// Plugin to make entity title show the real entity, idea by Roman Komarov
+Prism.hooks.add("wrap", function (env) {
+  if (env.type === "entity") {
+    env.attributes["title"] = env.content.replace(/&amp;/, "&");
+  }
+});
+Prism.languages.css = {
+  comment: /\/\*[\w\W]*?\*\//g,
+  atrule: {
+    pattern: /@[\w-]+?.*?(;|(?=\s*{))/gi,
+    inside: {
+      punctuation: /[;:]/g,
+    },
+  },
+  url: /url\((["']?).*?\1\)/gi,
+  selector: /[^\{\}\s][^\{\};]*(?=\s*\{)/g,
+  property: /(\b|\B)[\w-]+(?=\s*:)/gi,
+  string: /("|')(\\?.)*?\1/g,
+  important: /\B!important\b/gi,
+  punctuation: /[\{\};:]/g,
+  function: /[-a-z0-9]+(?=\()/gi,
+};
+
+if (Prism.languages.markup) {
+  Prism.languages.insertBefore("markup", "tag", {
+    style: {
+      pattern: /<style[\w\W]*?>[\w\W]*?<\/style>/gi,
+      inside: {
+        tag: {
+          pattern: /<style[\w\W]*?>|<\/style>/gi,
+          inside: Prism.languages.markup.tag.inside,
+        },
+        rest: Prism.languages.css,
+      },
+    },
+  });
+}
+Prism.languages.clike = {
+  comment: {
+    pattern: /(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,
+    lookbehind: true,
+  },
+  string: /("|')(\\?.)*?\1/g,
+  "class-name": {
+    pattern:
+      /((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/gi,
+    lookbehind: true,
+    inside: {
+      punctuation: /(\.|\\)/,
+    },
+  },
+  keyword:
+    /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g,
+  boolean: /\b(true|false)\b/g,
+  function: {
+    pattern: /[a-z0-9_]+\(/gi,
+    inside: {
+      punctuation: /\(/,
+    },
+  },
+  number: /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,
+  operator: /[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,
+  ignore: /&(lt|gt|amp);/gi,
+  punctuation: /[{}[\];(),.:]/g,
+};
+Prism.languages.javascript = Prism.languages.extend("clike", {
+  keyword:
+    /\b(break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|get|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/g,
+  number: /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g,
+});
+
+Prism.languages.insertBefore("javascript", "keyword", {
+  regex: {
+    pattern:
+      /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,
+    lookbehind: true,
+  },
+});
+
+if (Prism.languages.markup) {
+  Prism.languages.insertBefore("markup", "tag", {
+    script: {
+      pattern: /<script[\w\W]*?>[\w\W]*?<\/script>/gi,
+      inside: {
+        tag: {
+          pattern: /<script[\w\W]*?>|<\/script>/gi,
+          inside: Prism.languages.markup.tag.inside,
+        },
+        rest: Prism.languages.javascript,
+      },
+    },
+  });
+}
+Prism.languages.bash = Prism.languages.extend("clike", {
+  comment: {
+    pattern: /(^|[^"{\\])(#.*?(\r?\n|$))/g,
+    lookbehind: true,
+  },
+  string: {
+    //allow multiline string
+    pattern: /("|')(\\?[\s\S])*?\1/g,
+    inside: {
+      //'property' class reused for bash variables
+      property: /\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^\}]+\})/g,
+    },
+  },
+  keyword:
+    /\b(if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)\b/g,
+});
+
+Prism.languages.insertBefore("bash", "keyword", {
+  //'property' class reused for bash variables
+  property: /\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^}]+\})/g,
+});
+Prism.languages.insertBefore("bash", "comment", {
+  //shebang must be before comment, 'important' class from css reused
+  important: /(^#!\s*\/bin\/bash)|(^#!\s*\/bin\/sh)/g,
+});
+Prism.languages.c = Prism.languages.extend("clike", {
+  // allow for c multiline strings
+  string: /("|')([^\n\\\1]|\\.|\\\r*\n)*?\1/g,
+  keyword:
+    /\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/g,
+  operator:
+    /[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\//g,
+});
+
+Prism.languages.insertBefore("c", "string", {
+  // property class reused for macro statements
+  property: {
+    // allow for multiline macro definitions
+    // spaces after the # character compile fine with gcc
+    pattern: /((^|\n)\s*)#\s*[a-z]+([^\n\\]|\\.|\\\r*\n)*/gi,
+    lookbehind: true,
+    inside: {
+      // highlight the path of the include statement as a string
+      string: {
+        pattern: /(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/g,
+        lookbehind: true,
+      },
+    },
+  },
+});
+
+delete Prism.languages.c["class-name"];
+delete Prism.languages.c["boolean"];
+Prism.languages.python = {
+  comment: {
+    pattern: /(^|[^\\])#.*?(\r?\n|$)/g,
+    lookbehind: true,
+  },
+  string: /"""[\s\S]+?"""|("|')(\\?.)*?\1/g,
+  keyword:
+    /\b(as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/g,
+  boolean: /\b(True|False)\b/g,
+  number: /\b-?(0x)?\d*\.?[\da-f]+\b/g,
+  operator:
+    /[-+]{1,2}|=?&lt;|=?&gt;|!|={1,2}|(&){1,2}|(&amp;){1,2}|\|?\||\?|\*|\/|~|\^|%|\b(or|and|not)\b/g,
+  ignore: /&(lt|gt|amp);/gi,
+  punctuation: /[{}[\];(),.:]/g,
+};
+
+Prism.languages.sql = {
+  comment: {
+    pattern: /(^|[^\\])(\/\*[\w\W]*?\*\/|((--)|(\/\/)|#).*?(\r?\n|$))/g,
+    lookbehind: true,
+  },
+  string: /("|')(\\?[\s\S])*?\1/g,
+  keyword:
+    /\b(ACTION|ADD|AFTER|ALGORITHM|ALTER|ANALYZE|APPLY|AS|ASC|AUTHORIZATION|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADE|CASCADED|CASE|CHAIN|CHAR VARYING|CHARACTER VARYING|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLUMN|COLUMNS|COMMENT|COMMIT|COMMITTED|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATA|DATABASE|DATABASES|DATETIME|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DOUBLE PRECISION|DROP|DUMMY|DUMP|DUMPFILE|DUPLICATE KEY|ELSE|ENABLE|ENCLOSED BY|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPE|ESCAPED BY|EXCEPT|EXEC|EXECUTE|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR|FOR EACH ROW|FORCE|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GEOMETRY|GEOMETRYCOLLECTION|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|IDENTITY|IDENTITY_INSERT|IDENTITYCOL|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTO|INVOKER|ISOLATION LEVEL|JOIN|KEY|KEYS|KILL|LANGUAGE SQL|LAST|LEFT|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONGBLOB|LONGTEXT|MATCH|MATCHED|MEDIUMBLOB|MEDIUMINT|MEDIUMTEXT|MERGE|MIDDLEINT|MODIFIES SQL DATA|MODIFY|MULTILINESTRING|MULTIPOINT|MULTIPOLYGON|NATIONAL|NATIONAL CHAR VARYING|NATIONAL CHARACTER|NATIONAL CHARACTER VARYING|NATIONAL VARCHAR|NATURAL|NCHAR|NCHAR VARCHAR|NEXT|NO|NO SQL|NOCHECK|NOCYCLE|NONCLUSTERED|NULLIF|NUMERIC|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPTIMIZE|OPTION|OPTIONALLY|ORDER|OUT|OUTER|OUTFILE|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREV|PRIMARY|PRINT|PRIVILEGES|PROC|PROCEDURE|PUBLIC|PURGE|QUICK|RAISERROR|READ|READS SQL DATA|READTEXT|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEATABLE|REPLICATION|REQUIRE|RESTORE|RESTRICT|RETURN|RETURNS|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROWCOUNT|ROWGUIDCOL|ROWS?|RTREE|RULE|SAVE|SAVEPOINT|SCHEMA|SELECT|SERIAL|SERIALIZABLE|SESSION|SESSION_USER|SET|SETUSER|SHARE MODE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|START|STARTING BY|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLE|TABLES|TABLESPACE|TEMPORARY|TEMPTABLE|TERMINATED BY|TEXT|TEXTSIZE|THEN|TIMESTAMP|TINYBLOB|TINYINT|TINYTEXT|TO|TOP|TRAN|TRANSACTION|TRANSACTIONS|TRIGGER|TRUNCATE|TSEQUAL|TYPE|TYPES|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNPIVOT|UPDATE|UPDATETEXT|USAGE|USE|USER|USING|VALUE|VALUES|VARBINARY|VARCHAR|VARCHARACTER|VARYING|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH|WITH ROLLUP|WITHIN|WORK|WRITE|WRITETEXT)\b/gi,
+  boolean: /\b(TRUE|FALSE|NULL)\b/gi,
+  number: /\b-?(0x)?\d*\.?[\da-f]+\b/g,
+  operator:
+    /\b(ALL|AND|ANY|BETWEEN|EXISTS|IN|LIKE|NOT|OR|IS|UNIQUE|CHARACTER SET|COLLATE|DIV|OFFSET|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b|[-+]{1}|!|=?&lt;|=?&gt;|={1}|(&amp;){1,2}|\|?\||\?|\*|\//gi,
+  ignore: /&(lt|gt|amp);/gi,
+  punctuation: /[;[\]()`,.]/g,
+};
+Prism.languages.http = {
+  "request-line": {
+    pattern:
+      /^(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b\shttps?:\/\/\S+\sHTTP\/[0-9.]+/g,
+    inside: {
+      // HTTP Verb
+      property: /^\b(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b/g,
+      // Path or query argument
+      "attr-name": /:\w+/g,
+    },
+  },
+  "response-status": {
+    pattern: /^HTTP\/1.[01] [0-9]+.*/g,
+    inside: {
+      // Status, e.g. 200 OK
+      property: /[0-9]+[A-Z\s-]+$/g,
+    },
+  },
+  // HTTP header name
+  keyword: /^[\w-]+:(?=.+)/gm,
+};
+
+// Create a mapping of Content-Type headers to language definitions
+var httpLanguages = {
+  "application/json": Prism.languages.javascript,
+  "application/xml": Prism.languages.markup,
+  "text/xml": Prism.languages.markup,
+  "text/html": Prism.languages.markup,
+};
+
+// Insert each content type parser that has its associated language
+// currently loaded.
+for (var contentType in httpLanguages) {
+  if (httpLanguages[contentType]) {
+    var options = {};
+    options[contentType] = {
+      pattern: new RegExp(
+        "(content-type:\\s*" + contentType + "[\\w\\W]*?)\\n\\n[\\w\\W]*",
+        "gi"
+      ),
+      lookbehind: true,
+      inside: {
+        rest: httpLanguages[contentType],
+      },
+    };
+    Prism.languages.insertBefore("http", "keyword", options);
+  }
+}
+Prism.hooks.add("after-highlight", function (env) {
+  // works only for <code> wrapped inside <pre data-line-numbers> (not inline)
+  var pre = env.element.parentNode;
+  if (
+    !pre ||
+    !/pre/i.test(pre.nodeName) ||
+    pre.className.indexOf("line-numbers") === -1
+  ) {
+    return;
+  }
+
+  var linesNum = 1 + env.code.split("\n").length;
+  var lineNumbersWrapper;
+
+  lines = new Array(linesNum);
+  lines = lines.join("<span></span>");
+
+  lineNumbersWrapper = document.createElement("span");
+  lineNumbersWrapper.className = "line-numbers-rows";
+  lineNumbersWrapper.innerHTML = lines;
+
+  if (pre.hasAttribute("data-start")) {
+    pre.style.counterReset =
+      "linenumber " + (parseInt(pre.getAttribute("data-start"), 10) - 1);
+  }
+
+  env.element.appendChild(lineNumbersWrapper);
+});

new file
public/.deps/prismjs.production.min.js
@@ -0,0 +1,12 @@
+/* https://jasonrivers.github.io/prism/download.html?themes=prism&languages=markup+css+clike+javascript+bash+c+python+sql+http&plugins=line-numbers */
+self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{};var Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content)):"Array"===t.util.type(e)?e.map(t.util.encode):e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var r={};for(var a in e)e.hasOwnProperty(a)&&(r[a]=t.util.clone(e[a]));return r;case"Array":return e.slice()}return e}},languages:{extend:function(e,n){var r=t.util.clone(t.languages[e]);for(var a in n)r[a]=n[a];return r},insertBefore:function(e,n,r,a){a=a||t.languages;var i=a[e],o={};for(var l in i)if(i.hasOwnProperty(l)){if(l==n)for(var s in r)r.hasOwnProperty(s)&&(o[s]=r[s]);o[l]=i[l]}return a[e]=o},DFS:function(e,n){for(var r in e)n.call(e,r,e[r]),"Object"===t.util.type(e)&&t.languages.DFS(e[r],n)}},highlightAll:function(e,n){for(var r,a=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'),i=0;r=a[i++];)t.highlightElement(r,e===!0,n)},highlightElement:function(r,a,i){for(var o,l,s=r;s&&!e.test(s.className);)s=s.parentNode;if(s&&(o=(s.className.match(e)||[,""])[1],l=t.languages[o]),l){r.className=r.className.replace(e,"").replace(/\s+/g," ")+" language-"+o,s=r.parentNode,/pre/i.test(s.nodeName)&&(s.className=s.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var c=r.textContent;if(c){var g={element:r,language:o,grammar:l,code:c};if(t.hooks.run("before-highlight",g),a&&self.Worker){var u=new Worker(t.filename);u.onmessage=function(e){g.highlightedCode=n.stringify(JSON.parse(e.data),o),t.hooks.run("before-insert",g),g.element.innerHTML=g.highlightedCode,i&&i.call(g.element),t.hooks.run("after-highlight",g)},u.postMessage(JSON.stringify({language:g.language,code:g.code}))}else g.highlightedCode=t.highlight(g.code,g.grammar,g.language),t.hooks.run("before-insert",g),g.element.innerHTML=g.highlightedCode,i&&i.call(r),t.hooks.run("after-highlight",g)}}},highlight:function(e,r,a){var i=t.tokenize(e,r);return n.stringify(t.util.encode(i),a)},tokenize:function(e,n){var r=t.Token,a=[e],i=n.rest;if(i){for(var o in i)n[o]=i[o];delete n.rest}e:for(var o in n)if(n.hasOwnProperty(o)&&n[o]){var l=n[o],s=l.inside,c=!!l.lookbehind,g=0;l=l.pattern||l;for(var u=0;u<a.length;u++){var f=a[u];if(a.length>e.length)break e;if(!(f instanceof r)){l.lastIndex=0;var h=l.exec(f);if(h){c&&(g=h[1].length);var d=h.index-1+g,h=h[0].slice(g),p=h.length,m=d+p,v=f.slice(0,d+1),y=f.slice(m+1),k=[u,1];v&&k.push(v);var b=new r(o,s?t.tokenize(h,s):h);k.push(b),y&&k.push(y),Array.prototype.splice.apply(a,k)}}}}return a},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[],r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(r&&r.length)for(var a,i=0;a=r[i++];)a(n)}}},n=t.Token=function(e,t){this.type=e,this.content=t};if(n.stringify=function(e,r,a){if("string"==typeof e)return e;if("[object Array]"==Object.prototype.toString.call(e))return e.map(function(t){return n.stringify(t,r,e)}).join("");var i={type:e.type,content:n.stringify(e.content,r,a),tag:"span",classes:["token",e.type],attributes:{},language:r,parent:a};"comment"==i.type&&(i.attributes.spellcheck="true"),t.hooks.run("wrap",i);var o="";for(var l in i.attributes)o+=l+'="'+(i.attributes[l]||"")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'" '+o+">"+i.content+"</"+i.tag+">"},!self.document)return self.addEventListener?(self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,a=n.code;self.postMessage(JSON.stringify(t.tokenize(a,t.languages[r]))),self.close()},!1),self.Prism):self.Prism;var r=document.getElementsByTagName("script");return r=r[r.length-1],r&&(t.filename=r.src,document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)),self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism);;
+Prism.languages.markup={comment:/<!--[\w\W]*?-->/g,prolog:/<\?.+?\?>/,doctype:/<!DOCTYPE.+?>/,cdata:/<!\[CDATA\[[\w\W]*?]]>/i,tag:{pattern:/<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/gi,inside:{tag:{pattern:/^<\/?[\w:-]+/i,inside:{punctuation:/^<\/?/,namespace:/^[\w-]+?:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,inside:{punctuation:/=|>|"/g}},punctuation:/\/?>/g,"attr-name":{pattern:/[\w:-]+/g,inside:{namespace:/^[\w-]+?:/}}}},entity:/\&#?[\da-z]{1,8};/gi},Prism.hooks.add("wrap",function(t){"entity"===t.type&&(t.attributes.title=t.content.replace(/&amp;/,"&"))});;
+Prism.languages.css={comment:/\/\*[\w\W]*?\*\//g,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*{))/gi,inside:{punctuation:/[;:]/g}},url:/url\((["']?).*?\1\)/gi,selector:/[^\{\}\s][^\{\};]*(?=\s*\{)/g,property:/(\b|\B)[\w-]+(?=\s*:)/gi,string:/("|')(\\?.)*?\1/g,important:/\B!important\b/gi,punctuation:/[\{\};:]/g,"function":/[-a-z0-9]+(?=\()/gi},Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{style:{pattern:/<style[\w\W]*?>[\w\W]*?<\/style>/gi,inside:{tag:{pattern:/<style[\w\W]*?>|<\/style>/gi,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css}}});;
+Prism.languages.clike={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/gi,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,"function":{pattern:/[a-z0-9_]+\(/gi,inside:{punctuation:/\(/}},number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};;
+Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|get|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/<script[\w\W]*?>[\w\W]*?<\/script>/gi,inside:{tag:{pattern:/<script[\w\W]*?>|<\/script>/gi,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}});;
+Prism.languages.bash=Prism.languages.extend("clike",{comment:{pattern:/(^|[^"{\\])(#.*?(\r?\n|$))/g,lookbehind:!0},string:{pattern:/("|')(\\?[\s\S])*?\1/g,inside:{property:/\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^\}]+\})/g}},keyword:/\b(if|then|else|elif|fi|for|break|continue|while|in|case|function|select|do|done|until|echo|exit|return|set|declare)\b/g}),Prism.languages.insertBefore("bash","keyword",{property:/\$([a-zA-Z0-9_#\?\-\*!@]+|\{[^}]+\})/g}),Prism.languages.insertBefore("bash","comment",{important:/(^#!\s*\/bin\/bash)|(^#!\s*\/bin\/sh)/g});;
+Prism.languages.c=Prism.languages.extend("clike",{string:/("|')([^\n\\\1]|\\.|\\\r*\n)*?\1/g,keyword:/\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/g,operator:/[-+]{1,2}|!=?|<{1,2}=?|>{1,2}=?|\->|={1,2}|\^|~|%|&{1,2}|\|?\||\?|\*|\//g}),Prism.languages.insertBefore("c","string",{property:{pattern:/((^|\n)\s*)#\s*[a-z]+([^\n\\]|\\.|\\\r*\n)*/gi,lookbehind:!0,inside:{string:{pattern:/(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/g,lookbehind:!0}}}}),delete Prism.languages.c["class-name"],delete Prism.languages.c["boolean"];;
+Prism.languages.python={comment:{pattern:/(^|[^\\])#.*?(\r?\n|$)/g,lookbehind:!0},string:/"""[\s\S]+?"""|("|')(\\?.)*?\1/g,keyword:/\b(as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/g,"boolean":/\b(True|False)\b/g,number:/\b-?(0x)?\d*\.?[\da-f]+\b/g,operator:/[-+]{1,2}|=?&lt;|=?&gt;|!|={1,2}|(&){1,2}|(&amp;){1,2}|\|?\||\?|\*|\/|~|\^|%|\b(or|and|not)\b/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};;
+Prism.languages.sql={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|((--)|(\/\/)|#).*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?[\s\S])*?\1/g,keyword:/\b(ACTION|ADD|AFTER|ALGORITHM|ALTER|ANALYZE|APPLY|AS|ASC|AUTHORIZATION|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADE|CASCADED|CASE|CHAIN|CHAR VARYING|CHARACTER VARYING|CHECK|CHECKPOINT|CLOSE|CLUSTERED|COALESCE|COLUMN|COLUMNS|COMMENT|COMMIT|COMMITTED|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS|CONTAINSTABLE|CONTINUE|CONVERT|CREATE|CROSS|CURRENT|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATA|DATABASE|DATABASES|DATETIME|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DOUBLE PRECISION|DROP|DUMMY|DUMP|DUMPFILE|DUPLICATE KEY|ELSE|ENABLE|ENCLOSED BY|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPE|ESCAPED BY|EXCEPT|EXEC|EXECUTE|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR|FOR EACH ROW|FORCE|FOREIGN|FREETEXT|FREETEXTTABLE|FROM|FULL|FUNCTION|GEOMETRY|GEOMETRYCOLLECTION|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|IDENTITY|IDENTITY_INSERT|IDENTITYCOL|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTO|INVOKER|ISOLATION LEVEL|JOIN|KEY|KEYS|KILL|LANGUAGE SQL|LAST|LEFT|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONGBLOB|LONGTEXT|MATCH|MATCHED|MEDIUMBLOB|MEDIUMINT|MEDIUMTEXT|MERGE|MIDDLEINT|MODIFIES SQL DATA|MODIFY|MULTILINESTRING|MULTIPOINT|MULTIPOLYGON|NATIONAL|NATIONAL CHAR VARYING|NATIONAL CHARACTER|NATIONAL CHARACTER VARYING|NATIONAL VARCHAR|NATURAL|NCHAR|NCHAR VARCHAR|NEXT|NO|NO SQL|NOCHECK|NOCYCLE|NONCLUSTERED|NULLIF|NUMERIC|OF|OFF|OFFSETS|ON|OPEN|OPENDATASOURCE|OPENQUERY|OPENROWSET|OPTIMIZE|OPTION|OPTIONALLY|ORDER|OUT|OUTER|OUTFILE|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREV|PRIMARY|PRINT|PRIVILEGES|PROC|PROCEDURE|PUBLIC|PURGE|QUICK|RAISERROR|READ|READS SQL DATA|READTEXT|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEATABLE|REPLICATION|REQUIRE|RESTORE|RESTRICT|RETURN|RETURNS|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROWCOUNT|ROWGUIDCOL|ROWS?|RTREE|RULE|SAVE|SAVEPOINT|SCHEMA|SELECT|SERIAL|SERIALIZABLE|SESSION|SESSION_USER|SET|SETUSER|SHARE MODE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|START|STARTING BY|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLE|TABLES|TABLESPACE|TEMPORARY|TEMPTABLE|TERMINATED BY|TEXT|TEXTSIZE|THEN|TIMESTAMP|TINYBLOB|TINYINT|TINYTEXT|TO|TOP|TRAN|TRANSACTION|TRANSACTIONS|TRIGGER|TRUNCATE|TSEQUAL|TYPE|TYPES|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNPIVOT|UPDATE|UPDATETEXT|USAGE|USE|USER|USING|VALUE|VALUES|VARBINARY|VARCHAR|VARCHARACTER|VARYING|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH|WITH ROLLUP|WITHIN|WORK|WRITE|WRITETEXT)\b/gi,"boolean":/\b(TRUE|FALSE|NULL)\b/gi,number:/\b-?(0x)?\d*\.?[\da-f]+\b/g,operator:/\b(ALL|AND|ANY|BETWEEN|EXISTS|IN|LIKE|NOT|OR|IS|UNIQUE|CHARACTER SET|COLLATE|DIV|OFFSET|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b|[-+]{1}|!|=?&lt;|=?&gt;|={1}|(&amp;){1,2}|\|?\||\?|\*|\//gi,ignore:/&(lt|gt|amp);/gi,punctuation:/[;[\]()`,.]/g};;
+Prism.languages.http={"request-line":{pattern:/^(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b\shttps?:\/\/\S+\sHTTP\/[0-9.]+/g,inside:{property:/^\b(POST|GET|PUT|DELETE|OPTIONS|PATCH|TRACE|CONNECT)\b/g,"attr-name":/:\w+/g}},"response-status":{pattern:/^HTTP\/1.[01] [0-9]+.*/g,inside:{property:/[0-9]+[A-Z\s-]+$/g}},keyword:/^[\w-]+:(?=.+)/gm};var httpLanguages={"application/json":Prism.languages.javascript,"application/xml":Prism.languages.markup,"text/xml":Prism.languages.markup,"text/html":Prism.languages.markup};for(var contentType in httpLanguages)if(httpLanguages[contentType]){var options={};options[contentType]={pattern:new RegExp("(content-type:\\s*"+contentType+"[\\w\\W]*?)\\n\\n[\\w\\W]*","gi"),lookbehind:!0,inside:{rest:httpLanguages[contentType]}},Prism.languages.insertBefore("http","keyword",options)};
+Prism.hooks.add("after-highlight",function(e){var n=e.element.parentNode;if(n&&/pre/i.test(n.nodeName)&&-1!==n.className.indexOf("line-numbers")){var t,a=1+e.code.split("\n").length;lines=new Array(a),lines=lines.join("<span></span>"),t=document.createElement("span"),t.className="line-numbers-rows",t.innerHTML=lines,n.hasAttribute("data-start")&&(n.style.counterReset="linenumber "+(parseInt(n.getAttribute("data-start"),10)-1)),e.element.appendChild(t)}});;