summaryrefslogtreecommitdiff
path: root/_www/public/build/bundle.css.map
diff options
context:
space:
mode:
Diffstat (limited to '_www/public/build/bundle.css.map')
-rw-r--r--_www/public/build/bundle.css.map32
1 files changed, 0 insertions, 32 deletions
diff --git a/_www/public/build/bundle.css.map b/_www/public/build/bundle.css.map
deleted file mode 100644
index 59cba63..0000000
--- a/_www/public/build/bundle.css.map
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "version": 3,
- "file": "bundle.css",
- "sources": [
- "../../InputIPPort.svelte",
- "../../InputNumber.svelte",
- "../../LabelHint.svelte",
- "../../Notif.svelte",
- "../../NotifItem.svelte",
- "../../App.svelte",
- "../../Dashboard.svelte",
- "../../Environment.svelte",
- "../../HostsBlock.svelte",
- "../../HostsDir.svelte",
- "../../MasterDir.svelte"
- ],
- "sourcesContent": [
- "<script>\n\texport let value = \"\";\n\tlet isInvalid = false;\n\tlet error = \"\";\n\n\tfunction onBlur() {\n\t\tif (value === \"\") {\n\t\t\tisInvalid = false;\n\t\t\terror = \"\";\n\t\t\treturn;\n\t\t}\n\t\tconst ipport = value.split(\":\");\n\t\tif (ipport.length !== 2) {\n\t\t\tisInvalid = true;\n\t\t\terror = \"missing port number\";\n\t\t\treturn;\n\t\t}\n\t\tconst ip = ipport[0];\n\t\tconst port = parseInt(ipport[1]);\n\t\tif (isNaN(port) || port <= 0 || port >= 65535) {\n\t\t\tisInvalid = true;\n\t\t\terror = \"invalid port number\";\n\t\t\treturn;\n\t\t}\n\t\tisInvalid = false;\n\t\tvalue = ip +\":\"+ port;\n\t}\n</script>\n\n<style>\n\t.wui-input-ipport {\n\t\tdisplay: inline-block;\n\t\twidth: 100%;\n\t}\n\t.wui-input-ipport input {\n\t\twidth: 100%;\n\t}\n\t.invalid {\n\t\tcolor: red;\n\t}\n\tdiv.invalid {\n\t\tfont-size: 12px;\n\t}\n</style>\n\n<div class=\"wui-input-ipport\">\n\t<input\n\t\ttype=\"text\"\n\t\tbind:value={value}\n\t\ton:blur={onBlur}\n\t\tclass:invalid={isInvalid}\n\t\tplaceholder=\"127.0.0.1:8080\"\n\t>\n\t{#if isInvalid}\n\t<div class=\"invalid\">{error}</div>\n\t{/if}\n</div>\n",
- "<script>\n\texport let min;\n\texport let max;\n\texport let value = 0;\n\texport let unit;\n\n\tfunction onBlur() {\n\t\tvalue = +value\n\t\tif (isNaN(value)) {\n\t\t\tvalue = max\n\t\t} else if (value < min) {\n\t\t\tvalue = min\n\t\t} else if (value > max) {\n\t\t\tvalue = max\n\t\t}\n\t}\n</script>\n\n<style>\n\t.wui-input-number {\n\t\twidth: 100%;\n\t}\n\t.wui-input-number input {\n\t\tdisplay: inline-block;\n\t\twidth: 70%;\n\t}\n\t.wui-input-number .suffix {\n\t\twidth: 30%;\n\t}\n</style>\n\n<div class=\"wui-input-number\">\n\t<input type=\"number\" on:blur={onBlur} bind:value={value}>\n\t{#if unit !== ''}\n\t\t<span class=\"suffix\">\n\t\t\t{unit}\n\t\t</span>\n\t{/if}\n</div>\n",
- "<script>\n\texport let title;\n\texport let info;\n\texport let title_width = \"300px\";\n\tlet showInfo = false;\n</script>\n\n<style>\n\t.label-hint {\n\t\tdisplay: inline-flex;\n\t\tmargin-top: 1em;\n\t\twidth: 100%;\n\t}\n\t.title {\n\t\tmargin-bottom: 4px;\n\t}\n\t.title {\n\t\tdisplay: inline-block;\n\t}\n\t.toggle {\n\t\tborder-radius: 50%;\n\t\tborder: 1px solid grey;\n\t\tcursor: pointer;\n\t\tdisplay: inline-block;\n\t\tfont-size: 12px;\n\t\theight: 14px;\n\t\tline-height: 14px;\n\t\tpadding: 2px;\n\t\ttext-align: center;\n\t\twidth: 14px;\n\t}\n\t.info {\n\t\tbackground-color: #eee;\n\t\tmargin: 8px 0px;\n\t\tpadding: 1em;\n\t}\n\t@media (max-width: 720px) {\n\t\t.label-hint {\n\t\t\tdisplay: block;\n\t\t}\n\t}\n</style>\n\n<label class=\"label-hint\">\n\t<span class=\"title\" style=\"width:{title_width};\">\n\t\t{title}\n\t\t<span class=\"toggle\" on:click={() => showInfo = !showInfo}>\n\t\t\t?\n\t\t</span>\n\t</span>\n\n\t<slot>\n\t</slot>\n\n</label>\n\n{#if showInfo}\n<div class=\"info\">\n\t{@html info}\n</div>\n{/if}\n",
- "<script context=\"module\">\n\timport { messages } from \"./Notif.store.js\"\n\timport NotifItem from \"./NotifItem.svelte\"\n\n\texport const WuiPushNotif = {\n\t\tInfo: function(text) {\n\t\t\tconst msg = {\n\t\t\t\ttext: text,\n\t\t\t}\n\t\t\tmessages.update(msgs => msgs = [...msgs, msg])\n\t\t},\n\t\tError: function(text) {\n\t\t\tconst msg = {\n\t\t\t\ttext: text,\n\t\t\t\tkind: \"error\",\n\t\t\t}\n\t\t\tmessages.update(msgs => msgs = [...msgs, msg])\n\t\t}\n\t}\n</script>\n<script>\n\texport let timeout = 5000;\n</script>\n\n<style>\n\t.wui-notif {\n\t\tposition: fixed;\n\t\ttop: 5px;\n\t\tleft: calc((100% - 400px)/2);\n\t\twidth: 400px;\n\t}\n\t@media (max-width: 500px) {\n\t\t.wui-notif {\n\t\t\tleft: 1em;\n\t\t\twidth: calc(100% - 2em);\n\t\t}\n\t}\n</style>\n\n<div class=\"wui-notif\">\n\t{#each $messages as msg (msg)}\n\t<NotifItem text={msg.text} kind=\"{msg.kind}\" {timeout}/>\n\t{/each}\n</div>\n",
- "<script>\n\timport { onMount } from 'svelte'\n\timport { fade } from 'svelte/transition'\n\timport { messages } from \"./Notif.store.js\"\n\n\texport let text = \"\"\n\texport let kind = \"\"\n\texport let timeout = 5000\n\n\tonMount(() => {\n\t\tlet timerID = setTimeout(()=> {\n\t\t\tmessages.update(msgs => {\n\t\t\t\tmsgs.splice(0, 1);\n\t\t\t\tmsgs = msgs\n\t\t\t\treturn msgs\n\t\t\t})\n\t\t}, timeout)\n\t})\n</script>\n\n<style>\n\t.wui-notif-item {\n\t\tbackground-color: white;\n\t\tborder: 1px solid black;\n\t\tbox-shadow: 3px 3px;\n\t\tpadding: 1em;\n\t\tmargin-bottom: 1em;\n\t\tz-index: 1000;\n\t}\n\t.wui-notif-item.error {\n\t\tborder: 1px solid red;\n\t\tbox-shadow: 3px 3px red;\n\t}\n</style>\n\n<div transition:fade class=\"wui-notif-item {kind}\">\n\t{text}\n</div>\n",
- "<script>\n\timport { onMount } from 'svelte';\n\timport { WuiNotif, WuiPushNotif } from 'wui.svelte';\n\n\timport { apiEnvironment, environment, nanoSeconds, setEnvironment } from './environment.js';\n\timport Dashboard from './Dashboard.svelte';\n\timport Environment from './Environment.svelte';\n\timport HostsBlock from './HostsBlock.svelte';\n\timport HostsDir from './HostsDir.svelte';\n\timport MasterDir from './MasterDir.svelte';\n\n\tconst stateEnvironment = \"environment\";\n\tconst stateHostsBlock = \"hosts_block\";\n\tconst stateHostsDir = \"hosts_d\";\n\tconst stateMasterDir = \"master_d\";\n\n\tlet state;\n\tlet env = {\n\t\tNameServers: [],\n\t\tHostsBlocks: [],\n\t\tHostsFiles: {},\n\t};\n\n\tonMount(async () => {\n\t\tconst res = await fetch(apiEnvironment);\n\t\tif (res.status >= 400) {\n\t\t\tWuiPushNotif.Error(\"ERROR: {apiEnvironment}: \",\n\t\t\t\tres.status, res.statusText);\n\t\t\treturn;\n\t\t}\n\n\t\tsetEnvironment(await res.json());\n \t\tstate = window.location.hash.slice(1);\n\t});\n</script>\n\n<style>\n\tdiv.main {\n\t\tmargin: 0 auto;\n\t\twidth: 800px;\n\t\tpadding: 0px 1em;\n\t}\n\tnav.menu {\n\t\tcolor: #ff3e00;\n\t\ttext-transform: uppercase;\n\t\tfont-weight: 100;\n\t\tmargin-bottom: 2em;\n\t}\n\t.active {\n\t\tpadding-bottom: 4px;\n\t\tborder-bottom: 4px solid #ff3e00;\n\t}\n\t@media (max-width: 900px) {\n\t\tdiv.main {\n\t\t\twidth: calc(100% - 2em);\n\t\t}\n\t}\n</style>\n\n<WuiNotif timeout=3000 />\n\n<div class=\"main\">\n\t<nav class=\"menu\">\n\t\t<a\n\t\t\thref=\"#home\"\n\t\t\ton:click={()=>state=\"\"}\n\t\t\tclass:active=\"{state===''||state==='home'}\"\n\t\t>\n\t\t\trescached\n\t\t</a>\n\t\t/\n\t\t<a\n\t\t\thref=\"#environment\"\n\t\t\ton:click={()=>state=stateEnvironment}\n\t\t\tclass:active=\"{state===stateEnvironment}\"\n\t\t>\n\t\t\tEnvironment\n\t\t</a>\n\t\t/\n\t\t<a\n\t\t\thref=\"#{stateHostsBlock}\"\n\t\t\ton:click={()=>state=stateHostsBlock}\n\t\t\tclass:active=\"{state===stateHostsBlock}\"\n\t\t>\n\t\t\tHosts blocks\n\t\t</a>\n\t\t/\n\t\t<a\n\t\t\thref=\"#{stateHostsDir}\"\n\t\t\ton:click={()=>state=stateHostsDir}\n\t\t\tclass:active=\"{state === stateHostsDir}\"\n\t\t>\n\t\t\thosts.d\n\t\t</a>\n\t\t/\n\t\t<a\n\t\t\thref=\"#{stateMasterDir}\"\n\t\t\ton:click={()=>state=stateMasterDir}\n\t\t\tclass:active=\"{state === stateMasterDir}\"\n\t\t>\n\t\t\tmaster.d\n\t\t</a>\n\t</nav>\n\n\t{#if state === stateEnvironment}\n\t\t<Environment/>\n\t{:else if state === stateHostsBlock}\n\t\t<HostsBlock/>\n\t{:else if state === stateHostsDir}\n\t\t<HostsDir/>\n\t{:else if state === stateMasterDir}\n\t\t<MasterDir/>\n\t{:else}\n\t\t<Dashboard/>\n\t{/if}\n</div>\n",
- "<script>\n\timport {WuiPushNotif} from 'wui.svelte';\n\timport {getRRTypeName} from './common.js';\n\n\tconst apiCaches = \"/api/caches\";\n\n\tlet query = \"\";\n\tlet listMsg = [];\n\n\tasync function handleSearch() {\n\t\tconst res = await fetch(apiCaches+\"?query=\"+ query)\n\n\t\tif (res.status >= 400) {\n\t\t\tconst resbody = await res.json()\n\t\t\tWuiPushNotif.Error(\"ERROR: \"+ resbody.message)\n\t\t\treturn;\n\t\t}\n\n\t\tlistMsg = await res.json()\n\t}\n\n\tasync function handleRemoveFromCaches(name) {\n\t\tconst res = await fetch(apiCaches+\"?name=\"+ name, {\n\t\t\tmethod: \"DELETE\",\n\t\t})\n\n\t\tif (res.status >= 400) {\n\t\t\tconst resbody = await res.json()\n\t\t\tWuiPushNotif.Error(\"ERROR: \"+ resbody.message)\n\t\t\treturn;\n\t\t}\n\n\t\tfor (let x = 0; x < listMsg.length; x++) {\n\t\t\tif (listMsg[x].Question.Name === name) {\n\t\t\t\tlistMsg.splice(x, 1)\n\t\t\t\tlistMsg = listMsg\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tconst msg = await res.json()\n\n\t\tWuiPushNotif.Info(msg.message)\n\t}\n</script>\n\n<style>\n\t.message {\n\t\tpadding: 1em 0px;\n\t\tborder-bottom: 1px solid silver;\n\t}\n\t.rr {\n\t\tmargin-left: 1em;\n\t\twidth: 100%;\n\t}\n\t.rr.header {\n\t\tfont-weight: bold;\n\t}\n\t.rr span {\n\t\tdisplay: inline-block;\n\t}\n\t.kind {\n\t\twidth: 9em;\n\t}\n\t.type {\n\t\twidth: 5em;\n\t}\n\t.ttl {\n\t\twidth: 6em;\n\t}\n\t.value {\n\t\tword-wrap: anywhere;\n\t\twidth: calc(100% - 24em);\n\t}\n</style>\n\n<div class=\"dashboard\">\n\t<div class=\"search\">\n\t\tCaches:\n\t\t<input bind:value={query}>\n\t\t<button on:click={handleSearch}>\n\t\t\tSearch\n\t\t</button>\n\t</div>\n\t{#each listMsg as msg (msg)}\n\t\t<div class=\"message\">\n\t\t\t<div class=\"qname\">\n\t\t\t\t{msg.Question.Name}\n\n\t\t\t\t<button\n\t\t\t\t\tclass=\"b-remove\"\n\t\t\t\t\ton:click={handleRemoveFromCaches(msg.Question.Name)}\n\t\t\t\t>\n\t\t\t\t\tRemove from caches\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<div class=\"rr header\">\n\t\t\t\t<span class=\"kind\"> </span>\n\t\t\t\t<span class=\"type\"> Type </span>\n\t\t\t\t<span class=\"ttl\"> TTL </span>\n\t\t\t\t<span class=\"value\"> Value </span>\n\t\t\t</div>\n\n\t\t\t{#if msg.Answer !== null && msg.Answer.length > 0}\n\t\t\t\t{#each msg.Answer as rr}\n\t\t\t\t\t<div class=\"rr\">\n\t\t\t\t\t\t<span class=\"kind\"> Answer </span>\n\t\t\t\t\t\t<span class=\"type\"> {getRRTypeName(rr.Type)} </span>\n\t\t\t\t\t\t<span class=\"ttl\"> {rr.TTL} </span>\n\t\t\t\t\t\t<span class=\"value\"> {JSON.stringify(rr.Value, null, 2)} </span>\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\t\t\t{/if}\n\t\t\t{#if msg.Authority !== null && msg.Authority.length > 0}\n\t\t\t\t{#each msg.Authority as rr}\n\t\t\t\t\t<div class=\"rr\">\n\t\t\t\t\t\t<span class=\"kind\"> Authority </span>\n\t\t\t\t\t\t<span class=\"type\"> {getRRTypeName(rr.Type)} </span>\n\t\t\t\t\t\t<span class=\"ttl\"> {rr.TTL} </span>\n\t\t\t\t\t\t<span class=\"value\"> {JSON.stringify(rr.Value, null, 2)} </span>\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\t\t\t{/if}\n\t\t\t{#if msg.Additional !== null && msg.Additional.length > 0}\n\t\t\t\t{#each msg.Additional as rr}\n\t\t\t\t\t<div class=\"rr\">\n\t\t\t\t\t\t<span class=\"kind\"> Additional </span>\n\t\t\t\t\t\t<span class=\"type\"> {getRRTypeName(rr.Type)} </span>\n\t\t\t\t\t\t<span class=\"ttl\"> {rr.TTL} </span>\n\t\t\t\t\t\t<span class=\"value\"> {JSON.stringify(rr.Value, null, 2)} </span>\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\t\t\t{/if}\n\t\t</div>\n\t{/each}\n</div>\n",
- "<script>\n\timport { onDestroy } from 'svelte';\n\n\timport { apiEnvironment, environment, nanoSeconds } from './environment.js';\n\timport { WuiPushNotif } from \"wui.svelte\";\n\timport { WuiLabelHint, WuiInputNumber, WuiInputIPPort } from \"wui.svelte\";\n\n\tlet env = {\n\t\tNameServers: [],\n\t\tHostsBlocks: [],\n\t\tHostsFiles: {},\n\t};\n\n\tconst envUnsubscribe = environment.subscribe(value => {\n\t\tenv = value;\n\t});\n\n\tonDestroy(envUnsubscribe);\n\n\tconst defTitleWidth = \"300px\";\n\n\tfunction addNameServer() {\n\t\tenv.NameServers = [...env.NameServers, '']\n\t}\n\n\tfunction deleteNameServer(ns) {\n\t\tfor (let x = 0; x < env.NameServers.length; x++) {\n\t\t\tif (env.NameServers[x] === ns) {\n\t\t\t\tenv.NameServers.splice(x, 1);\n\t\t\t\tenv.NameServers = env.NameServers;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tasync function updateEnvironment() {\n\t\tlet got = {};\n\n\t\tObject.assign(got, env)\n\t\tenvironment.set(env)\n\n\t\tgot.PruneDelay = got.PruneDelay * nanoSeconds;\n\t\tgot.PruneThreshold = got.PruneThreshold * nanoSeconds;\n\n\t\tconst res = await fetch(apiEnvironment, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(got),\n\t\t});\n\n\t\tif (res.status >= 400) {\n\t\t\tconst resbody = await res.json()\n\t\t\tWuiPushNotif.Error(\"ERROR: \", resbody.message)\n\t\t\treturn;\n\t\t}\n\n\t\tWuiPushNotif.Info(\"The environment succesfully updated ...\")\n\t}\n</script>\n\n<style>\n\tinput {\n\t\twidth: 100%;\n\t}\n\t.input-deletable {\n\t\twidth: 100%;\n\t}\n\t.input-deletable > input {\n\t\tmax-width: calc(100% - 100px);\n\t}\n\t.input-deletable > button {\n\t\twidth: 80px;\n\t}\n\t.input-checkbox {\n\t\twidth: 100%;\n\t}\n\t.input-checkbox input[type=\"checkbox\"] {\n\t\twidth: auto;\n\t}\n\t.section-bottom {\n\t\tmargin: 2em 0px 0px 0px;\n\t\tpadding: 1em;\n\t\tborder-top: 1px solid black;\n\t}\n</style>\n\n<div class=\"environment\">\n<p>\nThis page allow you to change the rescached environment.\nUpon save, the rescached service will be restarted.\n</p>\n\n<h3>rescached</h3>\n<div>\n\t<WuiLabelHint\n\t\ttitle=\"System resolv.conf\"\n\t\ttitle_width=\"{defTitleWidth}\"\n\t\tinfo=\"A path to dynamically generated resolv.conf(5) by\nresolvconf(8). If set, the nameserver values in referenced file will\nreplace 'parent' value and 'parent' will become a fallback in\ncase the referenced file being deleted or can not be parsed.\"\n\t>\n\t\t<input\n\t\t\tbind:value={env.FileResolvConf}\n\t\t/>\n\t</WuiLabelHint>\n\n\t<WuiLabelHint\n\t\ttitle=\"Debug level\"\n\t\ttitle_width=\"{defTitleWidth}\"\n\t\tinfo=\"This option only used for debugging program or if user\nwant to monitor what kind of traffic goes in and out of rescached.\"\n\t>\n\t\t<WuiInputNumber\n\t\t\tmin=0\n\t\t\tmax=3\n\t\t\tbind:value={env.Debug}\n\t\t\tunit=\"\"\n\t\t/>\n\t</WuiLabelHint>\n</div>\n\n<h3>DNS server</h3>\n<div>\n\t<WuiLabelHint\n\t\ttitle=\"Parent name servers\"\n\t\ttitle_width=\"{defTitleWidth}\"\n\t\tinfo=\"List of parent DNS servers.\"\n\t>\n\t</WuiLabelHint>\n\n\t{#each env.NameServers as ns}\n\t<div class=\"input-deletable\">\n\t\t<input bind:value={ns}>\n\t\t<button on:click={deleteNameServer(ns)}>\n\t\t\tDelete\n\t\t</button>\n\t</div>\n\t{/each}\n\n\t<button\n\t\ton:click={addNameServer}\n\t>\n\t\tAdd\n\t</button>\n\n\t<WuiLabelHint\n\t\ttitle=\"Listen address\"\n\t\ttitle_width=\"{defTitleWidth}\"\n\t\tinfo=\"Address in local network where rescached will\nlistening for query from client through UDP and TCP.\n<br/>\nIf you want rescached to serve a query from another host in your local\nnetwork, change this value to <tt>0.0.0.0:53</tt>.\"\n\t>\n\t\t<WuiInputIPPort\n\t\t\tbind:value={env.ListenAddress}\n\t\t/>\n\t</WuiLabelHint>\n\n\t<WuiLabelHint\n\t\ttitle=\"HTTP listen port\"\n\t\ttitle_width=\"{defTitleWidth}\"\n\t\tinfo=\"Port to serve DNS over HTTP\"\n\t>\n\t\t<WuiInputNumber\n\t\t\tmin=0\n\t\t\tmax=65535\n\t\t\tbind:value={env.HTTPPort}\n\t\t\tunit=\"\"\n\t\t/>\n\t</WuiLabelHint>\n\n\t<WuiLabelHint\n\t\ttitle=\"TLS listen port\"\n\t\ttitle_width=\"{defTitleWidth}\"\n\t\tinfo=\"Port to listen for DNS over TLS\"\n\t>\n\t\t<WuiInputNumber\n\t\t\tmin=0\n\t\t\tmax=65535\n\t\t\tbind:value={env.TLSPort}\n\t\t\tunit=\"\"\n\t\t/>\n\t</WuiLabelHint>\n\n\t<WuiLabelHint\n\t\ttitle=\"TLS certificate\"\n\t\ttitle_width=\"{defTitleWidth}\"\n\t\tinfo=\"Path to certificate file to serve DNS over TLS and\nHTTPS\">\n\t\t<input\n\t\t\tplaceholder=\"/path/to/certificate\"\n\t\t\tbind:value={env.TLSCertFile}\n\t\t/>\n\t</WuiLabelHint>\n\n\t<WuiLabelHint\n\t\ttitle=\"TLS private key\"\n\t\ttitle_width=\"{defTitleWidth}\"\n\t\tinfo=\"Path to certificate private key file to serve DNS over TLS and\nHTTPS.\"\n\t>\n\t\t<input\n\t\t\tplaceholder=\"/path/to/certificate/private.key\"\n\t\t\tbind:value={env.TLSPrivateKey}\n\t\t/>\n\t</WuiLabelHint>\n\n\t<WuiLabelHint\n\t\ttitle=\"TLS allow insecure\"\n\t\ttitle_width=\"{defTitleWidth}\"\n\t\tinfo=\"If its true, allow serving DoH and DoT with self signed\ncertificate.\"\n\t>\n\t\t<div class=\"input-checkbox\">\n\t\t\t<input\n\t\t\t\ttype=checkbox\n\t\t\t\tbind:checked={env.TLSAllowInsecure}\n\t\t\t>\n\t\t\t<span class=\"suffix\">\n\t\t\t\tYes\n\t\t\t</span>\n\t\t</div>\n\t</WuiLabelHint>\n\n\t<WuiLabelHint\n\t\ttitle=\"DoH behind proxy\"\n\t\ttitle_width=\"{defTitleWidth}\"\n\t\tinfo=\"If its true, serve DNS over HTTP only, even if\ncertificate files is defined.\nThis allow serving DNS request forwarded by another proxy server.\"\n\t>\n\t\t<div class=\"input-checkbox\">\n\t\t\t<input\n\t\t\t\ttype=checkbox\n\t\t\t\tbind:checked={env.DoHBehindProxy}\n\t\t\t>\n\t\t\t<span class=\"suffix\">\n\t\t\t\tYes\n\t\t\t</span>\n\t\t</div>\n\t</WuiLabelHint>\n\n\t<WuiLabelHint\n\t\ttitle=\"Prune delay\"\n\t\ttitle_width=\"{defTitleWidth}\"\n\t\tinfo=\"Delay for pruning caches.\nEvery N seconds, rescached will traverse all caches and remove response that\nhas not been accessed less than cache.prune_threshold.\nIts value must be equal or greater than 1 hour (3600 seconds).\n\"\n\t>\n\t\t<WuiInputNumber\n\t\t\tmin=3600\n\t\t\tmax=36000\n\t\t\tbind:value={env.PruneDelay}\n\t\t\tunit=\"seconds\"\n\t\t/>\n\t</WuiLabelHint>\n\n\t<WuiLabelHint\n\t\ttitle=\"Prune threshold\"\n\t\ttitle_width=\"{defTitleWidth}\"\n\t\tinfo=\"The duration when the cache will be considered expired.\nIts value must be negative and greater or equal than -1 hour (-3600 seconds).\"\n\t>\n\t\t<WuiInputNumber\n\t\t\tmin=-36000\n\t\t\tmax=-3600\n\t\t\tbind:value={env.PruneThreshold}\n\t\t\tunit=\"seconds\"\n\t\t/>\n\t</WuiLabelHint>\n</div>\n\n\t<div class=\"section-bottom\">\n\t\t<div>\n\t\t\t<button on:click={updateEnvironment}>\n\t\t\t\tSave\n\t\t\t</button>\n\t\t</div>\n\t</div>\n</div>\n",
- "<script>\n\timport { onDestroy } from 'svelte';\n\timport { WuiPushNotif } from 'wui.svelte';\n\timport { environment, nanoSeconds, setEnvironment } from './environment.js';\n\n\tconst apiHostsBlock = \"/api/hosts_block\"\n\tlet env = {\n\t\tNameServers: [],\n\t\tHostsBlocks: [],\n\t\tHostsFiles: {},\n\t};\n\n\tconst envUnsubscribe = environment.subscribe(value => {\n\t\tenv = value;\n\t});\n\tonDestroy(envUnsubscribe);\n\n\tasync function updateHostsBlocks() {\n\t\tconst res = await fetch(apiHostsBlock, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(env.HostsBlocks),\n\t\t});\n\n\t\tif (res.status >= 400) {\n\t\t\tWuiPushNotif.Error(\"ERROR: \", res.status, res.statusText)\n\t\t\treturn;\n\t\t}\n\n\t\tsetEnvironment(await res.json());\n\t}\n</script>\n\n<style>\n\t.block_source {\n\t\twidth: calc(100% - 2em);\n\t\toverflow: auto;\n\t\tfont-size: 12px;\n\t}\n\t.block_source input:disabled {\n\t\tcolor: black;\n\t}\n\t.item span {\n\t\tdisplay: inline-block;\n\t\tmargin-right: 1em;\n\t}\n\t.item.header {\n\t\tfont-weight: bold;\n\t\tmargin-bottom: 1em;\n\t\tborder-bottom: 1px solid silver;\n\t}\n\t.item > span:nth-child(1) {\n\t\twidth: 4em;\n\t}\n\t.item > span:nth-child(2) {\n\t\twidth: 15em;\n\t}\n\t.item > span:nth-child(3) {\n\t\twidth: 23em;\n\t}\n\t.item > span:nth-child(3) input {\n\t\twidth: 100%;\n\t}\n\t.item > span:nth-child(4) {\n\t\twidth: 16em;\n\t}\n</style>\n\n<div class=\"hosts-block\">\n\t<p>\n\tConfigure the source of blocked hosts file.\n\t</p>\n\n\t<div class=\"block_source\">\n\t\t<div class=\"item header\">\n\t\t\t<span> Enabled </span>\n\t\t\t<span> Name </span>\n\t\t\t<span> URL </span>\n\t\t\t<span> Last updated </span>\n\t\t</div>\n\t\t{#each env.HostsBlocks as hostsBlock}\n\t\t<div class=\"item\">\n\t\t\t<span>\n\t\t\t\t<input\n\t\t\t\t\ttype=checkbox\n\t\t\t\t\tbind:checked={hostsBlock.IsEnabled}\n\t\t\t\t>\n\t\t\t</span>\n\t\t\t<span>\n\t\t\t\t{hostsBlock.Name}\n\t\t\t</span>\n\t\t\t<span>\n\t\t\t\t<input\n\t\t\t\t\tbind:value={hostsBlock.URL}\n\t\t\t\t\tdisabled\n\t\t\t\t>\n\t\t\t</span>\n\t\t\t<span>\n\t\t\t\t{hostsBlock.LastUpdated}\n\t\t\t</span>\n\t\t</div>\n\t\t{/each}\n\t</div>\n\n\t<div>\n\t\t<button on:click={updateHostsBlocks}>\n\t\t\tSave\n\t\t</button>\n\t</div>\n</div>\n",
- "<script> import { onDestroy } from 'svelte';\n\timport { WuiPushNotif } from 'wui.svelte';\n\timport { apiEnvironment, environment, nanoSeconds } from './environment.js';\n\n\tconst apiHostsDir = \"/api/hosts.d\"\n\n\tlet env = {\n\t\tHostsFiles: {},\n\t};\n\tlet hostsFile = {\n\t\tName: \"\",\n\t\tRecords: [],\n\t};\n\tlet newRecord = null;\n\tlet newHostsFile = \"\";\n\n\tconst envUnsubscribe = environment.subscribe(value => {\n\t\tenv = value;\n\t});\n\tonDestroy(envUnsubscribe);\n\n\tasync function getHostsFile(hf) {\n\t\tif (hf.Records === null) {\n\t\t\thf.Records = []\n\t\t}\n\t\tif (hf.Records.length > 0) {\n\t\t\thostsFile = hf;\n\t\t\treturn;\n\t\t}\n\t\tconst res = await fetch(apiHostsDir +\"/\"+ hf.Name);\n\t\thf.Records = await res.json();\n\t\thostsFile = hf;\n\t}\n\n\tasync function createHostsFile() {\n\t\tif (newHostsFile === \"\") {\n\t\t\treturn;\n\t\t}\n\n\t\tconst res = await fetch(apiHostsDir+ \"/\"+ newHostsFile, {\n\t\t\tmethod: \"PUT\",\n\t\t})\n\n\t\tif (res.status >= 400) {\n\t\t\tconst resError = await res.json()\n\t\t\tWuiPushNotif.Error(\"ERROR: createHostsFile: \", resError.message)\n\t\t\treturn;\n\t\t}\n\n\t\tconst hf = {\n\t\t\tName: newHostsFile,\n\t\t\tRecords: [],\n\t\t}\n\t\tenv.HostsFiles[newHostsFile] = hf\n\t\tenv = env\n\n\t\tWuiPushNotif.Info(\"The new host file '\"+ newHostsFile +\"' has been created\")\n\t}\n\n\tasync function updateHostsFile() {\n\t\tconst res = await fetch(apiHostsDir+\"/\"+ hostsFile.Name, {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: JSON.stringify(hostsFile.Records),\n\t\t})\n\n\t\tif (res.status >= 400) {\n\t\t\tconst resError = await res.json()\n\t\t\tWuiPushNotif.Error(\"ERROR: updateHostsFile: \", resError.message)\n\t\t\treturn;\n\t\t}\n\n\t\thostsFile.Records = await res.json()\n\n\t\tWuiPushNotif.Info(\"The host file '\"+ hostsFile.Name +\"' has been updated\")\n\t}\n\n\tfunction addRecord() {\n\t\tif (newRecord !== null) {\n\t\t\treturn\n\t\t}\n\t\tnewRecord = {\n\t\t\tName: \"\",\n\t\t\tValue: \"\",\n\t\t}\n\t}\n\n\tasync function handleHostsRecordCreate() {\n\t\tconst api = apiHostsDir +\"/\"+ hostsFile.Name +\"/rr\"\n\t\t\t+\"?domain=\"+ newRecord.Name\n\t\t\t+\"&value=\"+ newRecord.Value\n\n\t\tconst res = await fetch(api, {\n\t\t\tmethod: \"POST\"\n\t\t})\n\t\tif (res.status >= 400) {\n\t\t\tconst resError = await res.json()\n\t\t\tWuiPushNotif.Error(\"ERROR: \"+ resError.message)\n\t\t\treturn;\n\t\t}\n\t\tconst rr = await res.json()\n\t\thostsFile.Records.push(rr)\n\t\thostsFile.Records = hostsFile.Records\n\t\tnewRecord = null\n\t\tWuiPushNotif.Info(\"Record '\"+ rr.Name +\"' has been created\")\n\t}\n\n\tasync function handleHostsRecordDelete(rr, idx) {\n\t\tconst api = apiHostsDir +\"/\"+ hostsFile.Name +\"/rr\"+\n\t\t\t\"?domain=\"+rr.Name\n\n\t\tconst res = await fetch(api, {\n\t\t\tmethod: \"DELETE\"\n\t\t})\n\t\tif (res.status >= 400) {\n\t\t\tconst resError = await res.json()\n\t\t\tWuiPushNotif.Error(\"ERROR: \"+ resError.message)\n\t\t\treturn;\n\t\t}\n\t\thostsFile.Records.splice(idx, 1);\n\t\thostsFile.Records = hostsFile.Records;\n\t\tWuiPushNotif.Info(\"Record '\"+ rr.Name +\"' has been deleted\")\n\t}\n\n\tasync function deleteHostsFile(hfile) {\n\t\tconst res = await fetch(apiHostsDir+\"/\"+hfile.Name, {\n\t\t\tmethod: \"DELETE\",\n\t\t});\n\t\tif (res.status >= 400) {\n\t\t\tconst resError = await res.json()\n\t\t\tWuiPushNotif.Error(\"ERROR: deleteHostsFile: \", resError.message)\n\t\t\treturn;\n\t\t}\n\t\tdelete env.HostsFiles[hfile.Name]\n\t\tenv = env;\n\t\thostsFile = {\n\t\t\tName: \"\",\n\t\t\tRecords: [],\n\t\t}\n\t\tWuiPushNotif.Info(\"The host file '\"+ hfile.Name +\"' has been deleted\")\n\t}\n</script>\n\n<style>\n\t.nav-left {\n\t\tpadding: 0px;\n\t\twidth: 280px;\n\t\tfloat: left;\n\t}\n\t.nav-left .item {\n\t\tmargin: 4px 0px;\n\t}\n\t.content {\n\t\tfloat: left;\n\t\twidth: calc(100% - 300px);\n\t}\n\t.host {\n\t\tfont-family: monospace;\n\t\twidth: 100%;\n\t}\n\t.host.header {\n\t\tmargin: 1em 0px;\n\t\tfont-weight: bold;\n\t\tborder-bottom: 1px solid silver;\n\t}\n\t.host_name {\n\t\tdisplay: inline-block;\n\t\twidth: 240px;\n\t\tword-wrap: break-word;\n\t}\n\t.host_value {\n\t\tdisplay: inline-block;\n\t\twidth: 140px;\n\t}\n</style>\n\n<div class=\"hosts_d\">\n\t<div class=\"nav-left\">\n\t\t{#each Object.entries(env.HostsFiles) as [name,hf], name }\n\t\t<div class=\"item\">\n\t\t\t<a href=\"#\" on:click={getHostsFile(hf)}>\n\t\t\t\t{hf.Name}\n\t\t\t</a>\n\t\t</div>\n\t\t{/each}\n\n\t\t<br/>\n\n\t\t<label>\n\t\t\t<span>New hosts file:</span>\n\t\t\t<br/>\n\t\t\t<input bind:value={newHostsFile}>\n\t\t</label>\n\t\t<button on:click={createHostsFile}>\n\t\t\tCreate\n\t\t</button>\n\t</div>\n\n\t<div class=\"content\">\n\t\t{#if hostsFile.Name === \"\"}\n\t\t\t<div>\n\t\t\t\tSelect one of the hosts file to manage.\n\t\t\t</div>\n\t\t{:else}\n\t\t\t<p>\n\t\t\t\t{hostsFile.Name} ({hostsFile.Records.length} records)\n\t\t\t\t<button on:click={deleteHostsFile(hostsFile)}>\n\t\t\t\t\tDelete\n\t\t\t\t</button>\n\t\t\t</p>\n\t\t\t<div>\n\t\t\t\t<button on:click={addRecord}>\n\t\t\t\t\tAdd\n\t\t\t\t</button>\n\t\t\t</div>\n\n\t\t\t{#if newRecord !== null}\n\t\t\t\t<div class=\"host\">\n\t\t\t\t\t<input\n\t\t\t\t\t\tclass=\"host_name\"\n\t\t\t\t\t\tplaceholder=\"Domain name\"\n\t\t\t\t\t\tbind:value={newRecord.Name}\n\t\t\t\t\t>\n\t\t\t\t\t<input\n\t\t\t\t\t\tclass=\"host_value\"\n\t\t\t\t\t\tplaceholder=\"IP address\"\n\t\t\t\t\t\tbind:value={newRecord.Value}\n\t\t\t\t\t>\n\t\t\t\t\t<button on:click={handleHostsRecordCreate}>\n\t\t\t\t\t\tCreate\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t{/if}\n\n\t\t\t<div class=\"host header\">\n\t\t\t\t<span class=\"host_name\"> Domain name </span>\n\t\t\t\t<span class=\"host_value\"> IP address </span>\n\t\t\t</div>\n\n\t\t\t{#each hostsFile.Records as rr, idx (idx)}\n\t\t\t\t<div class=\"host\">\n\t\t\t\t\t<span class=\"host_name\"> {rr.Name} </span>\n\t\t\t\t\t<span class=\"host_value\"> {rr.Value} </span>\n\t\t\t\t\t<button on:click={handleHostsRecordDelete(rr, idx)}>\n\t\t\t\t\t\tX\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t{/each}\n\t\t{/if}\n\t</div>\n</div>\n",
- "<script>\n\timport { onDestroy } from 'svelte';\n\timport { WuiPushNotif, WuiLabelHint } from 'wui.svelte';\n\timport { environment, nanoSeconds, setEnvironment } from './environment.js';\n\n\tconst apiMasterd = \"/api/master.d/\"\n\n\tlet env = {\n\t\tNameServers: [],\n\t\tHostsBlocks: [],\n\t\tHostsFiles: [],\n\t\tZoneFiles: {},\n\t};\n\tlet newZoneFile = \"\";\n\tlet activeZone = {\n\t\tName: \"\",\n\t};\n\n\tlet RRTypes = {\n\t\t1: 'A',\n\t\t2: 'NS',\n\t\t5: 'CNAME',\n\t\t12: 'PTR',\n\t\t15: 'MX',\n\t\t16: 'TXT',\n\t\t28: 'AAAA',\n\t};\n\n\tlet _rr = newRR()\n\tlet _rrMX = newMX();\n\n\tconst envUnsubscribe = environment.subscribe(value => {\n\t\tenv = value;\n\t});\n\tonDestroy(envUnsubscribe);\n\n\tfunction setActiveZone(zone) {\n\t\tif (zone.SOA === null) {\n\t\t\tzone.SOA = newSOA()\n\t\t}\n\t\tactiveZone = zone\n\t}\n\n\tasync function handleZoneFileCreate() {\n\t\tconst res = await fetch(apiMasterd + newZoneFile, {\n\t\t\tmethod: \"PUT\",\n\t\t})\n\n\t\tif (res.status >= 400) {\n\t\t\tconst resError = await res.json()\n\t\t\tWuiPushNotif.Error(\"ERROR: handleZoneFileCreate: \"+ resError.message)\n\t\t\treturn;\n\t\t}\n\n\t\tactiveZone = await res.json()\n\t\tactiveZone.SOA = newSOA()\n\t\tenv.ZoneFiles[activeZone.Name] = activeZone\n\n\t\tWuiPushNotif.Info(\"The new zone file '\"+ newZoneFile +\"' has been created\")\n\t}\n\n\tasync function handleZoneFileDelete() {\n\t\tlet api = apiMasterd + activeZone.Name\n\t\tconst res = await fetch(api, {\n\t\t\tmethod: \"DELETE\",\n\t\t})\n\n\t\tif (res.status >= 400) {\n\t\t\tconst resError = await res.json()\n\t\t\tWuiPushNotif.Error(\"ERROR: handleZoneFileDelete: \"+ resError.message)\n\t\t\treturn;\n\t\t}\n\n\t\tWuiPushNotif.Info(\"The zone file '\"+ activeZone.Name + \"' has beed deleted\")\n\n\t\tdelete env.ZoneFiles[activeZone.Name]\n\t\tactiveZone = {\n\t\t\tName: \"\",\n\t\t}\n\t\tenv.ZoneFiles = env.ZoneFiles\n\n\t}\n\n\tfunction onSelectRRType() {\n\t\tswitch (_rr.Type) {\n\t\tcase 15:\n\t\t\t_rrMX = newMX()\n\t\t\tbreak\n\t\t}\n\t}\n\n\tasync function handleSOADelete() {\n\t\treturn handleDeleteRR(activeZone.SOA, -1)\n\t}\n\n\tasync function handleSOASave() {\n\t\t_rr = activeZone.SOA\n\t\treturn handleCreateRR()\n\t}\n\n\tasync function handleCreateRR() {\n\t\tswitch (_rr.Type) {\n\t\tcase 15:\n\t\t\t_rr.Value = _rrMX;\n\t\t\tbreak;\n\t\t}\n\n\t\tlet api = apiMasterd + activeZone.Name +\"/rr/\"+ _rr.Type;\n\t\tconst res = await fetch(api, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n \t\t\t'Content-Type': 'application/json',\n\t\t\t},\n\t\t\tbody: JSON.stringify(_rr),\n\t\t})\n\n\t\tif (res.status >= 400) {\n\t\t\tconst resError = await res.json()\n\t\t\tWuiPushNotif.Error(\"ERROR: handleCreateRR: \"+ resError.message)\n\t\t\treturn;\n\t\t}\n\n\t\tlet resRR = await res.json()\n\n\t\tif (resRR.Type === 6) {\n\t\t\tactiveZone.SOA = resRR\n\t\t\tWuiPushNotif.Info(\"SOA record has been saved\")\n\t\t} else {\n\t\t\tlet listRR = activeZone.Records[resRR.Name]\n\t\t\tif (typeof listRR === \"undefined\") {\n\t\t\t\tlistRR = [];\n\t\t\t}\n\t\t\tlistRR.push(resRR);\n\t\t\tactiveZone.Records[resRR.Name] = listRR\n\t\t\tWuiPushNotif.Info(\"The new record '\"+ resRR.Name +\"' has been created\")\n\t\t}\n\t}\n\n\tasync function handleDeleteRR(rr, idx) {\n\t\tlet api = apiMasterd + activeZone.Name +\"/rr/\"+ rr.Type\n\n\t\tconst res = await fetch(api, {\n\t\t\tmethod: \"DELETE\",\n\t\t\theaders: {\n \t\t\t'Content-Type': 'application/json',\n\t\t\t},\n\t\t\tbody: JSON.stringify(rr),\n\t\t})\n\n\t\tif (res.status >= 400) {\n\t\t\tconst resError = await res.json()\n\t\t\tWuiPushNotif.Error(\"ERROR: handleDeleteRR: \"+ resError.message)\n\t\t\treturn\n\t\t}\n\n\t\tWuiPushNotif.Info(\"The record '\"+ rr.Name +\"' has been deleted\")\n\n\t\tif (rr.Type == 6) { // SOA.\n\t\t\tactiveZone.SOA = newSOA()\n\t\t} else {\n\t\t\tlet listRR = activeZone.Records[rr.Name]\n\t\t\tlistRR.splice(idx, 1)\n\t\t\tactiveZone.Records[rr.Name] = listRR\n\t\t}\n\n\t\tlet resbody = await res.json()\n\t}\n\n\tfunction getTypeName(k) {\n\t\tlet v = RRTypes[k];\n\t\tif (v === \"\") {\n\t\t\treturn k;\n\t\t}\n\t\treturn v;\n\t}\n\n\tfunction newRR() {\n\t\treturn {\n\t\t\tName: \"\",\n\t\t\tType: 1,\n\t\t\tValue: \"\",\n\t\t};\n\t}\n\n\tfunction newMX() {\n\t\treturn {\n\t\t\tPreference: 1,\n\t\t\tExchange: \"\",\n\t\t}\n\t}\n\n\tfunction newSOA() {\n\t\treturn {\n\t\t\tName: \"\",\n\t\t\tType: 6,\n\t\t\tValue: {\n\t\t\t\tMName: \"\",\n\t\t\t\tRName: \"\",\n\t\t\t\tSerial: 0,\n\t\t\t\tRefresh: 0,\n\t\t\t\tRetry: 0,\n\t\t\t\tExpire: 0,\n\t\t\t\tMinimum: 0\n\t\t\t}\n\t\t};\n\t}\n</script>\n\n<style>\n\th4 {\n\t\tborder-bottom: 1px solid silver;\n\t}\n\t.nav-left {\n\t\tpadding: 0px;\n\t\twidth: 280px;\n\t\tfloat: left;\n\t}\n\t.nav-left .item {\n\t\tmargin: 4px 0px;\n\t\tcursor: pointer;\n\t\tcolor: rgb(0, 100, 200);\n\t}\n\t.content {\n\t\tfloat: left;\n\t\twidth: calc(100% - 300px);\n\t}\n\t.action-delete {\n\t\tmargin-left: 1em;\n\t}\n\t.actions {\n\t\tpadding: 1em;\n\t}\n\t.actions button {\n\t\twidth: 100%;\n\t}\n\n\tform {\n\t\tmargin: 1em 0px;\n\t\tpadding: 10px 10px 0px 10px;\n\t\tborder: 1px solid silver;\n\t}\n\tform > label > span {\n\t\twidth: 7em;\n\t\tdisplay: inline-block;\n\t}\n\tform > label > input {\n\t\twidth: calc(100% - 8em);\n\t}\n\tform > label > input.name {\n\t\twidth: 12em;\n\t}\n\n\t.rr {\n\t\tfont-family: monospace;\n\t\twidth: 100%;\n\t\tpadding: 1em 0px;\n\t}\n\t.rr.header {\n\t\tfont-weight: bold;\n\t}\n\t.rr > .name {\n\t\twidth: 20em;\n\t\tdisplay: inline-block;\n\t\tword-wrap: break-word;\n\t}\n\t.rr > .type {\n\t\twidth: 4em;\n\t\tdisplay: inline-block;\n\t}\n\t.rr > .ttl {\n\t\twidth: 6em;\n\t\tdisplay: inline-block;\n\t}\n\t.rr > .value {\n\t\tdisplay: inline-block;\n\t\tword-wrap: break-word;\n\t}\n</style>\n\n<div class=\"master_d\">\n\t<div class=\"nav-left\">\n\t\t{#each Object.entries(env.ZoneFiles) as [name, zoneFile]}\n\t\t\t<div class=\"item\">\n\t\t\t\t<span on:click={setActiveZone(zoneFile)}>\n\t\t\t\t\t{zoneFile.Name}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t{/each}\n\t\t<br/>\n\n\t\t<label>\n\t\t\t<span>New zone file:</span>\n\t\t\t<br/>\n\t\t\t<input bind:value={newZoneFile}>\n\t\t</label>\n\t\t<button on:click={handleZoneFileCreate}>\n\t\t\tCreate\n\t\t</button>\n\t</div>\n\n\t<div class=\"content\">\n\t\t{#if activeZone.Name === \"\"}\n\t\t\t<p>\n\t\t\t\tSelect one of the zone file to manage.\n\t\t\t</p>\n\t\t{:else}\n\t\t\t<h3>\n\t\t\t\t{activeZone.Name}\n\t\t\t\t<button\n\t\t\t\t\tclass=\"action-delete\"\n\t\t\t\t\ton:click={handleZoneFileDelete}\n\t\t\t\t>\n\t\t\t\t\tDelete\n\t\t\t\t</button>\n\t\t\t</h3>\n\n\t\t\t<h4>\n\t\t\t\tSOA record\n\t\t\t\t<button\n\t\t\t\t\tclass=\"action-delete\"\n\t\t\t\t\ton:click={handleSOADelete}\n\t\t\t\t>\n\t\t\t\t\tDelete\n\t\t\t\t</button>\n\t\t\t</h4>\n\t\t\t<div class=\"rr-soa\">\n\t\t\t\t<WuiLabelHint\n\t\t\t\t\ttitle=\"Name server\"\n\t\t\t\t\ttitle_width=\"150px\"\n\t\t\t\t\tinfo=\"The domain-name of the name server that was the\noriginal or primary source of data for this zone.\nIt should be domain-name where the rescached run.\"\n\t\t\t\t>\n\t\t\t\t\t<input bind:value={activeZone.SOA.Value.MName}>\n\t\t\t\t</WuiLabelHint>\n\t\t\t\t<WuiLabelHint\n\t\t\t\t\ttitle=\"Admin email\"\n\t\t\t\t\ttitle_width=\"150px\"\n\t\t\t\t\tinfo='Email address of the administrator responsible for\nthis zone.\nThe \"@\" on email address is replaced with dot, and if there is a dot before\n\"@\" it should be escaped with \"\\\".\nFor example, \"dns.admin@domain.tld\" would be written as\n\"dns\\.admin.domain.tld\".'\n\t\t\t\t>\n\t\t\t\t\t<input bind:value={activeZone.SOA.Value.RName}>\n\t\t\t\t</WuiLabelHint>\n\t\t\t\t<WuiLabelHint\n\t\t\t\t\ttitle=\"Serial\"\n\t\t\t\t\ttitle_width=\"150px\"\n\t\t\t\t\tinfo=\"Serial number for this zone. If a secondary name\nserver observes an increase in this number, the server will assume that the\nzone has been updated and initiate a zone transfer.\"\n\t\t\t\t>\n\t\t\t\t\t<input\n\t\t\t\t\t\tbind:value={activeZone.SOA.Value.Serial}\n\t\t\t\t\t\ttype=number\n\t\t\t\t\t\tmin=0\n\t\t\t\t\t>\n\t\t\t\t</WuiLabelHint>\n\t\t\t\t<WuiLabelHint\n\t\t\t\t\ttitle=\"Refresh\"\n\t\t\t\t\ttitle_width=\"150px\"\n\t\t\t\t\tinfo=\"Number of seconds after which secondary name servers\nshould query the master for the SOA record, to detect zone changes.\nRecommendation for small and stable zones is 86400 seconds (24 hours).\"\n\t\t\t\t>\n\t\t\t\t\t<input\n\t\t\t\t\t\tbind:value={activeZone.SOA.Value.Refresh}\n\t\t\t\t\t\ttype=number\n\t\t\t\t\t\tmin=0\n\t\t\t\t\t>\n\t\t\t\t</WuiLabelHint>\n\t\t\t\t<WuiLabelHint\n\t\t\t\t\ttitle=\"Retry\"\n\t\t\t\t\ttitle_width=\"150px\"\n\t\t\t\t\tinfo=\"Number of seconds after which secondary name servers\nshould retry to request the serial number from the master if the master does\nnot respond.\nIt must be less than Refresh.\nRecommendation for small and stable zones is 7200 seconds (2 hours).\"\n\t\t\t\t>\n\t\t\t\t\t<input\n\t\t\t\t\t\tbind:value={activeZone.SOA.Value.Retry}\n\t\t\t\t\t\ttype=number\n\t\t\t\t\t\tmin=0\n\t\t\t\t\t>\n\t\t\t\t</WuiLabelHint>\n\t\t\t\t<WuiLabelHint\n\t\t\t\t\ttitle=\"Expire\"\n\t\t\t\t\ttitle_width=\"150px\"\n\t\t\t\t\tinfo=\"Number of seconds after which secondary name servers\nshould stop answering request for this zone if the master does not respond.\nThis value must be bigger than the sum of Refresh and Retry.\nRecommendation for small and stable zones is 3600000 seconds (1000 hours).\"\n\t\t\t\t>\n\t\t\t\t\t<input\n\t\t\t\t\t\tbind:value={activeZone.SOA.Value.Expire}\n\t\t\t\t\t\ttype=number\n\t\t\t\t\t\tmin=0\n\t\t\t\t\t>\n\t\t\t\t</WuiLabelHint>\n\t\t\t\t<WuiLabelHint\n\t\t\t\t\ttitle=\"Minimum\"\n\t\t\t\t\ttitle_width=\"150px\"\n\t\t\t\t\tinfo=\"Time to live for purposes of negative caching.\nRecommendation for small and stable zones is 1800 seconds (30 min).\"\n\t\t\t\t>\n\t\t\t\t\t<input\n\t\t\t\t\t\tbind:value={activeZone.SOA.Value.Minimum}\n\t\t\t\t\t\ttype=number\n\t\t\t\t\t\tmin=0\n\t\t\t\t\t>\n\t\t\t\t</WuiLabelHint>\n\t\t\t\t<div class=\"actions\">\n\t\t\t\t\t<button on:click={handleSOASave}>\n\t\t\t\t\t\tSave\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<h4> List records </h4>\n\t\t\t<div class=\"rr header\">\n\t\t\t\t<span class=\"name\">\n\t\t\t\t\tName\n\t\t\t\t</span>\n\t\t\t\t<span class=\"type\">\n\t\t\t\t\tType\n\t\t\t\t</span>\n\t\t\t\t<span class=\"value\">\n\t\t\t\t\tValue\n\t\t\t\t</span>\n\t\t\t</div>\n\n\t\t\t{#each Object.entries(activeZone.Records) as [dname, listRR]}\n\t\t\t\t{#each listRR as rr, idx}\n\t\t\t\t\t<div class=\"rr\">\n\t\t\t\t\t\t<span class=\"name\">\n\t\t\t\t\t\t\t{rr.Name}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span class=\"type\">\n\t\t\t\t\t\t\t{getTypeName(rr.Type)}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span class=\"value\">\n\t\t\t\t\t\t\t{rr.Value}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<button on:click={handleDeleteRR(rr, idx)}>\n\t\t\t\t\t\t\tX\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\t\t\t{/each}\n\n\t\t\t<form on:submit|preventDefault={handleCreateRR}>\n\t\t\t\t<label>\n\t\t\t\t\t<span>\n\t\t\t\t\t\tType:\n\t\t\t\t\t</span>\n\t\t\t\t\t<select\n\t\t\t\t\t\tbind:value={_rr.Type}\n\t\t\t\t\t\ton:blur={onSelectRRType}\n\t\t\t\t\t>\n\t\t\t\t\t\t{#each Object.entries(RRTypes) as [k, v]}\n\t\t\t\t\t\t\t<option value={parseInt(k)}>\n\t\t\t\t\t\t\t\t{v}\n\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t{/each}\n\t\t\t\t\t</select>\n\t\t\t\t</label>\n\n\t\t\t\t{#if _rr.Type === 1 || _rr.Type === 2 || _rr.Type === 5 ||\n\t\t\t\t\t_rr.Type === 16 || _rr.Type === 28\n\t\t\t\t}\n\t\t\t\t\t<label>\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\tName:\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<input class=\"name\" bind:value={_rr.Name}>\n\t\t\t\t\t\t.{activeZone.Name}\n\t\t\t\t\t</label>\n\n\t\t\t\t\t<label>\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\tValue:\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<input bind:value={_rr.Value}>\n\t\t\t\t\t</label>\n\t\t\t\t{:else if _rr.Type === 12} <!-- PTR -->\n\t\t\t\t\t<label>\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\tName:\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<input bind:value={_rr.Name}>\n\t\t\t\t\t</label>\n\t\t\t\t\t<label>\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\tValue:\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<input class=\"name\" bind:value={_rr.Value}>\n\t\t\t\t\t\t.{activeZone.Name}\n\t\t\t\t\t</label>\n\t\t\t\t{:else if _rr.Type === 15} <!-- MX -->\n\t\t\t\t\t<label>\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\tName:\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<input class=\"name\" bind:value={_rr.Name}>\n\t\t\t\t\t\t.{activeZone.Name}\n\t\t\t\t\t</label>\n\t\t\t\t\t<label>\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\tPreference:\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<input bind:value={_rrMX.Preference} type=number min=1 max=65535>\n\t\t\t\t\t</label>\n\t\t\t\t\t<label>\n\t\t\t\t\t\t<span>\n\t\t\t\t\t\t\tExchange:\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<input bind:value={_rrMX.Exchange}>\n\t\t\t\t\t</label>\n\t\t\t\t{/if}\n\n\t\t\t\t<div class=\"actions\">\n\t\t\t\t\t<button class=\"create\" type=submit>\n\t\t\t\t\t\tCreate\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</form>\n\t\t{/if}\n\t</div> <!-- content -->\n</div> <!-- master_d -->\n"
- ],
- "names": [],
- "mappings": "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"
-} \ No newline at end of file