{
"version": 3,
"sources": ["../../../assets/lib/bm.js/bm.module.js", "../../../assets/lib/bm.js/components/alert/alert.js", "../../../assets/lib/bm.js/components/common.js", "../../../assets/lib/bm.js/components/breadcrumb/breadcrumb.js", "../../../assets/lib/bm.js/components/button/button.js", "../../../assets/lib/bm.js/components/card/card.js", "../../../assets/lib/bm.js/components/chip/chip.js", "../../../assets/lib/bm.js/components/collapse/collapse.js", "../../../assets/lib/bm.js/components/icon/icon.js", "../../../assets/lib/bm.js/components/input/input.js", "../../../assets/lib/bm.js/components/layout/full-page.js", "../../../assets/lib/bm.js/components/modal/modal.js", "../../../assets/lib/bm.js/components/placeholder/placeholder.js", "../../../assets/lib/bm.js/components/tabs/tabs.js", "../../../assets/lib/bm.js/components/tabs/tab-header.js", "../../../assets/lib/bm.js/components/tabs/tab-panel.js", "../../../assets/lib/bm.js/components/data.js", "../../../assets/js/common.js", "../../../assets/js/components/dropdown/dropdown.js", "../../../assets/js/components/go-back.js", "../../../assets/js/components/input/key-value.js", "../../../assets/js/components/input/list.js", "../../../assets/js/components/link-tabs/tabs.js", "../../../assets/js/components/popover/popover.js", "../../../assets/js/components/slider/range.js", "../../../assets/js/components/slider/slider.js", "../../../assets/js/components/switch/switch.js", "../../../assets/js/components/textarea/textarea.js", "../../../assets/js/enhanced/button.js", "../../../assets/js/enhanced/form.js", "../../../assets/js/enhanced/textarea.js", "../../../assets/js/layout/header/logo.js", "../../../assets/js/layout/header/search.js", "../../../assets/js/shortcut.js"],
"sourcesContent": ["// bluemir's micro js library.\n// light-weight & simple & vanilla friendly\n//\n// Usage\n// import * as $ from \"bm.module.js\";\nexport var config = {\n\thook: {\n\t\tpreRequest: function(method, url, opt) { return opt }\n\t},\n}\n\nexport function get(target, query) {\n\tif(target.querySelector instanceof Function) {\n\t\treturn target.querySelector(query);\n\t}\n\treturn document.querySelector(target)\n}\nexport function all(target, query) {\n\tif(target.querySelectorAll instanceof Function) {\n\t\treturn target.querySelectorAll(query);\n\t}\n\treturn document.querySelectorAll(target);\n}\nexport function create(tagname, attr = {}) {\n\tvar newTag = document.createElement(tagname);\n\tif (attr.$text){\n\t\tnewTag.appendChild(document.createTextNode(attr.$text));\n\t}\n\tif (attr.$html){\n\t\tnewTag.innerHTML = attr.$html;\n\t}\n\tif (attr.$child) {\n\t\tif (attr.$child instanceof Array){\n\t\t\tattr.$child.forEach(n => newTag.appendChild(n))\n\t\t} else {\n\t\t\tnewTag.appendChild(attr.$child)\n\t\t}\n\t}\n\tif (attr.$values) {\n\t\tObject.entries(attr.$values).forEach(([k, v]) => {\n\t\t\tnewTag[k] = v;\n\t\t});\n\t}\n\tObject.entries(attr).filter(([key, values]) => key[0] != \"$\").forEach(([key, value]) => {\n\t\tnewTag.setAttribute(key, value);\n\t});\n\treturn newTag;\n}\nexport async function request(method, url, options = {}) {\n\ttry {\n\t\tvar opts = config.hook.preRequest(method, url, options) || options;\n\t} catch(e) {\n\t\tvar opts = options;\n\t}\n\n\tif (opts.timestamp === true) {\n\t\topts.query = opts.query || {};\n\t\topts.query[\"_timestamp\"] = Date.now();\n\t}\n\n\t// parse url\n\tconst u = new URL(url, location);\n\topts.query = [...u.searchParams.entries()].reduce((obj, [key, value]) => {\n\t\tobj[key] = value\n\t\treturn obj\n\t}, opts.query || {});\n\n\n\n\tu.search = \"\";\n\turl = u.href\n\n\treturn new Promise(function(resolve, reject) {\n\t\tlet req = new XMLHttpRequest();\n\n\t\treq.addEventListener(\"readystatechange\", function(){\n\t\t\tif (req.readyState == 4) {\n\t\t\t\tvar result = {\n\t\t\t\t\tstatusCode: req.status,\n\t\t\t\t\ttext : req.responseText,\n\t\t\t\t};\n\n\t\t\t\tvar contentType = req.getResponseHeader(\"Content-Type\") || \"\";\n\t\t\t\tif(contentType.includes(\"application/json\")) {\n\t\t\t\t\tresult.json = JSON.parse(result.text);\n\t\t\t\t}\n\n\t\t\t\tif (req.status >= 200 && req.status < 300){\n\t\t\t\t\tresolve(result)\n\t\t\t\t} else {\n\t\t\t\t\treject(result);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tif (opts.auth) {\n\t\t\tconsole.debug(\"request with auth\", opts.auth)\n\t\t\t// In Chrome and firefox Auth header not included request(due to security, see https://bugs.chromium.org/p/chromium/issues/detail?id=128323)\n\t\t\t// so forced set header\n\t\t\treq.open(method, resolveParam(url, opts.params) + queryString(opts.query), true, opts.auth.user, opts.auth.password);\n\t\t\treq.setRequestHeader(\"Authorization\", \"Basic \" + btoa(opts.auth.user+\":\"+opts.auth.password));\n\t\t} else {\n\t\t\treq.open(method, resolveParam(url, opts.params) + queryString(opts.query), true);\n\t\t}\n\n\t\t// set default accept\n\t\treq.setRequestHeader(\"Accept\", \"application/json,*/*\");\n\n\t\treq.withCredentials = opts.withCredentials;\n\t\tObject.keys(opts.headers || {}).forEach(function(name){\n\t\t\treq.setRequestHeader(name, opts.headers[name]);\n\t\t});\n\n\t\topts.body = opts.body || opts.data;\n\n\t\tswitch (typeof opts.body) {\n\t\t\tcase \"object\":\n\t\t\t\tif (opts.body instanceof FormData) {\n\t\t\t\t\treq.send(opts.body);\n\t\t\t\t} else {\n\t\t\t\t\treq.setRequestHeader(\"Content-Type\", \"application/json\")\n\t\t\t\t\treq.send(JSON.stringify(opts.body))\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"string\":\n\t\t\t\treq.send(opts.body);\n\t\t\t\tbreak;\n\t\t\tcase \"undefined\":\n\t\t\t\treq.send();\n\t\t\t\tbreak; // just skip\n\t\t\tdefault:\n\t\t\t\treject(\"unknown type: req.body\");\n\t\t\t\tbreak;\n\t\t}\n\t});\n}\nexport async function timeout(ms) {\n\treturn new Promise(function(resolve, reject){\n\t\tsetTimeout(resolve, ms);\n\t});\n}\nexport function defer() {\n\tvar ret = {}\n\tret.promise = new Promise(function(resolve, reject){\n\t\tret.resolve = resolve;\n\t\tret.reject = reject;\n\t});\n\treturn ret;\n}\nexport function prevent(func){\n\treturn function(evt){\n\t\tevt.preventDefault();\n\t\treturn func();\n\t}\n}\nexport function form(form) {\n\tvar fd = new FormData(form)\n\treturn Array.from(fd).reduce((obj, [k, v] )=> {\n\t\tswitch(get(form, `[name=${k}]`).attr(\"type\")) {\n\t\t\tcase \"number\":\n\t\t\t\tobj[k] = v-0;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tobj[k] = v;\n\t\t\t\tbreak;\n\t\t}\n\t\treturn obj;\n\t}, {});\n}\nexport function debounce(func, {timeout = 200} = {}) {\n\tlet timer;\n\n\treturn function(...args) {\n\t\tclearTimeout(timer);\n\t\ttimer = setTimeout(_=> func.apply(this, args), timeout)\n\t}\n}\n\n// for await ( let dt of $.frames()){ /* do something */ }\nexport function frames({fps = 30} = {}) {\n\tvar stop = false;\n\tvar fpsInterval = 1000 / fps;\n\tvar then = Date.now();\n\n\tasync function* f() {\n\t\twhile(true) {\n\t\t\tyield new Promise((resolve, reject) => {\n\t\t\t\tconst animate = () => {\n\t\t\t\t\tvar now = Date.now();\n\t\t\t\t\tvar elapsed = now - then;\n\n\t\t\t\t\tif (elapsed > fpsInterval) {\n\t\t\t\t\t\tthen = now - (elapsed%fpsInterval);\n\n\t\t\t\t\t\tresolve(elapsed - (elapsed%fpsInterval))\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// wait next frame\n\t\t\t\t\t\trequestAnimationFrame(animate)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trequestAnimationFrame(animate)\n\t\t\t});\n\t\t}\n\t}\n\treturn f();\n}\n\nexport function animateFrame(callback, {fps = 30} = {}) {\n\tvar stop = false;\n\tvar fpsInterval = 1000 / fps;\n\tvar then = Date.now();\n\tanimate();\n\n\tfunction animate() {\n\t\tif (stop) {\n\t\t\treturn;\n\t\t}\n\t\trequestAnimationFrame(animate);\n\n\t\tvar now = Date.now();\n\t\tvar elapsed = now - then;\n\n\t\tif (elapsed > fpsInterval) {\n\t\t\tthen = now - (elapsed % fpsInterval);\n\n\t\t\tvar ret = callback(elapsed - (elapsed%fpsInterval));\n\t\t\tif (ret && ret.stop) {\n\t\t\t\tstop = true;\n\t\t\t}\n\t\t}\n\t}\n}\nexport function jq(data, query, value) {\n\tvar keys = query.split(\"\\\\.\").map(str => str.split(\".\")).reduce((p, c) => {\n\t\tif (p.length == 0 ) {\n\t\t\treturn c;\n\t\t}\n\t\tvar last = p.pop();\n\t\tvar first = c.shift();\n\n\t\treturn [].concat(p, [last+\".\"+first], c);\n\t});\n\n\tif (query[0] == \".\") {\n\t\tkeys.shift(); // remove first empty key\n\t}\n\n\ttry {\n\t\tvar visitor = data;\n\t\twhile(keys.length > 1) {\n\t\t\tvisitor = visitor[keys.shift()];\n\t\t}\n\n\t\tif (value !== undefined) {\n\t\t\tvisitor[keys.shift()] = value;\n\t\t\treturn value;\n\t\t} else {\n\t\t\treturn visitor[keys.shift()];\n\t\t}\n\t} catch(e) {\n\t\tthrow new ExtendedError(\"[$.jq] not found\", e);\n\t}\n}\nexport function merge(...args) {\n\treturn args.reduce((target, src={}) => {\n\t\treturn Object.entries(src).reduce((t, [key,value]) => {\n\t\t\tif (value instanceof Array) {\n\t\t\t\treturn {\n\t\t\t\t\t...t,\n\t\t\t\t\t[key]: [...(t[key]||[]), ...value],\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (value instanceof Object) {\n\t\t\t\treturn {\n\t\t\t\t\t...t,\n\t\t\t\t\t[key]: merge(t[key], value)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {...t, [key]:value}\n\t\t}, target)\n\t}, {})\n}\n\nclass ExtendedError extends Error {\n\tconstructor(message, error){\n\t\tsuper(message)\n\n\t\tthis.name = error.name;\n\n\t\tthis.cause = error;\n\t\tlet message_lines = (this.message.match(/\\n/g)||[]).length + 1;\n\t\tthis.stack = this.stack.split('\\n').slice(0, message_lines+1).join('\\n') + '\\n' + error.stack;\n\t}\n}\nexport function wsURL (url){\n\tvar u= new URL(url, document.location)\n\tu.protocol = document.location.protocol.includes(\"https\") ? \"wss:\" : \"ws:\"\n\treturn u;\n}\n\nexport const util = {\n\tfilter: {\n\t\tnotNull: e => e != null,\n\t\tunique: (value, index, self) => self.indexOf(value) === index,\n\t},\n\treduce: {\n\t\tappendChild: function(parent, child) {\n\t\t\tparent.appendChild(child);\n\t\t\treturn parent;\n\t\t},\n\t},\n};\nexport var events = new EventTarget();\n\nfunction resolveParam(url, params) {\n\tif (params == null) {\n\t\treturn url\n\t}\n\treturn url.replace(/:([a-zA-Z0-9]+)/g, function(matched, name){\n\t\tif (params[name]) {\n\t\t\treturn params[name];\n\t\t}\n\t\tconsole.warn(`[$.reqeust] find param pattern '${name}', but not provided`);\n\t\treturn matched;\n\t});\n}\n\nfunction queryString(obj) {\n\tif (obj == null) {\n\t\treturn \"\";\n\t}\n\treturn \"?\" + Object.keys(obj).map(function(key) {\n\t\treturn key + \"=\" + encodeURIComponent(obj[key]);\n\t}).join(\"&\");\n}\n\nObject.keyValues= function(obj, f) {\n\treturn Object.entries(obj).map(([key, value]) => {\n\t\treturn {key, value};\n\t});\n}\nObject.map = function(obj, f) {\n\treturn Object.entries(obj).map(([key, value]) => f({key,value})).reduce((obj, {key,value}={}) => (key?{ ...obj, [key]: value}:obj), {});\n}\nObject.same = function(x, y) {\n\tif (x === null || x === undefined || y === null || y === undefined) {\n\t\treturn x === y;\n\t}\n\tif (x.constructor !== y.constructor) {\n\t\treturn false;\n\t}\n\tif (x instanceof RegExp || x instanceof Function) {\n\t\treturn x === y;\n\t}\n\tif (x === y || x.valueOf() === y.valueOf()) {\n\t\treturn true;\n\t}\n\tif (Array.isArray(x) && x.length !== y.length) {\n\t\treturn false;\n\t}\n\n\t// if they are dates, they must had equal valueOf\n\tif (x instanceof Date) {\n\t\treturn false;\n\t}\n\n\tif (!(x instanceof Object)) {\n\t\treturn false;\n\t}\n\tif (!(y instanceof Object)) {\n\t\treturn false;\n\t}\n\tlet xk = Object.keys(x);\n\tlet yk = Object.keys(y);\n\n\tif (xk.length != yk.length) {\n\t\treturn false\n\t}\n\tif (!xk.every(i => yk.indexOf(i) !== -1)) {\n\t\treturn false\n\t}\n\n\t// recursive object equality check\n\treturn xk.every(i => Object.same(x[i], y[i]))\n}\n\nconst sig = \"__bm.js_inserted__\"\nfunction extend(TargetClass, proto){\n\tif (TargetClass.hasOwnProperty(sig)) {\n\t\tconsole.trace(\"already installed\")\n\t\treturn // already inserted\n\t}\n\n\tObject.keys(proto).forEach(function(name) {\n\t\tif (name in TargetClass.prototype) {\n\t\t\tconsole.warn(`cannot extend prototype: '${name}' already exist`)\n\t\t\treturn; // skip\n\t\t}\n\t\tTargetClass.prototype[name] = proto[name];\n\t});\n\n\tTargetClass[sig] = true\n}\nextend(Node, {\n\tappendTo: function(target) {\n\t\ttarget.appendChild(this);\n\t\treturn this;\n\t},\n\tclear : function(filter) {\n\t\tvar f = filter || function(e) { return true };\n\t\tthis.childNodes.filter(f).forEach((e) => this.removeChild(e))\n\t\treturn this;\n\t},\n});\nextend(Element, {\n\tattr: function(name, value){\n\t\tif (value === null) {\n\t\t\tthis.removeAttribute(name);\n\t\t\treturn\n\t\t}\n\t\tif (value !== undefined) {\n\n\t\t\tthis.setAttribute(name, value)\n\t\t\treturn value;\n\t\t} else {\n\t\t\treturn this.getAttribute(name)\n\t\t}\n\t},\n})\n\nextend(EventTarget, {\n\ton: function(name, handler, opt) {\n\t\tthis.addEventListener(name, handler, opt);\n\t\treturn this;\n\t},\n\toff: function(name, handler, opt) {\n\t\tthis.removeEventListener(name, handler, opt)\n\t\treturn this;\n\t},\n\tfireEvent: function(name, detail) {\n\t\tvar evt = new CustomEvent(name, {detail: detail});\n\t\tthis.dispatchEvent(evt);\n\t\treturn this;\n\t}\n});\n\nextend(NodeList, {\n\tmap: Array.prototype.map,\n\tfilter: Array.prototype.filter,\n\t//\"forEach\": Array.prototype.forEach,\n});\nextend(HTMLCollection, {\n\tmap: Array.prototype.map,\n\tfilter: Array.prototype.filter,\n\tforEach: Array.prototype.forEach,\n});\n\nextend(Array, {\n\tunique: function(isSame) {\n\t\tif (!isSame) {\n\t\t\treturn [... new Set(this)];\n\t\t}\n\t\treturn this.filter((v, i) => this.first(v, isSame) == i);\n\t},\n\tpromise: function() {\n\t\tvar arr = this;\n\t\treturn {\n\t\t\tall: () => Promise.all(arr),\n\t\t\tany: () => Promise.any(arr),\n\t\t\trace: () => Promise.race(arr),\n\t\t}\n\t},\n\tfirst: function(v, isSame = ((a,b)=>a==b)) {\n\t\tfor (let i = 0; i < this.length; i ++){\n\t\t\tif(isSame(this[i], v)) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t},\n});\n\n\nexport class CustomElement extends HTMLElement {\n\t// private\n\t#handler = {}\n\n\tconstructor({enableShadow = true} = {}) {\n\t\tsuper();\n\n\t\tif (enableShadow) {\n\t\t\t//this[\"--shadow\"] = this.attachShadow({mode: 'open'})\n\t\t\tthis.attachShadow({mode: 'open'})\n\t\t}\n\t}\n\t// syntactic sugar\n\tattributeChangedCallback(name, oldValue, newValue) {\n\t\t// to use set follow to custom elements\n\t\t//\n\t\t//\tstatic get observedAttributes() {\n\t\t//\t\treturn [\"cluster\"];\n\t\t//\t}\n\t\tthis.fireEvent(\"attribute-changed\", {\n\t\t\tname: name,\n\t\t\told: oldValue,\n\t\t\tnew: newValue,\n\t\t});\n\t\tthis.onAttributeChanged(name, oldValue, newValue);\n\t}\n\tonAttributeChanged() {\n\t\tthis.render && this.render();\n\t}\n\tconnectedCallback() {\n\t\tthis.render && this.render();\n\t\tthis.onConnected && this.onConnected();\n\t\tthis.fireEvent(\"connected\")\n\t}\n\tdisconnectedCallback() {\n\t\tthis.onDisconnected && this.onDisconnected();\n\t\tthis.fireEvent(\"disconnected\")\n\t}\n\tget shadow() {\n\t\treturn this.shadowRoot;\n\t}\n\thandler(h) {\n\t\tvar name = h instanceof Function ? h.name : h;\n\t\tvar f = h instanceof Function ? h : this[h];\n\n\t\tif (!this.#handler[name]) {\n\t\t\tthis.#handler[name] = evt => f.call(this, evt.detail);\n\t\t}\n\t\treturn this.#handler[name];\n\t}\n}\n\nexport class AwaitEventTarget {\n\tconstructor() {\n\t\tthis.handlers = new Map();\n\t}\n\n\t// method\n\taddEventListener(eventName, handler) {\n\t\tif (!this.handlers.has(eventName)) {\n\t\t\tthis.handlers.set(eventName, new Set());\n\t\t}\n\t\tthis.handlers.get(eventName).add(handler);\n\t}\n\tremoveEventListener(eventName, handler) {\n\t\tif (!this.handlers.has(eventName)) {\n\t\t\treturn;\n\t\t}\n\t\tthis.handlers.get(eventName).delete(handler);\n\t}\n\tdispatchEvent(event) {\n\t\tlet name = event.type;\n\t\tif (!this.handlers.has(name)) {\n\t\t\treturn;\n\t\t}\n\t\treturn [...this.handlers.get(name)].map(handler => {\n\t\t\treturn handler(event);\n\t\t}).promise().all();\n\t}\n\n\t// syntactic sugar\n\ton(eventName, handler) {\n\t\tthis.addEventListener(eventName, handler)\n\t}\n\toff(eventName, handler) {\n\t\tthis.removeEventListener(eventName, handler)\n\t}\n\tfireEvent(name, detail) {\n\t\tvar evt = new CustomEvent(name, {detail: detail});\n\t\t// name will be evt.type\n\t\treturn this.dispatchEvent(evt);\n\t}\n}\n\nexport class AwaitQueue {\n\tconstructor() {\n\t\tthis.queue = [];\n\t\tthis.resolve = null;\n\t}\n\t[Symbol.iterator]() {\n\t\tlet next = () => {\n\t\t\tif (this.queue.length > 0) {\n\t\t\t\treturn {\n\t\t\t\t\tvalue: this.queue.shift(),\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tvalue: () => new Promise((resolve) => {\n\t\t\t\t\tthis.resolve = resolve;\n\t\t\t\t}),\n\t\t\t};\n\t\t}\n\t\treturn { next }\n\t}\n\tadd(f) {\n\t\tif (!(f instanceof Function)) {\n\t\t\tthrow Error(\"must put function\");\n\t\t}\n\t\tif(this.resolve) {\n\t\t\tthis.resolve(f());\n\t\t\tthis.resolve = null;\n\t\t\treturn\n\t\t}\n\t\tthis.queue.push(f)\n\t}\n\tremove(f) {\n\t\tthis.queue = this.queue.filter(job => job != f);\n\t}\n\tget length() {\n\t\treturn this.queue.length;\n\t}\n}\n\nexport function logger(opt){\n\treturn new Logger(opt);\n}\nclass Logger {\n\tconstructor({show, name} = {}) {\n\t\tthis.show = show;\n\t\tthis.name = name;\n\t}\n\tdebug(message) {\n\t\tif(this.show) return;\n\t\tconsole.debug.apply(console, arguments);\n\t}\n\tinfo(message) {\n\t\tif(this.show) return;\n\t\tconsole.info.apply(console, arguments);\n\t}\n\twarn(message) {\n\t\tif(this.show) return;\n\t\tconsole.warn.apply(console, arguments);\n\t}\n\terror(message) {\n\t\tif(this.show) return;\n\t\tconsole.error.apply(console, arguments);\n\t}\n}\n", "import * as $ from \"../../bm.module.js\";\nimport {html, render} from 'lit-html';\nimport {css} from \"../common.js\";\n\nvar tmpl = (elem) => html`\n\t\n\t${elem.attr(\"text\")}\n`;\n\nclass Alert extends $.CustomElement {\n\tconstructor() {\n\t\tsuper();\n\t}\n\tstatic get observedAttributes() {\n\t\treturn [\"text\"];\n\t}\n\tasync render() {\n\t\trender(tmpl(this), this.shadow);\n\t}\n}\ncustomElements.define(\"c-alert\", Alert);\n", "export const css = `\n/* prevent FOUC */\n*:not(:defined) {\n\tdisplay:none;\n}\n:host {\n\tdisplay: block;\n}\n`\n", "import * as $ from \"../../bm.module.js\";\nimport {html, render} from 'lit-html';\n\nvar tmpl = (elem) => html`\n\t\n\t\n`;\n\nclass Breadcrumbs extends $.CustomElement {\n\tconstructor() {\n\t\tsuper();\n\t}\n\tasync render() {\n\t\trender(tmpl(this), this.shadow);\n\t}\n\t// attribute\n\tget breadcrumbs() {\n\t\tconst arr = location.pathname.split(\"/\").filter(e => e.length);\n\n\t\treturn arr.map((item, index) => {\n\t\t\treturn {\n\t\t\t\tname: item,\n\t\t\t\tpath: \"/\" + arr.slice(0, index+1).join(\"/\"),\n\t\t\t}\n\t\t});\n\t}\n}\ncustomElements.define(\"c-breadcrumbs\", Breadcrumbs);\n\n", "import * as $ from \"../../bm.module.js\";\nimport {html, render} from 'lit-html';\nimport {css} from \"../common.js\";\n\nvar tmpl = (elem) => html`\n\t\n\t ${elem.attr(\"title\") || \"extends\"}