changeset 2033:224c4a1625d7

serve homepage with lit and vite
author drewp@bigasterisk.com
date Sat, 09 Apr 2022 01:40:29 -0700
parents 0cd765253fde
children 04ed5d134973
files bin/homepage light9/web/homepage/ServiceButtonRow.ts light9/web/homepage/StatsLine.ts light9/web/homepage/StatsProcess.ts light9/web/homepage/index.html light9/web/homepage/vite.config.ts light9/web/index.html light9/web/stats-line.js light9/web/stats-process.js package.json pnpm-lock.yaml tsconfig.json
diffstat 12 files changed, 767 insertions(+), 380 deletions(-) [+]
line wrap: on
line diff
--- a/bin/homepage	Thu Apr 07 01:17:24 2022 -0700
+++ b/bin/homepage	Sat Apr 09 01:40:29 2022 -0700
@@ -26,15 +26,13 @@
   include "/tmp/light9_nginx_routes.conf";
 
   location / {
-    root $ROOT/light9/web;
-  }
-
-  location /node_modules {
-    root $ROOT/;
+    proxy_pass http://localhost:8300;
   }
 
  }
 }
 EOF
 head -1 /tmp/light9_nginx_routes.conf
-exec /usr/sbin/nginx -c $CONF
+pnpx vite -c light9/web/homepage/vite.config.ts &
+/usr/sbin/nginx -c $CONF
+wait
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light9/web/homepage/ServiceButtonRow.ts	Sat Apr 09 01:40:29 2022 -0700
@@ -0,0 +1,63 @@
+import { LitElement, html, css } from "lit";
+import { customElement, property } from "lit/decorators.js";
+export { StatsLine } from "./StatsLine";
+
+@customElement("service-button-row")
+export class ServiceButtonRow extends LitElement {
+  @property() name: string = "?";
+  static styles = [
+    css`
+      :host {
+        padding-bottom: 10px;
+      }
+      a {
+        color: #7d7dec;
+      }
+      div {
+        display: flex;
+        justify-content: space-between;
+        padding: 2px 3px;
+      }
+      .left {
+        display: inline-block;
+        margin-right: 3px;
+        flex-grow: 1;
+      }
+      .window {
+      }
+      .serviceGrid > td {
+        border: 5px solid red;
+        display: inline-block;
+      }
+      .big {
+        font-size: 120%;
+        display: inline-block;
+        padding: 10px 0;
+      }
+
+      :host > div {
+        display: inline-block;
+        vertical-align: top;
+      }
+      :host > div:nth-child(2) {
+        width: 9em;
+      }
+    `,
+  ];
+
+  render() {
+    return html`
+      <div>
+        <div class="left"><a class="big" href="${this.name}/">${this.name}</a></div>
+        <div class="window"><button @click="${this.click}">window</button></div>
+        <div><a href="${this.name}/stats/">stats</a></div>
+      </div>
+
+      <div id="stats"><stats-line name="${this.name}"></div>
+      `;
+  }
+
+  click() {
+    window.open(this.name + "/", "_blank", "scrollbars=1,resizable=1,titlebar=0,location=0");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light9/web/homepage/StatsLine.ts	Sat Apr 09 01:40:29 2022 -0700
@@ -0,0 +1,181 @@
+import { css, html, LitElement, TemplateResult } from "lit";
+import { customElement, property } from "lit/decorators.js";
+import { rounding } from "significant-rounding";
+import { StatsProcess } from "./StatsProcess";
+
+@customElement("stats-line")
+export class StatsLine extends LitElement {
+  @property() name = "?";
+  @property() stats: any;
+
+  updated(changedProperties: any) {
+    changedProperties.forEach((oldValue: any, propName: string) => {
+      if (propName == "name") {
+        const reload = () => {
+          fetch(this.name + "/stats/?format=json").then((resp) => {
+            if (resp.ok) {
+              resp
+                .json()
+                .then((msg) => {
+                  this.stats = msg;
+                  setTimeout(reload, 1000);
+                })
+                .catch((err) => {
+                  setTimeout(reload, 1000);
+                });
+            } else {
+              if (resp.status == 502) {
+                setTimeout(reload, 5000);
+              }
+              // 404: likely not mapped to a responding server
+            }
+          });
+        };
+        reload();
+      }
+    });
+  }
+
+  static styles = [
+    css`
+      :host {
+        border: 2px solid #46a79f;
+        display: inline-block;
+      }
+      table {
+        border-collapse: collapse;
+        background: #000;
+        color: #ccc;
+        font-family: sans-serif;
+      }
+      th,
+      td {
+        outline: 1px solid #000;
+      }
+      th {
+        padding: 2px 4px;
+        background: #2f2f2f;
+      }
+      td {
+        padding: 0;
+        vertical-align: top;
+        text-align: center;
+      }
+      td.val {
+        padding: 2px 4px;
+        background: #3b5651;
+      }
+      .recents {
+        display: flex;
+        align-items: flex-end;
+        height: 30px;
+      }
+      .recents > div {
+        width: 3px;
+        background: red;
+        border-right: 1px solid black;
+      }
+      .bigInt {
+        min-width: 6em;
+      }
+    `,
+  ];
+
+  render() {
+    const now = Date.now() / 1000;
+
+    const table = (d: any, path: string[]): TemplateResult => {
+      let cols = Object.keys(d);
+      cols.sort();
+
+      if (path.length == 0) {
+        ["webServer", "process"].forEach((earlyKey) => {
+          let i = cols.indexOf(earlyKey);
+          if (i != -1) {
+            cols = [earlyKey].concat(cols.slice(0, i), cols.slice(i + 1));
+          }
+        });
+      }
+
+      const th = (col: string): TemplateResult => {
+        return html`<th>${col}</th>`;
+      };
+      const td = (col: string): TemplateResult => {
+        const cell = d[col];
+        return html`${drawLevel(cell, path.concat(col))}`;
+      };
+      return html` <table>
+        <tr>
+          ${cols.map(th)}
+        </tr>
+        <tr>
+          ${cols.map(td)}
+        </tr>
+      </table>`;
+    };
+
+    const tdWrap = (content: TemplateResult): TemplateResult => {
+      return html`<td>${content}</td>`;
+    };
+
+    const recents = (d: any, path: string[]) => {
+      const hi = Math.max.apply(null, d.recents);
+      const scl = 30 / hi;
+
+      const bar = (y: number) => {
+        let color;
+        if (y < d.average) {
+          color = "#6a6aff";
+        } else {
+          color = "#d09e4c";
+        }
+        return html`<div class="bar" style="height: ${y * scl}px; background: ${color};"></div>`;
+      };
+      return html`<td>
+        <div class="recents">${d.recents.map(bar)}</div>
+        <div>avg=${rounding(d.average, 3)}</div>
+      </td>`;
+    };
+
+    const pmf = (d: any, path: string[]) => {
+      return tdWrap(
+        table(
+          {
+            count: d.count,
+            "values [ms]": html`
+              <div>mean=${rounding(d.mean * 1000, 3)}</div>
+              <div>sd=${rounding(d.stddev * 1000, 3)}</div>
+              <div>99=${rounding(d["99percentile"] * 1000, 3)}</div>
+            `,
+          },
+          path
+        )
+      );
+    };
+
+    const drawLevel = (d: any, path: string[]) => {
+      if (path.length == 1 && path[0] === "process") {
+        const elem = this.shadowRoot!.querySelector("#proc");
+        if (elem) {
+          (elem as StatsProcess).data = d;
+        }
+        return html`<stats-process id="proc"></stats-process>`;
+      }
+      if (typeof d === "object") {
+        if (d.strings) {//} instanceof TemplateResult) {
+          return html`<td class="val">${d}</td>`;
+        } else if (d.count !== undefined && d.min !== undefined) {
+          return pmf(d, path);
+        } else if (d.average !== undefined && d.recents !== undefined) {
+          return recents(d, path);
+        } else {
+          return tdWrap(table(d, path));
+        }
+      } else {
+        return html`<td class="val bigInt">${d}</td>`;
+      }
+    };
+
+    return table(this.stats || {}, []);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light9/web/homepage/StatsProcess.ts	Sat Apr 09 01:40:29 2022 -0700
@@ -0,0 +1,78 @@
+import { LitElement, html, css } from "lit";
+import { customElement, property } from "lit/decorators.js";
+import debug from "debug";
+
+const log = debug("process");
+
+const remap = (x: number, lo: number, hi: number, outLo: number, outHi: number) => {
+  return outLo + (outHi - outLo) * Math.max(0, Math.min(1, (x - lo) / (hi - lo)));
+};
+
+@customElement("stats-process")
+export class StatsProcess extends LitElement {
+  @property() data: any;
+
+  firstUpdated() {
+    // inspired by https://codepen.io/qiruiyin/pen/qOopQx
+    var context = this.shadowRoot!.firstElementChild as HTMLCanvasElement;
+    var ctx = context.getContext("2d")!,
+      w = 64,
+      h = 64,
+      revs = 0;
+
+    context.width = w;
+    context.height = h;
+
+    let prev = Date.now() / 1000;
+
+    var animate = () => {
+      requestAnimationFrame(animate);
+
+      const now = Date.now() / 1000;
+      ctx.beginPath();
+      // wrong type of fade- never goes to 0
+      ctx.fillStyle = "#00000003";
+      ctx.fillRect(0, 0, w, h);
+      if (!this.data || this.data.time < now - 2) {
+        return;
+      }
+      const dt = now - prev;
+      prev = now;
+
+      const size = remap(this.data.memMb, /*in*/ 20, 600, /*out*/ 3, 30);
+      revs += dt * remap(this.data.cpuPercent, /*in*/ 0, 100, /*out*/ 4, 120);
+      const rad = remap(size, /*in*/ 3, 30, /*out*/ 14, 5);
+
+      var x = w / 2 + rad * Math.cos(revs / 6.28),
+        y = h / 2 + rad * Math.sin(revs / 6.28);
+
+      ctx.save();
+      ctx.beginPath();
+      ctx.fillStyle = "hsl(194, 100%, 42%)";
+      ctx.arc(x, y, size, 0, 2 * Math.PI);
+      ctx.fill();
+      ctx.restore();
+    };
+    animate();
+  }
+
+  updated(changedProperties: any) {
+    if (changedProperties.has("data")) {
+      this.shadowRoot!.firstElementChild!.setAttribute("title", `cpu ${this.data.cpuPercent}% mem ${this.data.memMb}MB`);
+    }
+  }
+
+  static styles = [
+    css`
+      :host {
+        display: inline-block;
+        width: 64px;
+        height: 64px;
+      }
+    `,
+  ];
+
+  render() {
+    return html`<canvas></canvas>`;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light9/web/homepage/index.html	Sat Apr 09 01:40:29 2022 -0700
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+  <head>
+    <title>light9 home</title>
+    <meta charset="utf-8" />
+    <link rel="stylesheet" href="@fs/my/proj/light9/light9/web/style.css">
+    <script type="module" src="./ServiceButtonRow.ts"></script>
+  </head>
+  <body>
+     
+    -->
+    <h1>light9 home page</h1>
+
+    <div style="display: grid">
+      <service-button-row name="rdfdb"></service-button-row>
+      <hr>
+      <service-button-row name="ascoltami"></service-button-row>
+      <hr>
+      <!--  <service-button-row name="picamserve"></service-button-row> -->  
+      <service-button-row name="vidref"></service-button-row>
+      <hr>
+      <service-button-row name="collector"></service-button-row>
+      <service-button-row name="effectSequencer"></service-button-row>
+      <service-button-row name="live"></service-button-row>
+      <service-button-row name="effects"></service-button-row>
+      <service-button-row name="timeline"></service-button-row>
+      <service-button-row name="paint"></service-button-row>
+      <service-button-row name="effectEval"></service-button-row>
+<!--       <hr>
+      <service-button-row name="subServer"></service-button-row>
+      <service-button-row name="subComposer"></service-button-row>
+      -->
+    </div>
+    
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light9/web/homepage/vite.config.ts	Sat Apr 09 01:40:29 2022 -0700
@@ -0,0 +1,16 @@
+import { defineConfig } from "vite";
+
+export default defineConfig({
+  root: "./light9/web/homepage",
+  server: {
+    host: "0.0.0.0",
+    strictPort: true,
+    port: 8300,
+    hmr: {
+      port: 8400,
+    },
+  },
+  define: {
+    global: {},
+  },
+});
--- a/light9/web/index.html	Thu Apr 07 01:17:24 2022 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>light9 home</title>
-    <meta charset="utf-8" />
-    <script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>
-    <link rel="stylesheet" href="/style.css">
-    <link rel="import" href="/lib/polymer/polymer.html">
-  </head>
-  <body>
-    <script type="module" src="stats-line.js"></script>
-    <script type="module" src="stats-process.js"></script>
-     
-    <dom-module id="service-button-row">
-      <template>
-        <style>
-         :host { padding-bottom: 10px;  }
-         a {
-             color: #7d7dec;
-         }
-         div {
-             display: flex;
-             justify-content: space-between;
-             padding: 2px 3px;
-         }
-         .left {
-             display: inline-block;
-             margin-right: 3px;
-             flex-grow: 1;
-         }
-         .window {
-         }
-         .serviceGrid > td {
-             border: 5px solid red;
-             display: inline-block;
-         }
-         .big {
-             font-size: 120%;
-             display: inline-block;
-             padding: 10px 0;
-         }
-
-         
-         :host > div { display: inline-block; vertical-align: top; }
-         :host > div:nth-child(2) { width: 9em; }
-        </style>
-
-        <div>
-        <div class="left"><a class="big" href="{{name}}/">{{name}}</a></div>
-        <div class="window"><button on-click="click">window</button></div>
-        <div><a href="{{name}}/stats/">stats</a></div>
-        </div>
-
-        <div id="stats"><stats-line name="{{name}}"></div>
-      </template>
-      <script>
-       HTMLImports.whenReady(function () {
-         Polymer({
-           is: "service-button-row",
-           properties: {
-             name: String,
-           },
-           ready: function() {
-           },
-           click: function() {
-             window.open(this.name + '/', '_blank',
-                         'scrollbars=1,resizable=1,titlebar=0,location=0');
-           },
-         });
-       });
-      </script>
-    </dom-module>
-    
-    <h1>light9 home page</h1>
-
-    <div style="display: grid">
-      <service-button-row name="rdfdb"></service-button-row>
-      <hr>
-      <service-button-row name="ascoltami"></service-button-row>
-      <hr>
-      <!--  <service-button-row name="picamserve"></service-button-row> -->  
-      <service-button-row name="vidref"></service-button-row>
-      <hr>
-      <service-button-row name="collector"></service-button-row>
-      <service-button-row name="effectSequencer"></service-button-row>
-      <service-button-row name="live"></service-button-row>
-      <service-button-row name="effects"></service-button-row>
-      <service-button-row name="timeline"></service-button-row>
-      <service-button-row name="paint"></service-button-row>
-      <service-button-row name="effectEval"></service-button-row>
-<!--       <hr>
-      <service-button-row name="subServer"></service-button-row>
-      <service-button-row name="subComposer"></service-button-row>
-      -->
-    </div>
-    
-  </body>
-</html>
--- a/light9/web/stats-line.js	Thu Apr 07 01:17:24 2022 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +0,0 @@
-import { LitElement, TemplateResult, html, css } from '/node_modules/lit-element/lit-element.js';
-import { rounding }  from '/node_modules/significant-rounding/index.js';
-
-class StatsLine extends LitElement {
-    
-    static get properties() {
-        return {
-            name: {
-                type: String,
-                reflect: true,
-                
-            },
-            stats: Object // to be refreshed with ws
-        };
-    }
-
-    updated(changedProperties) {
-        changedProperties.forEach((oldValue, propName) => {
-            if (propName == 'name') {
-                const reload = () => {
-                    fetch(this.name + '/stats/?format=json').then((resp) => {
-                        if (resp.ok) {
-                            resp.json().then((msg) => {
-                                this.stats = msg;
-                                setTimeout(reload, 1000);
-                            }).catch((err) => {
-                                setTimeout(reload, 1000);
-                            });
-                        } else {
-                            if (resp.status == 502) {
-                                setTimeout(reload, 5000);
-                            }
-                            // 404: likely not mapped to a responding server
-                        }
-                    });
-                }
-                reload();
-            }
-        });
-    }
-    
-    static get styles() {
-        return css`
-        :host {
-            border: 2px solid #46a79f;
-            display: inline-block;
-        }
-        table { 
-            border-collapse: collapse;
-            background: #000;
-            color: #ccc;
-            font-family: sans-serif;
-        }
-        th, td { 
-            outline: 1px solid #000; 
-        }
-        th {
-            padding: 2px 4px;
-            background: #2f2f2f;
-        }
-        td {
-            padding: 0;
-            vertical-align: top;
-            text-align: center;
-        }
-        td.val {
-            padding: 2px 4px;
-            background: #3b5651;
-        }
-        .recents { 
-            display: flex;
-            align-items: flex-end;
-            height: 30px;
-        }
-        .recents > div {
-            width: 3px;
-            background: red;
-            border-right: 1px solid black;
-        }
-        .bigInt {
-            min-width: 6em;
-        }
-        `;
-    }
-    
-    render() {
-        const now = Date.now() / 1000;
-        const table = (d, path) => {
-
-            let cols = Object.keys(d);
-            cols.sort();
-
-            if (path.length == 0) {
-                ['webServer', 'process'].forEach((earlyKey) => {
-                    let i = cols.indexOf(earlyKey);
-                    if (i != -1) {
-                        cols = [earlyKey].concat(cols.slice(0, i), cols.slice(i + 1));
-                    }
-                });
-            }
-            
-            const th = (col) =>  {
-                return html`<th>${col}</th>`;
-            };
-            const td = (col)  => {
-                const cell = d[col];
-                return html`${drawLevel(cell, path.concat(col))}`;
-            };
-            return html`
-             <table>
-               <tr>
-                 ${cols.map(th)}
-               </tr>
-                 <tr>
-                   ${cols.map(td)}
-                 </tr>
-             </table>`;
-        };
-        const tdWrap = (content) => {
-            return html`<td>${content}</td>`;
-        }
-        const recents = (d, path) => {
-            const hi = Math.max.apply(null, d.recents);
-            const scl = 30 / hi;
-            
-            const bar = (y) => {
-                let color;
-                if (y < d.average) {
-                    color="#6a6aff";
-                } else {
-                    color="#d09e4c";
-                }
-                return html`<div class="bar" style="height: ${y * scl}px; background: ${color};"></div>`;
-            };
-            return html`<td>
-               <div class="recents">${d.recents.map(bar)}</div>
-               <div>avg=${rounding(d.average ,3)}</div>`;
-
-        };
-        const pmf = (d, path) => {
-            return tdWrap(table({
-                count: d.count,
-                'values [ms]': html`
-                   <div>mean=${rounding(d.mean*1000, 3)}</div>
-                   <div>sd=${rounding(d.stddev*1000, 3)}</div>
-                   <div>99=${rounding(d['99percentile']*1000, 3)}</div>
-                 `
-            }, path));
-        };
-        const drawLevel = (d, path) => {
-            if (path.length == 1 && path[0] === 'process') {
-                 const elem = this.shadowRoot.querySelector('#proc');
-                if (elem) {
-                    elem.data = d;
-                }
-                return html`<stats-process id="proc"></stats-process>`;
-            }
-            if (typeof d === 'object') {
-                if (d instanceof TemplateResult) {
-                    return html`<td class="val">${d}</td>`;
-                } else if (d.count !== undefined && d.min !== undefined) {
-                    return pmf(d, path);
-                } else if (d.average !== undefined && d.recents !== undefined) {
-                    return recents(d, path);
-                } else {
-                    return tdWrap(table(d, path));
-                }
-            } else {             
-                return html`<td class="val bigInt">${d}</td>`;
-            }
-        };
-        return table(this.stats || {}, []);
-    }
-}
-customElements.define('stats-line', StatsLine);
--- a/light9/web/stats-process.js	Thu Apr 07 01:17:24 2022 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-import { LitElement, TemplateResult, html, css } from '/node_modules/lit-element/lit-element.js';
-import debug from '/lib/debug/debug-build-es6.js';
-import { rounding }  from '/node_modules/significant-rounding/index.js';
-
-const log = debug('process');
-
-const remap = (x, lo, hi, outLo, outHi) => {
-    return outLo + (outHi - outLo) * Math.max(0, Math.min(1, (x - lo) / (hi - lo)));
-};
-
-class StatsProcess extends LitElement {
-    
-    static get properties() {
-        return {
-            data: { type: Object },
-        };
-    }
-
-    firstUpdated() {
-        // inspired by https://codepen.io/qiruiyin/pen/qOopQx
-        var context = this.shadowRoot.firstElementChild,
-	    ctx = context.getContext('2d'),
-	    w = 64,
-	    h = 64,
-	    revs = 0;   
-	
-	context.width = w;
-	context.height = h;
-
-        let prev = Date.now() / 1000;
-
-        var animate = () => {
-	    requestAnimationFrame( animate );
-
-            const now = Date.now() / 1000;
-            ctx.beginPath();
-            // wrong type of fade- never goes to 0
-            ctx.fillStyle = '#00000003';
-            ctx.fillRect(0, 0, w, h);
-            if (!this.data || this.data.time < now - 2) {
-                return;
-            }
-            const dt = now - prev;
-            prev = now;
-
-            const size = remap(this.data.memMb, /*in*/ 20, 600, /*out*/ 3, 30);
-	    revs += dt * remap(this.data.cpuPercent, /*in*/ 0, 100, /*out*/ 4, 120);
-            const rad  = remap(size, /*in*/ 3, 30, /*out*/ 14, 5);
-
-	    var x = w/2 + rad * Math.cos(revs / 6.28),
-		y = h/2 + rad * Math.sin(revs / 6.28);
-
-	    ctx.save();
-	    ctx.beginPath();
-	    ctx.fillStyle = "hsl(194, 100%, 42%)";
-	    ctx.arc(x, y, size, 0, 2*Math.PI);
-	    ctx.fill();
-	    ctx.restore();
-	    
-        };
-        animate();
-    }
-    
-    updated(changedProperties) {
-        if (changedProperties.has('data')) {
-            this.shadowRoot.firstElementChild.setAttribute('title', `cpu ${this.data.cpuPercent}% mem ${this.data.memMb}MB`);
-        }
-    }
-
-    static get styles() {
-        return css`
-        :host {
-           display: inline-block;
-           width: 64px;
-           height: 64px;
-        }
-        `;
-    }
-    
-    render() {
-        return html`<canvas></canvas>`;
-
-    }
-}
-customElements.define('stats-process', StatsProcess);
-
--- a/package.json	Thu Apr 07 01:17:24 2022 -0700
+++ b/package.json	Sat Apr 09 01:40:29 2022 -0700
@@ -9,6 +9,7 @@
     "test": "test"
   },
   "dependencies": {
+    "@types/debug": "^4.1.7",
     "@webcomponents/shadycss": "^1.3.1",
     "@webcomponents/webcomponentsjs": "^1.2.0",
     "bower": "^1.8.4",
@@ -18,14 +19,15 @@
     "coffeelint": "^2.1.0",
     "coffeescript": "^2.3.0",
     "d3": "^5.1.0",
+    "debug": "^4.3.4",
     "esmify": "^2.1.1",
-    "lit-element": "^2.1.0",
-    "lit-html": "^1.1.0",
+    "lit": "^2.2.2",
     "mocha": "^2.5.3",
     "n3": "^1.0.0-alpha",
     "pixi.js": "^4.7.3",
     "significant-rounding": "^2.0.0",
-    "tinycolor2": "^1.4.1"
+    "tinycolor2": "^1.4.1",
+    "vite": "^2.9.1"
   },
   "devDependencies": {
     "mocha": "^2.5.3"
--- a/pnpm-lock.yaml	Thu Apr 07 01:17:24 2022 -0700
+++ b/pnpm-lock.yaml	Sat Apr 09 01:40:29 2022 -0700
@@ -1,6 +1,7 @@
 lockfileVersion: 5.3
 
 specifiers:
+  '@types/debug': ^4.1.7
   '@webcomponents/shadycss': ^1.3.1
   '@webcomponents/webcomponentsjs': ^1.2.0
   bower: ^1.8.4
@@ -10,16 +11,18 @@
   coffeelint: ^2.1.0
   coffeescript: ^2.3.0
   d3: ^5.1.0
+  debug: ^4.3.4
   esmify: ^2.1.1
-  lit-element: ^2.1.0
-  lit-html: ^1.1.0
+  lit: ^2.2.2
   mocha: ^2.5.3
   n3: ^1.0.0-alpha
   pixi.js: ^4.7.3
   significant-rounding: ^2.0.0
   tinycolor2: ^1.4.1
+  vite: ^2.9.1
 
 dependencies:
+  '@types/debug': 4.1.7
   '@webcomponents/shadycss': 1.11.0
   '@webcomponents/webcomponentsjs': 1.3.3
   bower: 1.8.14
@@ -29,14 +32,15 @@
   coffeelint: 2.1.0
   coffeescript: 2.6.1
   d3: 5.16.0
+  debug: 4.3.4
   esmify: 2.1.1
-  lit-element: 2.5.1
-  lit-html: 1.4.1
+  lit: 2.2.2
   mocha: 2.5.3
   n3: 1.16.0
   pixi.js: 4.8.9
   significant-rounding: 2.0.0
   tinycolor2: 1.4.2
+  vite: 2.9.1
 
 packages:
 
@@ -1275,6 +1279,24 @@
       '@jridgewell/sourcemap-codec': 1.4.11
     dev: false
 
+  /@lit/reactive-element/1.3.1:
+    resolution: {integrity: sha512-nOJARIr3pReqK3hfFCSW2Zg/kFcFsSAlIE7z4a0C9D2dPrgD/YSn3ZP2ET/rxKB65SXyG7jJbkynBRm+tGlacw==}
+    dev: false
+
+  /@types/debug/4.1.7:
+    resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==}
+    dependencies:
+      '@types/ms': 0.7.31
+    dev: false
+
+  /@types/ms/0.7.31:
+    resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
+    dev: false
+
+  /@types/trusted-types/2.0.2:
+    resolution: {integrity: sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==}
+    dev: false
+
   /@webcomponents/shadycss/1.11.0:
     resolution: {integrity: sha512-L5O/+UPum8erOleNjKq6k58GVl3fNsEQdSOyh0EUhNmi7tHUyRuCJy1uqJiWydWcLARE5IPsMoPYMZmUGrz1JA==}
     dev: false
@@ -3224,6 +3246,214 @@
       minimalistic-crypto-utils: 1.0.1
     dev: false
 
+  /esbuild-android-64/0.14.34:
+    resolution: {integrity: sha512-XfxcfJqmMYsT/LXqrptzFxmaR3GWzXHDLdFNIhm6S00zPaQF1TBBWm+9t0RZ6LRR7iwH57DPjaOeW20vMqI4Yw==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [android]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-android-arm64/0.14.34:
+    resolution: {integrity: sha512-T02+NXTmSRL1Mc6puz+R9CB54rSPICkXKq6+tw8B6vxZFnCPzbJxgwIX4kcluz9p8nYBjF3+lSilTGWb7+Xgew==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [android]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-darwin-64/0.14.34:
+    resolution: {integrity: sha512-pLRip2Bh4Ng7Bf6AMgCrSp3pPe/qZyf11h5Qo2mOfJqLWzSVjxrXW+CFRJfrOVP7TCnh/gmZSM2AFdCPB72vtw==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [darwin]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-darwin-arm64/0.14.34:
+    resolution: {integrity: sha512-vpidSJEBxx6lf1NWgXC+DCmGqesJuZ5Y8aQVVsaoO4i8tRXbXb0whChRvop/zd3nfNM4dIl5EXAky0knRX5I6w==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [darwin]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-freebsd-64/0.14.34:
+    resolution: {integrity: sha512-m0HBjePhe0hAQJgtMRMNV9kMgIyV4/qSnzPx42kRMQBcPhgjAq1JRu4Il26czC+9FgpMbFkUktb07f/Lwnc6CA==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [freebsd]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-freebsd-arm64/0.14.34:
+    resolution: {integrity: sha512-cpRc2B94L1KvMPPYB4D6G39jLqpKlD3noAMY4/e86iXXXkhUYJJEtTuyNFTa9JRpWM0xCAp4mxjHjoIiLuoCLA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [freebsd]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-linux-32/0.14.34:
+    resolution: {integrity: sha512-8nQaEaoW7MH/K/RlozJa+lE1ejHIr8fuPIHhc513UebRav7HtXgQvxHQ6VZRUkWtep23M6dd7UqhwO1tMOfzQQ==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [linux]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-linux-64/0.14.34:
+    resolution: {integrity: sha512-Y3of4qQoLLlAgf042MlrY1P+7PnN9zWj8nVtw9XQG5hcLOZLz7IKpU35oeu7n4wvyaZHwvQqDJ93gRLqdJekcQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [linux]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-linux-arm/0.14.34:
+    resolution: {integrity: sha512-9lpq1NcJqssAF7alCO6zL3gvBVVt/lKw4oetUM7OgNnRX0OWpB+ZIO9FwCrSj/dMdmgDhPLf+119zB8QxSMmAg==}
+    engines: {node: '>=12'}
+    cpu: [arm]
+    os: [linux]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-linux-arm64/0.14.34:
+    resolution: {integrity: sha512-IlWaGtj9ir7+Nrume1DGcyzBDlK8GcnJq0ANKwcI9pVw8tqr+6GD0eqyF9SF1mR8UmAp+odrx1H5NdR2cHdFHA==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [linux]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-linux-mips64le/0.14.34:
+    resolution: {integrity: sha512-k3or+01Rska1AjUyNjA4buEwB51eyN/xPQAoOx1CjzAQC3l8rpjUDw55kXyL63O/1MUi4ISvtNtl8gLwdyEcxw==}
+    engines: {node: '>=12'}
+    cpu: [mips64el]
+    os: [linux]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-linux-ppc64le/0.14.34:
+    resolution: {integrity: sha512-+qxb8M9FfM2CJaVU7GgYpJOHM1ngQOx+/VrtBjb4C8oVqaPcESCeg2anjl+HRZy8VpYc71q/iBYausPPbJ+Keg==}
+    engines: {node: '>=12'}
+    cpu: [ppc64]
+    os: [linux]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-linux-riscv64/0.14.34:
+    resolution: {integrity: sha512-Y717ltBdQ5j5sZIHdy1DV9kieo0wMip0dCmVSTceowCPYSn1Cg33Kd6981+F/3b9FDMzNWldZFOBRILViENZSA==}
+    engines: {node: '>=12'}
+    cpu: [riscv64]
+    os: [linux]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-linux-s390x/0.14.34:
+    resolution: {integrity: sha512-bDDgYO4LhL4+zPs+WcBkXph+AQoPcQRTv18FzZS0WhjfH8TZx2QqlVPGhmhZ6WidrY+jKthUqO6UhGyIb4MpmA==}
+    engines: {node: '>=12'}
+    cpu: [s390x]
+    os: [linux]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-netbsd-64/0.14.34:
+    resolution: {integrity: sha512-cfaFGXdRt0+vHsjNPyF0POM4BVSHPSbhLPe8mppDc7GDDxjIl08mV1Zou14oDWMp/XZMjYN1kWYRSfftiD0vvQ==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [netbsd]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-openbsd-64/0.14.34:
+    resolution: {integrity: sha512-vmy9DxXVnRiI14s8GKuYBtess+EVcDALkbpTqd5jw4XITutIzyB7n4x0Tj5utAkKsgZJB22lLWGekr0ABnSLow==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [openbsd]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-sunos-64/0.14.34:
+    resolution: {integrity: sha512-eNPVatNET1F7tRMhii7goL/eptfxc0ALRjrj9SPFNqp0zmxrehBFD6BaP3R4LjMn6DbMO0jOAnTLFKr8NqcJAA==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [sunos]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-windows-32/0.14.34:
+    resolution: {integrity: sha512-EFhpXyHEcnqWYe2rAHFd8dRw8wkrd9U+9oqcyoEL84GbanAYjiiIjBZsnR8kl0sCQ5w6bLpk7vCEIA2VS32Vcg==}
+    engines: {node: '>=12'}
+    cpu: [ia32]
+    os: [win32]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-windows-64/0.14.34:
+    resolution: {integrity: sha512-a8fbl8Ky7PxNEjf1aJmtxdDZj32/hC7S1OcA2ckEpCJRTjiKslI9vAdPpSjrKIWhws4Galpaawy0nB7fjHYf5Q==}
+    engines: {node: '>=12'}
+    cpu: [x64]
+    os: [win32]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild-windows-arm64/0.14.34:
+    resolution: {integrity: sha512-EYvmKbSa2B3sPnpC28UEu9jBK5atGV4BaVRE7CYGUci2Hlz4AvtV/LML+TcDMT6gBgibnN2gcltWclab3UutMg==}
+    engines: {node: '>=12'}
+    cpu: [arm64]
+    os: [win32]
+    requiresBuild: true
+    dev: false
+    optional: true
+
+  /esbuild/0.14.34:
+    resolution: {integrity: sha512-QIWdPT/gFF6hCaf4m7kP0cJ+JIuFkdHibI7vVFvu3eJS1HpVmYHWDulyN5WXwbRA0SX/7ZDaJ/1DH8SdY9xOJg==}
+    engines: {node: '>=12'}
+    hasBin: true
+    requiresBuild: true
+    optionalDependencies:
+      esbuild-android-64: 0.14.34
+      esbuild-android-arm64: 0.14.34
+      esbuild-darwin-64: 0.14.34
+      esbuild-darwin-arm64: 0.14.34
+      esbuild-freebsd-64: 0.14.34
+      esbuild-freebsd-arm64: 0.14.34
+      esbuild-linux-32: 0.14.34
+      esbuild-linux-64: 0.14.34
+      esbuild-linux-arm: 0.14.34
+      esbuild-linux-arm64: 0.14.34
+      esbuild-linux-mips64le: 0.14.34
+      esbuild-linux-ppc64le: 0.14.34
+      esbuild-linux-riscv64: 0.14.34
+      esbuild-linux-s390x: 0.14.34
+      esbuild-netbsd-64: 0.14.34
+      esbuild-openbsd-64: 0.14.34
+      esbuild-sunos-64: 0.14.34
+      esbuild-windows-32: 0.14.34
+      esbuild-windows-64: 0.14.34
+      esbuild-windows-arm64: 0.14.34
+    dev: false
+
   /escalade/3.1.1:
     resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
     engines: {node: '>=6'}
@@ -3446,6 +3676,14 @@
     resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=}
     dev: false
 
+  /fsevents/2.3.2:
+    resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+    os: [darwin]
+    requiresBuild: true
+    dev: false
+    optional: true
+
   /function-bind/1.1.1:
     resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
     dev: false
@@ -4074,14 +4312,25 @@
       immediate: 3.0.6
     dev: false
 
-  /lit-element/2.5.1:
-    resolution: {integrity: sha512-ogu7PiJTA33bEK0xGu1dmaX5vhcRjBXCFexPja0e7P7jqLhTpNKYRPmE+GmiCaRVAbiQKGkUgkh/i6+bh++dPQ==}
-    dependencies:
-      lit-html: 1.4.1
-    dev: false
-
-  /lit-html/1.4.1:
-    resolution: {integrity: sha512-B9btcSgPYb1q4oSOb/PrOT6Z/H+r6xuNzfH4lFli/AWhYwdtrgQkQWBbIc6mdnf6E2IL3gDXdkkqNktpU0OZQA==}
+  /lit-element/3.2.0:
+    resolution: {integrity: sha512-HbE7yt2SnUtg5DCrWt028oaU4D5F4k/1cntAFHTkzY8ZIa8N0Wmu92PxSxucsQSOXlODFrICkQ5x/tEshKi13g==}
+    dependencies:
+      '@lit/reactive-element': 1.3.1
+      lit-html: 2.2.2
+    dev: false
+
+  /lit-html/2.2.2:
+    resolution: {integrity: sha512-cJofCRXuizwyaiGt9pJjJOcauezUlSB6t87VBXsPwRhbzF29MgD8GH6fZ0BuZdXAAC02IRONZBd//VPUuU8QbQ==}
+    dependencies:
+      '@types/trusted-types': 2.0.2
+    dev: false
+
+  /lit/2.2.2:
+    resolution: {integrity: sha512-eN3+2QRHn/erxYB88AXiiRgQA6RltE9MhzySCwX+ACOxA/MLWN3VdXvcbZD9PN09zmUwlgzDvW3T84YWj2Sa0A==}
+    dependencies:
+      '@lit/reactive-element': 1.3.1
+      lit-element: 3.2.0
+      lit-html: 2.2.2
     dev: false
 
   /locate-path/3.0.0:
@@ -4349,6 +4598,12 @@
       readable-stream: 3.6.0
     dev: false
 
+  /nanoid/3.3.2:
+    resolution: {integrity: sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==}
+    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+    hasBin: true
+    dev: false
+
   /nanomatch/1.2.13:
     resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==}
     engines: {node: '>=0.10.0'}
@@ -4645,6 +4900,15 @@
     engines: {node: '>=0.10.0'}
     dev: false
 
+  /postcss/8.4.12:
+    resolution: {integrity: sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==}
+    engines: {node: ^10 || ^12 || >=14}
+    dependencies:
+      nanoid: 3.3.2
+      picocolors: 1.0.0
+      source-map-js: 1.0.2
+    dev: false
+
   /preserve/0.2.0:
     resolution: {integrity: sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=}
     engines: {node: '>=0.10.0'}
@@ -5009,6 +5273,14 @@
       inherits: 2.0.4
     dev: false
 
+  /rollup/2.70.1:
+    resolution: {integrity: sha512-CRYsI5EuzLbXdxC6RnYhOuRdtz4bhejPMSWjsFLfVM/7w/85n2szZv6yExqUXsBdz5KT8eoubeyDUDjhLHEslA==}
+    engines: {node: '>=10.0.0'}
+    hasBin: true
+    optionalDependencies:
+      fsevents: 2.3.2
+    dev: false
+
   /rw/1.3.3:
     resolution: {integrity: sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=}
     dev: false
@@ -5156,6 +5428,11 @@
       use: 3.1.1
     dev: false
 
+  /source-map-js/1.0.2:
+    resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
+    engines: {node: '>=0.10.0'}
+    dev: false
+
   /source-map-resolve/0.5.3:
     resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==}
     dependencies:
@@ -5540,6 +5817,30 @@
       inherits: 2.0.3
     dev: false
 
+  /vite/2.9.1:
+    resolution: {integrity: sha512-vSlsSdOYGcYEJfkQ/NeLXgnRv5zZfpAsdztkIrs7AZHV8RCMZQkwjo4DS5BnrYTqoWqLoUe1Cah4aVO4oNNqCQ==}
+    engines: {node: '>=12.2.0'}
+    hasBin: true
+    peerDependencies:
+      less: '*'
+      sass: '*'
+      stylus: '*'
+    peerDependenciesMeta:
+      less:
+        optional: true
+      sass:
+        optional: true
+      stylus:
+        optional: true
+    dependencies:
+      esbuild: 0.14.34
+      postcss: 8.4.12
+      resolve: 1.22.0
+      rollup: 2.70.1
+    optionalDependencies:
+      fsevents: 2.3.2
+    dev: false
+
   /vm-browserify/1.1.2:
     resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==}
     dev: false
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tsconfig.json	Sat Apr 09 01:40:29 2022 -0700
@@ -0,0 +1,71 @@
+{
+  "compilerOptions": {
+    /* Visit https://aka.ms/tsconfig.json to read more about this file */
+
+    /* Basic Options */
+    // "incremental": true,                         /* Enable incremental compilation */
+    "target": "es2020",                             /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
+    "module": "es2020",                             /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
+    // "lib": [],                                   /* Specify library files to be included in the compilation. */
+    // "allowJs": true,                             /* Allow javascript files to be compiled. */
+    // "checkJs": true,                             /* Report errors in .js files. */
+    // "jsx": "preserve",                           /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
+    // "declaration": true,                         /* Generates corresponding '.d.ts' file. */
+    // "declarationMap": true,                      /* Generates a sourcemap for each corresponding '.d.ts' file. */
+    // "sourceMap": true,                           /* Generates corresponding '.map' file. */
+    // "outFile": "./",                             /* Concatenate and emit output to single file. */
+    // "outDir": "./",                              /* Redirect output structure to the directory. */
+    // "rootDir": "./",                             /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
+    // "composite": true,                           /* Enable project compilation */
+    // "tsBuildInfoFile": "./",                     /* Specify file to store incremental compilation information */
+    // "removeComments": true,                      /* Do not emit comments to output. */
+    // "noEmit": true,                              /* Do not emit outputs. */
+    // "importHelpers": true,                       /* Import emit helpers from 'tslib'. */
+    // "downlevelIteration": true,                  /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
+    // "isolatedModules": true,                     /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
+
+    /* Strict Type-Checking Options */
+    "strict": true,                                 /* Enable all strict type-checking options. */
+    // "noImplicitAny": true,                       /* Raise error on expressions and declarations with an implied 'any' type. */
+    // "strictNullChecks": true,                    /* Enable strict null checks. */
+    // "strictFunctionTypes": true,                 /* Enable strict checking of function types. */
+    // "strictBindCallApply": true,                 /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
+    // "strictPropertyInitialization": true,        /* Enable strict checking of property initialization in classes. */
+    // "noImplicitThis": true,                      /* Raise error on 'this' expressions with an implied 'any' type. */
+    // "alwaysStrict": true,                        /* Parse in strict mode and emit "use strict" for each source file. */
+
+    /* Additional Checks */
+    // "noUnusedLocals": true,                      /* Report errors on unused locals. */
+    // "noUnusedParameters": true,                  /* Report errors on unused parameters. */
+    // "noImplicitReturns": true,                   /* Report error when not all code paths in function return a value. */
+    // "noFallthroughCasesInSwitch": true,          /* Report errors for fallthrough cases in switch statement. */
+    // "noUncheckedIndexedAccess": true,            /* Include 'undefined' in index signature results */
+    // "noPropertyAccessFromIndexSignature": true,  /* Require undeclared properties from index signatures to use element accesses. */
+
+    /* Module Resolution Options */
+    "moduleResolution": "node",                  /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
+    // "baseUrl": "./",                             /* Base directory to resolve non-absolute module names. */
+    // "paths": {},                                 /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
+    // "rootDirs": [],                              /* List of root folders whose combined content represents the structure of the project at runtime. */
+    // "typeRoots": ["/my/proj/light9/light9/web/homepage"],                             /* List of folders to include type definitions from. */
+    // "types": [],                                 /* Type declaration files to be included in compilation. */
+    // "allowSyntheticDefaultImports": true,        /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
+    "esModuleInterop": true,                        /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
+    // "preserveSymlinks": true,                    /* Do not resolve the real path of symlinks. */
+    // "allowUmdGlobalAccess": true,                /* Allow accessing UMD globals from modules. */
+
+    /* Source Map Options */
+    // "sourceRoot": "",                            /* Specify the location where debugger should locate TypeScript files instead of source locations. */
+    // "mapRoot": "",                               /* Specify the location where debugger should locate map files instead of generated locations. */
+    // "inlineSourceMap": true,                     /* Emit a single file with source maps instead of having a separate file. */
+    // "inlineSources": true,                       /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
+
+    /* Experimental Options */
+    "experimentalDecorators": true,              /* Enables experimental support for ES7 decorators. */
+    // "emitDecoratorMetadata": true,               /* Enables experimental support for emitting type metadata for decorators. */
+
+    /* Advanced Options */
+    "skipLibCheck": true,                           /* Skip type checking of declaration files. */
+    "forceConsistentCasingInFileNames": true        /* Disallow inconsistently-cased references to the same file. */
+  }
+}