diff --git a/credits.txt b/credits.txt index 75f89fd..91f0770 100644 --- a/credits.txt +++ b/credits.txt @@ -1,3 +1,15 @@ +=== Code === +== Packages and tools == +busboy (https://www.npmjs.com/package/busboy) +check-disk-space (https://www.npmjs.com/package/check-disk-space) +express: (https://www.npmjs.com/package/express) +ip: (https://www.npmjs.com/package/ip) +mime-types: (https://www.npmjs.com/package/mime-types) +node-gzip: (https://www.npmjs.com/package/node-gzip) +stream-meter: (https://www.npmjs.com/package/stream-meter) +Sveltekit (https://kit.svelte.dev/) + +=== Images === == Key == Material Icons: https://materialdesignicons.com/ diff --git a/server/config.json b/server/config.json index 2f4a751..d40a114 100644 --- a/server/config.json +++ b/server/config.json @@ -8,7 +8,6 @@ "downloadedFile": 10 }, "clientRelated": { - "cleaningUp": 0.5, "maxRoomsReached": 10, "fileNotReady": 1, "tooManyFiles": 5 @@ -31,9 +30,13 @@ }, "log": { - "unusual": true + "uploadErrors": true, + "diskSpaceLessThanLimit": true + }, + "require": { + "diskSpaceMoreThanLimit": false }, "serve": { - "gzip": false + "gzip": true } } \ No newline at end of file diff --git a/server/gzipBuild/app/immutable/chunks/TopBar-1a82d815.js.gz b/server/gzipBuild/app/immutable/chunks/TopBar-1a82d815.js.gz deleted file mode 100644 index 7894f68..0000000 Binary files a/server/gzipBuild/app/immutable/chunks/TopBar-1a82d815.js.gz and /dev/null differ diff --git a/server/gzipBuild/app/immutable/chunks/TopBar-b4235a47.js.gz b/server/gzipBuild/app/immutable/chunks/TopBar-b4235a47.js.gz new file mode 100644 index 0000000..cf8a5d5 Binary files /dev/null and b/server/gzipBuild/app/immutable/chunks/TopBar-b4235a47.js.gz differ diff --git a/server/gzipBuild/app/immutable/chunks/index-e18ba743.js.gz b/server/gzipBuild/app/immutable/chunks/index-e18ba743.js.gz new file mode 100644 index 0000000..9862631 Binary files /dev/null and b/server/gzipBuild/app/immutable/chunks/index-e18ba743.js.gz differ diff --git a/server/gzipBuild/app/immutable/chunks/index-fd06faab.js.gz b/server/gzipBuild/app/immutable/chunks/index-fd06faab.js.gz deleted file mode 100644 index 0f7604a..0000000 Binary files a/server/gzipBuild/app/immutable/chunks/index-fd06faab.js.gz and /dev/null differ diff --git a/server/gzipBuild/app/immutable/error.svelte-a3ddb1a9.js.gz b/server/gzipBuild/app/immutable/error.svelte-a3ddb1a9.js.gz deleted file mode 100644 index 0b6e465..0000000 Binary files a/server/gzipBuild/app/immutable/error.svelte-a3ddb1a9.js.gz and /dev/null differ diff --git a/server/gzipBuild/app/immutable/error.svelte-c6d9751f.js.gz b/server/gzipBuild/app/immutable/error.svelte-c6d9751f.js.gz new file mode 100644 index 0000000..ea3ddfb Binary files /dev/null and b/server/gzipBuild/app/immutable/error.svelte-c6d9751f.js.gz differ diff --git a/server/gzipBuild/app/immutable/layout.svelte-ab90e838.js.gz b/server/gzipBuild/app/immutable/layout.svelte-ab90e838.js.gz new file mode 100644 index 0000000..83c7d77 Binary files /dev/null and b/server/gzipBuild/app/immutable/layout.svelte-ab90e838.js.gz differ diff --git a/server/gzipBuild/app/immutable/layout.svelte-bd35716c.js.gz b/server/gzipBuild/app/immutable/layout.svelte-bd35716c.js.gz deleted file mode 100644 index d37d5b2..0000000 Binary files a/server/gzipBuild/app/immutable/layout.svelte-bd35716c.js.gz and /dev/null differ diff --git a/server/gzipBuild/app/immutable/manifest.json.gz b/server/gzipBuild/app/immutable/manifest.json.gz index 99ac9fb..cdaad90 100644 Binary files a/server/gzipBuild/app/immutable/manifest.json.gz and b/server/gzipBuild/app/immutable/manifest.json.gz differ diff --git a/server/gzipBuild/app/immutable/pages/index.svelte-73518255.js.gz b/server/gzipBuild/app/immutable/pages/index.svelte-73518255.js.gz new file mode 100644 index 0000000..9f1da8a Binary files /dev/null and b/server/gzipBuild/app/immutable/pages/index.svelte-73518255.js.gz differ diff --git a/server/gzipBuild/app/immutable/pages/index.svelte-ccc7e32a.js.gz b/server/gzipBuild/app/immutable/pages/index.svelte-ccc7e32a.js.gz deleted file mode 100644 index cf704f6..0000000 Binary files a/server/gzipBuild/app/immutable/pages/index.svelte-ccc7e32a.js.gz and /dev/null differ diff --git a/server/gzipBuild/app/immutable/pages/room.svelte-30b473f9.js.gz b/server/gzipBuild/app/immutable/pages/room.svelte-30b473f9.js.gz deleted file mode 100644 index 300c82d..0000000 Binary files a/server/gzipBuild/app/immutable/pages/room.svelte-30b473f9.js.gz and /dev/null differ diff --git a/server/gzipBuild/app/immutable/pages/room.svelte-b5ceba1b.js.gz b/server/gzipBuild/app/immutable/pages/room.svelte-b5ceba1b.js.gz new file mode 100644 index 0000000..91681c3 Binary files /dev/null and b/server/gzipBuild/app/immutable/pages/room.svelte-b5ceba1b.js.gz differ diff --git a/server/gzipBuild/app/immutable/start-2b9897d8.js.gz b/server/gzipBuild/app/immutable/start-2b9897d8.js.gz new file mode 100644 index 0000000..525bd4a Binary files /dev/null and b/server/gzipBuild/app/immutable/start-2b9897d8.js.gz differ diff --git a/server/gzipBuild/app/immutable/start-ec45075e.js.gz b/server/gzipBuild/app/immutable/start-ec45075e.js.gz deleted file mode 100644 index d909093..0000000 Binary files a/server/gzipBuild/app/immutable/start-ec45075e.js.gz and /dev/null differ diff --git a/server/gzipBuild/app/version.json.gz b/server/gzipBuild/app/version.json.gz index 7ab9aa9..4105ac3 100644 Binary files a/server/gzipBuild/app/version.json.gz and b/server/gzipBuild/app/version.json.gz differ diff --git a/server/gzipBuild/index.html.gz b/server/gzipBuild/index.html.gz index 0161ab1..af01f69 100644 Binary files a/server/gzipBuild/index.html.gz and b/server/gzipBuild/index.html.gz differ diff --git a/server/gzipBuild/room.html.gz b/server/gzipBuild/room.html.gz index dacc80b..3ca1223 100644 Binary files a/server/gzipBuild/room.html.gz and b/server/gzipBuild/room.html.gz differ diff --git a/server/index.js b/server/index.js index 1d81139..5af6975 100644 --- a/server/index.js +++ b/server/index.js @@ -1,18 +1,15 @@ /* TODO -Use await for when a request can't be completed due to the server cleaning up. It won't be long Use a preflight system for the upload. Client sends request to a different URL, with the size of the file. Server sends back a random key and id it'll be at. This id and the space for the file is now reserved, client has 5 seconds to start the main request or everything's ondone and the code is invalid. The upload also fails if the file becomes bigger than what was stated upfront. Check scaling -Preload images More security stuff involving timings I guess? Mainly around async stuff and assuming data is still correct. Maybe delay processing new rooms when the folder is being created for a new room or something -Proper tab order -Check the max space in config is available Use maps instead of objects generally. Objects should ideally be used in the same way as in strongly typed languages = Bugs = +Probably not my fault: State can desync with files, causing errors Error: write EPIPE on download disconnect Client aborting uploads isn't properly handled. The code will be 400 and request.aborted will be true "Error: Request aborted". Or at least sometimes...? Might be a busboy issue @@ -20,6 +17,7 @@ Client aborting uploads isn't properly handled. The code will be 400 and request const GB_TO_BYTES = Math.pow(1024, 3); +const BYTES_TO_GB = 1 / GB_TO_BYTES; const fs = require("fs/promises"); const oldFS = require("fs"); @@ -28,6 +26,7 @@ const busboy = require("busboy"); const mime = require("mime-types"); const meter = require("stream-meter"); const serveCompressed = require("express-precompressed"); +const getDiskSpace = require("check-disk-space").default; const ipPackage = require("ip"); const IP = ipPackage.address(); @@ -46,7 +45,10 @@ const state = { totalSize: 0, totalFileCount: 0, - cleaningUp: false + tasks: { + cleaningUp: null, + loadConfig: null + } }; let config; // It'll be loaded from the disk let PORT; // Loaded as part of config or from the environment variable @@ -83,10 +85,29 @@ const loadConfig = async _ => { PORT = process.env.PORT?? config.port; }; -const cleanUp = async _ => { - state.cleaningUp = true; - await helper.clearDir("sharedFiles", fs, path); - state.cleaningUp = false; +const checkDiskSpace = async _ => { + let info = await getDiskSpace(__dirname); + await state.tasks.loadConfig; + + let maxSpace = config.limits.max.totalFileSize - state.totalSize; + let notEnoughSpace = maxSpace > info.free; + + if (notEnoughSpace) { + const message = ` +The amount of space left on this computer is less than the maximum total uploads can take up. You might want to reduce the maximum or free up some space. +${maxSpace * BYTES_TO_GB}GB is expected but there's only ${info.free * BYTES_TO_GB} available. +`; + if (config.require.diskSpaceMoreThanLimit) { + throw new Error(message); + } + else if (config.log.diskSpaceLessThanLimit) { + console.warn(message); + } + } +}; + +const cleanUp = _ => { + state.tasks.cleaningUp = helper.clearDir("sharedFiles", fs, path); }; const startServer = _ => { @@ -211,11 +232,7 @@ const startServer = _ => { }); app.post("/room/upload/:roomName/", async (req, res) => { - if (state.cleaningUp) { - res.setHeader("Retry-After", config.timings.clientRelated.cleaningUp); - res.status(503).send("CleaningUp"); - return; - } + await state.tasks.cleaningUp; const max = config.limits.max; if (state.totalFileCount == max.totalFileCount) { @@ -227,8 +244,8 @@ const startServer = _ => { const room = await getOrCreateRoom(req.params.roomName); if (! checks.underRoomLimit(room, res)) return; - let spaceLeft = max.totalFileSize - state.totalSize; - let maxFilesize = max.fileSize == -1? spaceLeft : Math.min(max.fileSize, spaceLeft); + const spaceLeft = max.totalFileSize - state.totalSize; + const maxFilesize = max.fileSize == -1? spaceLeft : Math.min(max.fileSize, spaceLeft); let fileSize = parseInt(req.headers["content-length"]); // Not completely accurate due to overhead but will be reduced once the length is known if (fileSize - max.expectedUploadOverhead > maxFilesize) { // Stop the request early if it'll be too big @@ -306,7 +323,7 @@ const startServer = _ => { deleteUpload(room, id); res.end(); - if (config.log.unusual) { + if (config.log.uploadErrors) { if (stream) { console.log("File upload failed due to client disconnecting."); } @@ -449,7 +466,8 @@ const main = _ => { }; const start = async _ => { - await loadConfig(); + state.tasks.loadConfig = loadConfig(); + await Promise.all([state.tasks.loadConfig, checkDiskSpace()]); cleanUp(); startServer(); diff --git a/server/package.json b/server/package.json index 2ab778c..15d89aa 100644 --- a/server/package.json +++ b/server/package.json @@ -10,6 +10,7 @@ "license": "GPL-3.0", "dependencies": { "busboy": "^1.6.0", + "check-disk-space": "^3.3.1", "express": "^4.18.1", "express-precompressed": "^1.0.0", "ip": "^1.1.8", diff --git a/static/build/app/immutable/manifest.json b/static/build/app/immutable/manifest.json index 4936169..439a207 100644 --- a/static/build/app/immutable/manifest.json +++ b/static/build/app/immutable/manifest.json @@ -1,6 +1,6 @@ { ".svelte-kit/runtime/client/start.js": { - "file": "start-844c4abc.js", + "file": "start-2b9897d8.js", "src": ".svelte-kit/runtime/client/start.js", "isEntry": true, "imports": [ diff --git a/static/build/app/immutable/start-844c4abc.js b/static/build/app/immutable/start-2b9897d8.js similarity index 99% rename from static/build/app/immutable/start-844c4abc.js rename to static/build/app/immutable/start-2b9897d8.js index 7591a7e..4e9364b 100644 --- a/static/build/app/immutable/start-844c4abc.js +++ b/static/build/app/immutable/start-2b9897d8.js @@ -1 +1 @@ -var rt=Object.defineProperty,it=Object.defineProperties;var at=Object.getOwnPropertyDescriptors;var ue=Object.getOwnPropertySymbols;var ze=Object.prototype.hasOwnProperty,qe=Object.prototype.propertyIsEnumerable;var Ve=(n,e,t)=>e in n?rt(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t,x=(n,e)=>{for(var t in e||(e={}))ze.call(e,t)&&Ve(n,t,e[t]);if(ue)for(var t of ue(e))qe.call(e,t)&&Ve(n,t,e[t]);return n},se=(n,e)=>it(n,at(e));var Je=(n,e)=>{var t={};for(var r in n)ze.call(n,r)&&e.indexOf(r)<0&&(t[r]=n[r]);if(n!=null&&ue)for(var r of ue(n))e.indexOf(r)<0&&qe.call(n,r)&&(t[r]=n[r]);return t};import{s as tt,n as ve,S as ot,i as ct,e as lt,c as ft,a as ut,d as V,b as $e,f as B,g as z,t as dt,h as pt,j as ht,k as _t,l as C,m as mt,o as G,p as T,q as M,r as I,u as gt,v as wt,w as Re,x as q,y as ie,z as J,A as ae,B as oe,C as K,D as ce,E as Ke}from"./chunks/index-e18ba743.js";const H=[];function pe(n,e=ve){let t;const r=new Set;function l(s){if(tt(n,s)&&(n=s,t)){const i=!H.length;for(const a of r)a[1](),H.push(a,n);if(i){for(let a=0;a{r.delete(a),r.size===0&&(t(),t=null)}}return{set:l,update:c,subscribe:f}}let Be="",nt="";function bt(n){Be=n.base,nt=n.assets||Be}function yt(n){let e,t,r;const l=[n[1]||{}];var c=n[0][0];function f(s){let i={};for(let a=0;a{K(d,1)}),M()}c?(e=new c(f()),q(e.$$.fragment),I(e.$$.fragment,1),J(e,t.parentNode,t)):e=null}else c&&e.$set(a)},i(s){r||(e&&I(e.$$.fragment,s),r=!0)},o(s){e&&T(e.$$.fragment,s),r=!1},d(s){s&&V(t),e&&K(e,s)}}}function vt(n){let e,t,r;const l=[n[1]||{}];var c=n[0][0];function f(s){let i={$$slots:{default:[Rt]},$$scope:{ctx:s}};for(let a=0;a{K(d,1)}),M()}c?(e=new c(f(s)),q(e.$$.fragment),I(e.$$.fragment,1),J(e,t.parentNode,t)):e=null}else c&&e.$set(a)},i(s){r||(e&&I(e.$$.fragment,s),r=!0)},o(s){e&&T(e.$$.fragment,s),r=!1},d(s){s&&V(t),e&&K(e,s)}}}function $t(n){let e,t,r;const l=[n[2]||{}];var c=n[0][1];function f(s){let i={};for(let a=0;a{K(d,1)}),M()}c?(e=new c(f()),q(e.$$.fragment),I(e.$$.fragment,1),J(e,t.parentNode,t)):e=null}else c&&e.$set(a)},i(s){r||(e&&I(e.$$.fragment,s),r=!0)},o(s){e&&T(e.$$.fragment,s),r=!1},d(s){s&&V(t),e&&K(e,s)}}}function kt(n){let e,t,r;const l=[n[2]||{}];var c=n[0][1];function f(s){let i={$$slots:{default:[Et]},$$scope:{ctx:s}};for(let a=0;a{K(d,1)}),M()}c?(e=new c(f(s)),q(e.$$.fragment),I(e.$$.fragment,1),J(e,t.parentNode,t)):e=null}else c&&e.$set(a)},i(s){r||(e&&I(e.$$.fragment,s),r=!0)},o(s){e&&T(e.$$.fragment,s),r=!1},d(s){s&&V(t),e&&K(e,s)}}}function Et(n){let e,t,r;const l=[n[3]||{}];var c=n[0][2];function f(s){let i={};for(let a=0;a{K(d,1)}),M()}c?(e=new c(f()),q(e.$$.fragment),I(e.$$.fragment,1),J(e,t.parentNode,t)):e=null}else c&&e.$set(a)},i(s){r||(e&&I(e.$$.fragment,s),r=!0)},o(s){e&&T(e.$$.fragment,s),r=!1},d(s){s&&V(t),e&&K(e,s)}}}function Rt(n){let e,t,r,l;const c=[kt,$t],f=[];function s(i,a){return i[0][2]?0:1}return e=s(n),t=f[e]=c[e](n),{c(){t.c(),r=C()},l(i){t.l(i),r=C()},m(i,a){f[e].m(i,a),z(i,r,a),l=!0},p(i,a){let d=e;e=s(i),e===d?f[e].p(i,a):(G(),T(f[d],1,1,()=>{f[d]=null}),M(),t=f[e],t?t.p(i,a):(t=f[e]=c[e](i),t.c()),I(t,1),t.m(r.parentNode,r))},i(i){l||(I(t),l=!0)},o(i){T(t),l=!1},d(i){f[e].d(i),i&&V(r)}}}function We(n){let e,t=n[5]&&Ye(n);return{c(){e=lt("div"),t&&t.c(),this.h()},l(r){e=ft(r,"DIV",{id:!0,"aria-live":!0,"aria-atomic":!0,style:!0});var l=ut(e);t&&t.l(l),l.forEach(V),this.h()},h(){$e(e,"id","svelte-announcer"),$e(e,"aria-live","assertive"),$e(e,"aria-atomic","true"),B(e,"position","absolute"),B(e,"left","0"),B(e,"top","0"),B(e,"clip","rect(0 0 0 0)"),B(e,"clip-path","inset(50%)"),B(e,"overflow","hidden"),B(e,"white-space","nowrap"),B(e,"width","1px"),B(e,"height","1px")},m(r,l){z(r,e,l),t&&t.m(e,null)},p(r,l){r[5]?t?t.p(r,l):(t=Ye(r),t.c(),t.m(e,null)):t&&(t.d(1),t=null)},d(r){r&&V(e),t&&t.d()}}}function Ye(n){let e;return{c(){e=dt(n[6])},l(t){e=pt(t,n[6])},m(t,r){z(t,e,r)},p(t,r){r&64&&ht(e,t[6])},d(t){t&&V(e)}}}function St(n){let e,t,r,l,c;const f=[vt,yt],s=[];function i(d,L){return d[0][1]?0:1}e=i(n),t=s[e]=f[e](n);let a=n[4]&&We(n);return{c(){t.c(),r=_t(),a&&a.c(),l=C()},l(d){t.l(d),r=mt(d),a&&a.l(d),l=C()},m(d,L){s[e].m(d,L),z(d,r,L),a&&a.m(d,L),z(d,l,L),c=!0},p(d,[L]){let E=e;e=i(d),e===E?s[e].p(d,L):(G(),T(s[E],1,1,()=>{s[E]=null}),M(),t=s[e],t?t.p(d,L):(t=s[e]=f[e](d),t.c()),I(t,1),t.m(r.parentNode,r)),d[4]?a?a.p(d,L):(a=We(d),a.c(),a.m(l.parentNode,l)):a&&(a.d(1),a=null)},i(d){c||(I(t),c=!0)},o(d){T(t),c=!1},d(d){s[e].d(d),d&&V(r),a&&a.d(d),d&&V(l)}}}function Lt(n,e,t){let{stores:r}=e,{page:l}=e,{components:c}=e,{props_0:f=null}=e,{props_1:s=null}=e,{props_2:i=null}=e;gt("__svelte__",r),wt(r.page.notify);let a=!1,d=!1,L=null;return Re(()=>{const E=r.page.subscribe(()=>{a&&(t(5,d=!0),t(6,L=document.title||"untitled page"))});return t(4,a=!0),E}),n.$$set=E=>{"stores"in E&&t(7,r=E.stores),"page"in E&&t(8,l=E.page),"components"in E&&t(0,c=E.components),"props_0"in E&&t(1,f=E.props_0),"props_1"in E&&t(2,s=E.props_1),"props_2"in E&&t(3,i=E.props_2)},n.$$.update=()=>{n.$$.dirty&384&&r.page.set(l)},[c,f,s,i,a,d,L,r,l]}class Ut extends ot{constructor(e){super(),ct(this,e,Lt,St,tt,{stores:7,page:8,components:0,props_0:1,props_1:2,props_2:3})}}const At="modulepreload",Ge={},Ot="/app/immutable/",de=function(e,t){return!t||t.length===0?e():Promise.all(t.map(r=>{if(r=`${Ot}${r}`,r in Ge)return;Ge[r]=!0;const l=r.endsWith(".css"),c=l?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${r}"]${c}`))return;const f=document.createElement("link");if(f.rel=l?"stylesheet":At,l||(f.as="script",f.crossOrigin=""),f.href=r,document.head.appendChild(f),l)return new Promise((s,i)=>{f.addEventListener("load",s),f.addEventListener("error",()=>i(new Error(`Unable to preload CSS for ${r}`)))})})).then(()=>e())},Pt={},he=[()=>de(()=>import("./layout.svelte-ab90e838.js"),["layout.svelte-ab90e838.js","chunks/index-e18ba743.js"]),()=>de(()=>import("./error.svelte-c6d9751f.js"),["error.svelte-c6d9751f.js","chunks/index-e18ba743.js"]),()=>de(()=>import("./pages/index.svelte-73518255.js"),["pages/index.svelte-73518255.js","assets/pages/index.svelte-56891da8.css","chunks/index-e18ba743.js","chunks/TopBar-b4235a47.js","assets/TopBar-58fadc1e.css"]),()=>de(()=>import("./pages/room.svelte-b5ceba1b.js"),["pages/room.svelte-b5ceba1b.js","assets/pages/room.svelte-a4d60193.css","chunks/index-e18ba743.js","chunks/TopBar-b4235a47.js","assets/TopBar-58fadc1e.css"])],Nt={"":[[0,2],[1]],room:[[0,3],[1]]};function xt(n){n.client}function Me(n){return n instanceof Error||n&&n.name&&n.message?n:new Error(JSON.stringify(n))}function Fe(n){if(n.fallthrough)throw new Error("fallthrough is no longer supported. Use matchers instead: https://kit.svelte.dev/docs/routing#advanced-routing-matching");if("maxage"in n)throw new Error("maxage should be replaced with cache: { maxage }");const e=n.status&&n.status>=400&&n.status<=599&&!n.redirect;if(n.error||e){const t=n.status;if(!n.error&&e)return{status:t||500,error:new Error};const r=typeof n.error=="string"?new Error(n.error):n.error;return r instanceof Error?!t||t<400||t>599?(console.warn('"error" returned from load() without a valid status code \u2014 defaulting to 500'),{status:500,error:r}):{status:t,error:r}:{status:500,error:new Error(`"error" property returned from load() must be a string or instance of Error, received type "${typeof r}"`)}}if(n.redirect){if(!n.status||Math.floor(n.status/100)!==3)throw new Error('"redirect" property returned from load() must be accompanied by a 3xx status code');if(typeof n.redirect!="string")throw new Error('"redirect" property returned from load() must be a string')}if(n.dependencies&&(!Array.isArray(n.dependencies)||n.dependencies.some(t=>typeof t!="string")))throw new Error('"dependencies" property returned from load() must be of type string[]');if(n.context)throw new Error('You are returning "context" from a load function. "context" was renamed to "stuff", please adjust your code accordingly.');return n}function Ct(n,e){return n==="/"||e==="ignore"?n:e==="never"?n.endsWith("/")?n.slice(0,-1):n:e==="always"&&!n.endsWith("/")?n+"/":n}function Xe(n){let e=n.baseURI;if(!e){const t=n.getElementsByTagName("base");e=t.length?t[0].href:n.URL}return e}function Se(){return{x:pageXOffset,y:pageYOffset}}function He(n){return n.composedPath().find(t=>t instanceof Node&&t.nodeName.toUpperCase()==="A")}function Ze(n){return n instanceof SVGAElement?new URL(n.href.baseVal,document.baseURI):new URL(n.href)}function Qe(n){const e=pe(n);let t=!0;function r(){t=!0,e.update(f=>f)}function l(f){t=!1,e.set(f)}function c(f){let s;return e.subscribe(i=>{(s===void 0||t&&i!==s)&&f(s=i)})}return{notify:r,set:l,subscribe:c}}function Tt(){const{set:n,subscribe:e}=pe(!1),t="1658237858244";let r;async function l(){clearTimeout(r);const f=await fetch(`${nt}/app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(f.ok){const{version:s}=await f.json(),i=s!==t;return i&&(n(!0),clearTimeout(r)),i}else throw new Error(`Version check failed: ${f.status}`)}return{subscribe:e,check:l}}function It(n){let e=5381,t=n.length;if(typeof n=="string")for(;t;)e=e*33^n.charCodeAt(--t);else for(;t;)e=e*33^n[--t];return(e>>>0).toString(36)}const Le=window.fetch;function jt(n,e){let r=`script[sveltekit\\:data-type="data"][sveltekit\\:data-url=${JSON.stringify(typeof n=="string"?n:n.url)}]`;e&&typeof e.body=="string"&&(r+=`[sveltekit\\:data-body="${It(e.body)}"]`);const l=document.querySelector(r);if(l&&l.textContent){const c=JSON.parse(l.textContent),{body:f}=c,s=Je(c,["body"]);return Promise.resolve(new Response(f,s))}return Le(n,e)}const Dt=/^(\.\.\.)?(\w+)(?:=(\w+))?$/;function Vt(n){const e=[],t=[];let r=!0;return{pattern:n===""?/^\/$/:new RegExp(`^${decodeURIComponent(n).split(/(?:@[a-zA-Z0-9_-]+)?(?:\/|$)/).map((c,f,s)=>{const i=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(c);if(i)return e.push(i[1]),t.push(i[2]),"(?:/(.*))?";const a=f===s.length-1;return c&&"/"+c.split(/\[(.+?)\]/).map((d,L)=>{if(L%2){const[,E,Z,F]=Dt.exec(d);return e.push(Z),t.push(F),E?"(.*?)":"([^/]+?)"}return a&&d.includes(".")&&(r=!1),d.normalize().replace(/%5[Bb]/g,"[").replace(/%5[Dd]/g,"]").replace(/#/g,"%23").replace(/\?/g,"%3F").replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}).join("")}).join("")}${r?"/?":""}$`),names:e,types:t}}function zt(n,e,t,r){const l={};for(let c=0;c{const{pattern:i,names:a,types:d}=Vt(l);return{id:l,exec:L=>{const E=i.exec(L);if(E)return zt(E,a,d,t)},a:c.map(L=>n[L]),b:f.map(L=>n[L]),has_shadow:!!s}})}const st="sveltekit:scroll",W="sveltekit:index",ke=qt(he,Nt,Pt),Jt=he[0](),Kt=he[1](),et={};let re={};try{re=JSON.parse(sessionStorage[st])}catch{}function Ee(n){re[n]=Se()}function Bt({target:n,session:e,base:t,trailing_slash:r}){var je;const l=new Map,c=[],f={url:Qe({}),page:Qe({}),navigating:pe(null),session:pe(e),updated:Tt()},s={id:null,promise:null},i={before_navigate:[],after_navigate:[]};let a={branch:[],error:null,session_id:0,stuff:et,url:null},d=!1,L=!0,E=!1,Z=1,F=null,Ue,Ae,Oe=!1;f.session.subscribe(async o=>{Ae=o,Oe&&(Z+=1,we(new URL(location.href),[],!0))}),Oe=!0;let X=!0,j=(je=history.state)==null?void 0:je[W];j||(j=Date.now(),history.replaceState(se(x({},history.state),{[W]:j}),"",location.href));const _e=re[j];_e&&(history.scrollRestoration="manual",scrollTo(_e.x,_e.y));let me=!1,ge,Pe;async function Ne(o,{noscroll:p=!1,replaceState:g=!1,keepfocus:u=!1,state:h={}},w){const $=new URL(o,Xe(document));if(X)return ye({url:$,scroll:p?Se():null,keepfocus:u,redirect_chain:w,details:{state:h,replaceState:g},accepted:()=>{},blocked:()=>{}});await te($)}async function xe(o){const p=Ie(o);if(!p)throw new Error("Attempted to prefetch a URL that does not belong to this app");return s.promise=Te(p,!1),s.id=p.id,s.promise}async function we(o,p,g,u,h){var R,U,A;const w=Ie(o),$=Pe={};let _=w&&await Te(w,g);if(!_&&o.origin===location.origin&&o.pathname===location.pathname&&(_=await ee({status:404,error:new Error(`Not found: ${o.pathname}`),url:o,routeId:null})),!_)return await te(o),!1;if(Pe!==$)return!1;if(c.length=0,_.redirect)if(p.length>10||p.includes(o.pathname))_=await ee({status:500,error:new Error("Redirect loop"),url:o,routeId:null});else return X?Ne(new URL(_.redirect,o).href,{},[...p,o.pathname]):await te(new URL(_.redirect,location.href)),!1;else((U=(R=_.props)==null?void 0:R.page)==null?void 0:U.status)>=400&&await f.updated.check()&&await te(o);if(E=!0,u&&u.details){const{details:y}=u,v=y.replaceState?0:1;y.state[W]=j+=v,history[y.replaceState?"replaceState":"pushState"](y.state,"",o)}if(d?(a=_.state,_.props.page&&(_.props.page.url=o),Ue.$set(_.props)):Ce(_),u){const{scroll:y,keepfocus:v}=u;if(!v){const b=document.body,k=b.getAttribute("tabindex");(A=getSelection())==null||A.removeAllRanges(),b.tabIndex=-1,b.focus({preventScroll:!0}),k!==null?b.setAttribute("tabindex",k):b.removeAttribute("tabindex")}if(await Ke(),L){const b=o.hash&&document.getElementById(o.hash.slice(1));y?scrollTo(y.x,y.y):b?b.scrollIntoView():scrollTo(0,0)}}else await Ke();s.promise=null,s.id=null,L=!0,_.props.page&&(ge=_.props.page);const m=_.state.branch[_.state.branch.length-1];X=(m==null?void 0:m.module.router)!==!1,h&&h(),E=!1}function Ce(o){a=o.state;const p=document.querySelector("style[data-sveltekit]");if(p&&p.remove(),ge=o.props.page,Ue=new Ut({target:n,props:se(x({},o.props),{stores:f}),hydrate:!0}),X){const g={from:null,to:new URL(location.href)};i.after_navigate.forEach(u=>u(g))}d=!0}async function be({url:o,params:p,stuff:g,branch:u,status:h,error:w,routeId:$}){var v,b;const _=u.filter(Boolean),m=_.find(k=>{var O;return(O=k.loaded)==null?void 0:O.redirect}),R={redirect:(v=m==null?void 0:m.loaded)==null?void 0:v.redirect,state:{url:o,params:p,branch:u,error:w,stuff:g,session_id:Z},props:{components:_.map(k=>k.module.default)}};for(let k=0;k<_.length;k+=1){const O=_[k].loaded;R.props[`props_${k}`]=O?await O.props:null}if(!a.url||o.href!==a.url.href||a.error!==w||a.stuff!==g){R.props.page={error:w,params:p,routeId:$,status:h,stuff:g,url:o};const k=(O,S)=>{Object.defineProperty(R.props.page,O,{get:()=>{throw new Error(`$page.${O} has been replaced by $page.url.${S}`)}})};k("origin","origin"),k("path","pathname"),k("query","searchParams")}const A=_[_.length-1],y=(b=A==null?void 0:A.loaded)==null?void 0:b.cache;if(y){const k=o.pathname+o.search;let O=!1;const S=()=>{l.get(k)===R&&l.delete(k),N(),clearTimeout(P)},P=setTimeout(S,y.maxage*1e3),N=f.session.subscribe(()=>{O&&S()});O=!0,l.set(k,R)}return R}async function Q({status:o,error:p,module:g,url:u,params:h,stuff:w,props:$,routeId:_}){const m={module:g,uses:{params:new Set,url:!1,session:!1,stuff:!1,dependencies:new Set},loaded:null,stuff:w};function R(y){const{href:v}=new URL(y,u);m.uses.dependencies.add(v)}$&&m.uses.dependencies.add(u.href);const U={};for(const y in h)Object.defineProperty(U,y,{get(){return m.uses.params.add(y),h[y]},enumerable:!0});const A=Ae;if(g.load){const y={routeId:_,params:U,props:$||{},get url(){return m.uses.url=!0,new Proxy(u,{get:(b,k)=>{if(k==="hash")throw new Error("url.hash is inaccessible from load. Consider accessing hash from the page store within the script tag of your component.");return Reflect.get(b,k,b)}})},get session(){return m.uses.session=!0,A},get stuff(){return m.uses.stuff=!0,x({},w)},async fetch(b,k){let O;typeof b=="string"?O=b:(O=b.url,k=x({body:b.method==="GET"||b.method==="HEAD"?void 0:await b.blob(),cache:b.cache,credentials:b.credentials,headers:b.headers,integrity:b.integrity,keepalive:b.keepalive,method:b.method,mode:b.mode,redirect:b.redirect,referrer:b.referrer,referrerPolicy:b.referrerPolicy,signal:b.signal},k));const S=new URL(O,u).href;return R(S),d?Le(S,k):jt(O,k)},status:o!=null?o:null,error:p!=null?p:null};let v;if(v=await g.load.call(null,y),!v)throw new Error("load function must return a value");m.loaded=Fe(v),m.loaded.stuff&&(m.stuff=m.loaded.stuff),m.loaded.dependencies&&m.loaded.dependencies.forEach(R)}else $&&(m.loaded=Fe({props:$}));return m}async function Te({id:o,url:p,params:g,route:u},h){var b,k,O;if(s.id===o&&s.promise)return s.promise;if(!h){const S=l.get(o);if(S)return S}const{a:w,b:$,has_shadow:_}=u,m=a.url&&{url:o!==a.url.pathname+a.url.search,params:Object.keys(g).filter(S=>a.params[S]!==g[S]),session:Z!==a.session_id};let R=[],U=et,A=!1,y=200,v=null;w.forEach(S=>S().catch(()=>{}));e:for(let S=0;SD.uses.params.has(Y))||m.session&&D.uses.session||Array.from(D.uses.dependencies).some(Y=>c.some(fe=>fe(Y)))||A&&D.uses.stuff){let Y={};const fe=_&&S===w.length-1;if(fe){const ne=await Le(`${p.pathname}${p.pathname.endsWith("/")?"":"/"}__data.json${p.search}`,{headers:{"x-sveltekit-load":"true"}});if(ne.ok){const De=ne.headers.get("x-sveltekit-location");if(De)return{redirect:De,props:{},state:a};Y=ne.status===204?{}:await ne.json()}else y=ne.status,v=new Error("Failed to load data")}if(v||(P=await Q({module:N,url:p,params:g,props:Y,stuff:U,routeId:u.id})),P&&(fe&&(P.uses.url=!0),P.loaded)){if(P.loaded.error&&(y=P.loaded.status,v=P.loaded.error),P.loaded.redirect)return{redirect:P.loaded.redirect,props:{},state:a};P.loaded.stuff&&(A=!0)}}else P=D}catch(N){y=500,v=Me(N)}if(v){for(;S--;)if($[S]){let N,D,le=S;for(;!(D=R[le]);)le-=1;try{if(N=await Q({status:y,error:v,module:await $[S](),url:p,params:g,stuff:D.stuff,routeId:u.id}),(b=N==null?void 0:N.loaded)!=null&&b.error)continue;(k=N==null?void 0:N.loaded)!=null&&k.stuff&&(U=x(x({},U),N.loaded.stuff)),R=R.slice(0,le+1).concat(N);break e}catch{continue}}return await ee({status:y,error:v,url:p,routeId:u.id})}else(O=P==null?void 0:P.loaded)!=null&&O.stuff&&(U=x(x({},U),P.loaded.stuff)),R.push(P)}return await be({url:p,params:g,stuff:U,branch:R,status:y,error:v,routeId:u.id})}async function ee({status:o,error:p,url:g,routeId:u}){var _,m;const h={},w=await Q({module:await Jt,url:g,params:h,stuff:{},routeId:u}),$=await Q({status:o,error:p,module:await Kt,url:g,params:h,stuff:w&&w.loaded&&w.loaded.stuff||{},routeId:u});return await be({url:g,params:h,stuff:x(x({},(_=w==null?void 0:w.loaded)==null?void 0:_.stuff),(m=$==null?void 0:$.loaded)==null?void 0:m.stuff),branch:[w,$],status:o,error:p,routeId:u})}function Ie(o){if(o.origin!==location.origin||!o.pathname.startsWith(t))return;const p=decodeURI(o.pathname.slice(t.length)||"/");for(const g of ke){const u=g.exec(p);if(u)return{id:o.pathname+o.search,route:g,params:u,url:o}}}async function ye({url:o,scroll:p,keepfocus:g,redirect_chain:u,details:h,accepted:w,blocked:$}){const _=a.url;let m=!1;const R={from:_,to:o,cancel:()=>m=!0};if(i.before_navigate.forEach(y=>y(R)),m){$();return}const U=Ct(o.pathname,r),A=new URL(o.origin+U+o.search+o.hash);Ee(j),w(),d&&f.navigating.set({from:a.url,to:A}),await we(A,u,!1,{scroll:p,keepfocus:g,details:h},()=>{const y={from:_,to:A};i.after_navigate.forEach(v=>v(y)),f.navigating.set(null)})}function te(o){return location.href=o.href,new Promise(()=>{})}return{after_navigate:o=>{Re(()=>(i.after_navigate.push(o),()=>{const p=i.after_navigate.indexOf(o);i.after_navigate.splice(p,1)}))},before_navigate:o=>{Re(()=>(i.before_navigate.push(o),()=>{const p=i.before_navigate.indexOf(o);i.before_navigate.splice(p,1)}))},disable_scroll_handling:()=>{(E||!d)&&(L=!1)},goto:(o,p={})=>Ne(o,p,[]),invalidate:o=>{if(typeof o=="function")c.push(o);else{const{href:p}=new URL(o,location.href);c.push(g=>g===p)}return F||(F=Promise.resolve().then(async()=>{await we(new URL(location.href),[],!0),F=null})),F},prefetch:async o=>{const p=new URL(o,Xe(document));await xe(p)},prefetch_routes:async o=>{const g=(o?ke.filter(u=>o.some(h=>u.exec(h))):ke).map(u=>Promise.all(u.a.map(h=>h())));await Promise.all(g)},_start_router:()=>{history.scrollRestoration="manual",addEventListener("beforeunload",u=>{let h=!1;const w={from:a.url,to:null,cancel:()=>h=!0};i.before_navigate.forEach($=>$(w)),h?(u.preventDefault(),u.returnValue=""):history.scrollRestoration="auto"}),addEventListener("visibilitychange",()=>{if(document.visibilityState==="hidden"){Ee(j);try{sessionStorage[st]=JSON.stringify(re)}catch{}}});const o=u=>{const h=He(u);h&&h.href&&h.hasAttribute("sveltekit:prefetch")&&xe(Ze(h))};let p;const g=u=>{clearTimeout(p),p=setTimeout(()=>{var h;(h=u.target)==null||h.dispatchEvent(new CustomEvent("sveltekit:trigger_prefetch",{bubbles:!0}))},20)};addEventListener("touchstart",o),addEventListener("mousemove",g),addEventListener("sveltekit:trigger_prefetch",o),addEventListener("click",u=>{if(!X||u.button||u.which!==1||u.metaKey||u.ctrlKey||u.shiftKey||u.altKey||u.defaultPrevented)return;const h=He(u);if(!h||!h.href)return;const w=h instanceof SVGAElement,$=Ze(h);if(!w&&$.origin==="null")return;const _=(h.getAttribute("rel")||"").split(/\s+/);if(h.hasAttribute("download")||_.includes("external")||h.hasAttribute("sveltekit:reload")||(w?h.target.baseVal:h.target))return;const[m,R]=$.href.split("#");if(R!==void 0&&m===location.href.split("#")[0]){me=!0,Ee(j),f.page.set(se(x({},ge),{url:$})),f.page.notify();return}ye({url:$,scroll:h.hasAttribute("sveltekit:noscroll")?Se():null,keepfocus:!1,redirect_chain:[],details:{state:{},replaceState:$.href===location.href},accepted:()=>u.preventDefault(),blocked:()=>u.preventDefault()})}),addEventListener("popstate",u=>{if(u.state&&X){if(u.state[W]===j)return;ye({url:new URL(location.href),scroll:re[u.state[W]],keepfocus:!1,redirect_chain:[],details:null,accepted:()=>{j=u.state[W]},blocked:()=>{const h=j-u.state[W];history.go(h)}})}}),addEventListener("hashchange",()=>{me&&(me=!1,history.replaceState(se(x({},history.state),{[W]:++j}),"",location.href))})},_hydrate:async({status:o,error:p,nodes:g,params:u,routeId:h})=>{const w=new URL(location.href),$=[];let _={},m,R;try{for(let U=0;Ue in n?rt(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t,x=(n,e)=>{for(var t in e||(e={}))ze.call(e,t)&&Ve(n,t,e[t]);if(ue)for(var t of ue(e))qe.call(e,t)&&Ve(n,t,e[t]);return n},se=(n,e)=>it(n,at(e));var Je=(n,e)=>{var t={};for(var r in n)ze.call(n,r)&&e.indexOf(r)<0&&(t[r]=n[r]);if(n!=null&&ue)for(var r of ue(n))e.indexOf(r)<0&&qe.call(n,r)&&(t[r]=n[r]);return t};import{s as tt,n as ve,S as ot,i as ct,e as lt,c as ft,a as ut,d as V,b as $e,f as B,g as z,t as dt,h as pt,j as ht,k as _t,l as C,m as mt,o as G,p as T,q as M,r as I,u as gt,v as wt,w as Re,x as q,y as ie,z as J,A as ae,B as oe,C as K,D as ce,E as Ke}from"./chunks/index-e18ba743.js";const H=[];function pe(n,e=ve){let t;const r=new Set;function l(s){if(tt(n,s)&&(n=s,t)){const i=!H.length;for(const a of r)a[1](),H.push(a,n);if(i){for(let a=0;a{r.delete(a),r.size===0&&(t(),t=null)}}return{set:l,update:c,subscribe:f}}let Be="",nt="";function bt(n){Be=n.base,nt=n.assets||Be}function yt(n){let e,t,r;const l=[n[1]||{}];var c=n[0][0];function f(s){let i={};for(let a=0;a{K(d,1)}),M()}c?(e=new c(f()),q(e.$$.fragment),I(e.$$.fragment,1),J(e,t.parentNode,t)):e=null}else c&&e.$set(a)},i(s){r||(e&&I(e.$$.fragment,s),r=!0)},o(s){e&&T(e.$$.fragment,s),r=!1},d(s){s&&V(t),e&&K(e,s)}}}function vt(n){let e,t,r;const l=[n[1]||{}];var c=n[0][0];function f(s){let i={$$slots:{default:[Rt]},$$scope:{ctx:s}};for(let a=0;a{K(d,1)}),M()}c?(e=new c(f(s)),q(e.$$.fragment),I(e.$$.fragment,1),J(e,t.parentNode,t)):e=null}else c&&e.$set(a)},i(s){r||(e&&I(e.$$.fragment,s),r=!0)},o(s){e&&T(e.$$.fragment,s),r=!1},d(s){s&&V(t),e&&K(e,s)}}}function $t(n){let e,t,r;const l=[n[2]||{}];var c=n[0][1];function f(s){let i={};for(let a=0;a{K(d,1)}),M()}c?(e=new c(f()),q(e.$$.fragment),I(e.$$.fragment,1),J(e,t.parentNode,t)):e=null}else c&&e.$set(a)},i(s){r||(e&&I(e.$$.fragment,s),r=!0)},o(s){e&&T(e.$$.fragment,s),r=!1},d(s){s&&V(t),e&&K(e,s)}}}function kt(n){let e,t,r;const l=[n[2]||{}];var c=n[0][1];function f(s){let i={$$slots:{default:[Et]},$$scope:{ctx:s}};for(let a=0;a{K(d,1)}),M()}c?(e=new c(f(s)),q(e.$$.fragment),I(e.$$.fragment,1),J(e,t.parentNode,t)):e=null}else c&&e.$set(a)},i(s){r||(e&&I(e.$$.fragment,s),r=!0)},o(s){e&&T(e.$$.fragment,s),r=!1},d(s){s&&V(t),e&&K(e,s)}}}function Et(n){let e,t,r;const l=[n[3]||{}];var c=n[0][2];function f(s){let i={};for(let a=0;a{K(d,1)}),M()}c?(e=new c(f()),q(e.$$.fragment),I(e.$$.fragment,1),J(e,t.parentNode,t)):e=null}else c&&e.$set(a)},i(s){r||(e&&I(e.$$.fragment,s),r=!0)},o(s){e&&T(e.$$.fragment,s),r=!1},d(s){s&&V(t),e&&K(e,s)}}}function Rt(n){let e,t,r,l;const c=[kt,$t],f=[];function s(i,a){return i[0][2]?0:1}return e=s(n),t=f[e]=c[e](n),{c(){t.c(),r=C()},l(i){t.l(i),r=C()},m(i,a){f[e].m(i,a),z(i,r,a),l=!0},p(i,a){let d=e;e=s(i),e===d?f[e].p(i,a):(G(),T(f[d],1,1,()=>{f[d]=null}),M(),t=f[e],t?t.p(i,a):(t=f[e]=c[e](i),t.c()),I(t,1),t.m(r.parentNode,r))},i(i){l||(I(t),l=!0)},o(i){T(t),l=!1},d(i){f[e].d(i),i&&V(r)}}}function We(n){let e,t=n[5]&&Ye(n);return{c(){e=lt("div"),t&&t.c(),this.h()},l(r){e=ft(r,"DIV",{id:!0,"aria-live":!0,"aria-atomic":!0,style:!0});var l=ut(e);t&&t.l(l),l.forEach(V),this.h()},h(){$e(e,"id","svelte-announcer"),$e(e,"aria-live","assertive"),$e(e,"aria-atomic","true"),B(e,"position","absolute"),B(e,"left","0"),B(e,"top","0"),B(e,"clip","rect(0 0 0 0)"),B(e,"clip-path","inset(50%)"),B(e,"overflow","hidden"),B(e,"white-space","nowrap"),B(e,"width","1px"),B(e,"height","1px")},m(r,l){z(r,e,l),t&&t.m(e,null)},p(r,l){r[5]?t?t.p(r,l):(t=Ye(r),t.c(),t.m(e,null)):t&&(t.d(1),t=null)},d(r){r&&V(e),t&&t.d()}}}function Ye(n){let e;return{c(){e=dt(n[6])},l(t){e=pt(t,n[6])},m(t,r){z(t,e,r)},p(t,r){r&64&&ht(e,t[6])},d(t){t&&V(e)}}}function St(n){let e,t,r,l,c;const f=[vt,yt],s=[];function i(d,L){return d[0][1]?0:1}e=i(n),t=s[e]=f[e](n);let a=n[4]&&We(n);return{c(){t.c(),r=_t(),a&&a.c(),l=C()},l(d){t.l(d),r=mt(d),a&&a.l(d),l=C()},m(d,L){s[e].m(d,L),z(d,r,L),a&&a.m(d,L),z(d,l,L),c=!0},p(d,[L]){let E=e;e=i(d),e===E?s[e].p(d,L):(G(),T(s[E],1,1,()=>{s[E]=null}),M(),t=s[e],t?t.p(d,L):(t=s[e]=f[e](d),t.c()),I(t,1),t.m(r.parentNode,r)),d[4]?a?a.p(d,L):(a=We(d),a.c(),a.m(l.parentNode,l)):a&&(a.d(1),a=null)},i(d){c||(I(t),c=!0)},o(d){T(t),c=!1},d(d){s[e].d(d),d&&V(r),a&&a.d(d),d&&V(l)}}}function Lt(n,e,t){let{stores:r}=e,{page:l}=e,{components:c}=e,{props_0:f=null}=e,{props_1:s=null}=e,{props_2:i=null}=e;gt("__svelte__",r),wt(r.page.notify);let a=!1,d=!1,L=null;return Re(()=>{const E=r.page.subscribe(()=>{a&&(t(5,d=!0),t(6,L=document.title||"untitled page"))});return t(4,a=!0),E}),n.$$set=E=>{"stores"in E&&t(7,r=E.stores),"page"in E&&t(8,l=E.page),"components"in E&&t(0,c=E.components),"props_0"in E&&t(1,f=E.props_0),"props_1"in E&&t(2,s=E.props_1),"props_2"in E&&t(3,i=E.props_2)},n.$$.update=()=>{n.$$.dirty&384&&r.page.set(l)},[c,f,s,i,a,d,L,r,l]}class Ut extends ot{constructor(e){super(),ct(this,e,Lt,St,tt,{stores:7,page:8,components:0,props_0:1,props_1:2,props_2:3})}}const At="modulepreload",Ge={},Ot="/app/immutable/",de=function(e,t){return!t||t.length===0?e():Promise.all(t.map(r=>{if(r=`${Ot}${r}`,r in Ge)return;Ge[r]=!0;const l=r.endsWith(".css"),c=l?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${r}"]${c}`))return;const f=document.createElement("link");if(f.rel=l?"stylesheet":At,l||(f.as="script",f.crossOrigin=""),f.href=r,document.head.appendChild(f),l)return new Promise((s,i)=>{f.addEventListener("load",s),f.addEventListener("error",()=>i(new Error(`Unable to preload CSS for ${r}`)))})})).then(()=>e())},Pt={},he=[()=>de(()=>import("./layout.svelte-ab90e838.js"),["layout.svelte-ab90e838.js","chunks/index-e18ba743.js"]),()=>de(()=>import("./error.svelte-c6d9751f.js"),["error.svelte-c6d9751f.js","chunks/index-e18ba743.js"]),()=>de(()=>import("./pages/index.svelte-73518255.js"),["pages/index.svelte-73518255.js","assets/pages/index.svelte-56891da8.css","chunks/index-e18ba743.js","chunks/TopBar-b4235a47.js","assets/TopBar-58fadc1e.css"]),()=>de(()=>import("./pages/room.svelte-b5ceba1b.js"),["pages/room.svelte-b5ceba1b.js","assets/pages/room.svelte-a4d60193.css","chunks/index-e18ba743.js","chunks/TopBar-b4235a47.js","assets/TopBar-58fadc1e.css"])],Nt={"":[[0,2],[1]],room:[[0,3],[1]]};function xt(n){n.client}function Me(n){return n instanceof Error||n&&n.name&&n.message?n:new Error(JSON.stringify(n))}function Fe(n){if(n.fallthrough)throw new Error("fallthrough is no longer supported. Use matchers instead: https://kit.svelte.dev/docs/routing#advanced-routing-matching");if("maxage"in n)throw new Error("maxage should be replaced with cache: { maxage }");const e=n.status&&n.status>=400&&n.status<=599&&!n.redirect;if(n.error||e){const t=n.status;if(!n.error&&e)return{status:t||500,error:new Error};const r=typeof n.error=="string"?new Error(n.error):n.error;return r instanceof Error?!t||t<400||t>599?(console.warn('"error" returned from load() without a valid status code \u2014 defaulting to 500'),{status:500,error:r}):{status:t,error:r}:{status:500,error:new Error(`"error" property returned from load() must be a string or instance of Error, received type "${typeof r}"`)}}if(n.redirect){if(!n.status||Math.floor(n.status/100)!==3)throw new Error('"redirect" property returned from load() must be accompanied by a 3xx status code');if(typeof n.redirect!="string")throw new Error('"redirect" property returned from load() must be a string')}if(n.dependencies&&(!Array.isArray(n.dependencies)||n.dependencies.some(t=>typeof t!="string")))throw new Error('"dependencies" property returned from load() must be of type string[]');if(n.context)throw new Error('You are returning "context" from a load function. "context" was renamed to "stuff", please adjust your code accordingly.');return n}function Ct(n,e){return n==="/"||e==="ignore"?n:e==="never"?n.endsWith("/")?n.slice(0,-1):n:e==="always"&&!n.endsWith("/")?n+"/":n}function Xe(n){let e=n.baseURI;if(!e){const t=n.getElementsByTagName("base");e=t.length?t[0].href:n.URL}return e}function Se(){return{x:pageXOffset,y:pageYOffset}}function He(n){return n.composedPath().find(t=>t instanceof Node&&t.nodeName.toUpperCase()==="A")}function Ze(n){return n instanceof SVGAElement?new URL(n.href.baseVal,document.baseURI):new URL(n.href)}function Qe(n){const e=pe(n);let t=!0;function r(){t=!0,e.update(f=>f)}function l(f){t=!1,e.set(f)}function c(f){let s;return e.subscribe(i=>{(s===void 0||t&&i!==s)&&f(s=i)})}return{notify:r,set:l,subscribe:c}}function Tt(){const{set:n,subscribe:e}=pe(!1),t="1658242321512";let r;async function l(){clearTimeout(r);const f=await fetch(`${nt}/app/version.json`,{headers:{pragma:"no-cache","cache-control":"no-cache"}});if(f.ok){const{version:s}=await f.json(),i=s!==t;return i&&(n(!0),clearTimeout(r)),i}else throw new Error(`Version check failed: ${f.status}`)}return{subscribe:e,check:l}}function It(n){let e=5381,t=n.length;if(typeof n=="string")for(;t;)e=e*33^n.charCodeAt(--t);else for(;t;)e=e*33^n[--t];return(e>>>0).toString(36)}const Le=window.fetch;function jt(n,e){let r=`script[sveltekit\\:data-type="data"][sveltekit\\:data-url=${JSON.stringify(typeof n=="string"?n:n.url)}]`;e&&typeof e.body=="string"&&(r+=`[sveltekit\\:data-body="${It(e.body)}"]`);const l=document.querySelector(r);if(l&&l.textContent){const c=JSON.parse(l.textContent),{body:f}=c,s=Je(c,["body"]);return Promise.resolve(new Response(f,s))}return Le(n,e)}const Dt=/^(\.\.\.)?(\w+)(?:=(\w+))?$/;function Vt(n){const e=[],t=[];let r=!0;return{pattern:n===""?/^\/$/:new RegExp(`^${decodeURIComponent(n).split(/(?:@[a-zA-Z0-9_-]+)?(?:\/|$)/).map((c,f,s)=>{const i=/^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(c);if(i)return e.push(i[1]),t.push(i[2]),"(?:/(.*))?";const a=f===s.length-1;return c&&"/"+c.split(/\[(.+?)\]/).map((d,L)=>{if(L%2){const[,E,Z,F]=Dt.exec(d);return e.push(Z),t.push(F),E?"(.*?)":"([^/]+?)"}return a&&d.includes(".")&&(r=!1),d.normalize().replace(/%5[Bb]/g,"[").replace(/%5[Dd]/g,"]").replace(/#/g,"%23").replace(/\?/g,"%3F").replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}).join("")}).join("")}${r?"/?":""}$`),names:e,types:t}}function zt(n,e,t,r){const l={};for(let c=0;c{const{pattern:i,names:a,types:d}=Vt(l);return{id:l,exec:L=>{const E=i.exec(L);if(E)return zt(E,a,d,t)},a:c.map(L=>n[L]),b:f.map(L=>n[L]),has_shadow:!!s}})}const st="sveltekit:scroll",W="sveltekit:index",ke=qt(he,Nt,Pt),Jt=he[0](),Kt=he[1](),et={};let re={};try{re=JSON.parse(sessionStorage[st])}catch{}function Ee(n){re[n]=Se()}function Bt({target:n,session:e,base:t,trailing_slash:r}){var je;const l=new Map,c=[],f={url:Qe({}),page:Qe({}),navigating:pe(null),session:pe(e),updated:Tt()},s={id:null,promise:null},i={before_navigate:[],after_navigate:[]};let a={branch:[],error:null,session_id:0,stuff:et,url:null},d=!1,L=!0,E=!1,Z=1,F=null,Ue,Ae,Oe=!1;f.session.subscribe(async o=>{Ae=o,Oe&&(Z+=1,we(new URL(location.href),[],!0))}),Oe=!0;let X=!0,j=(je=history.state)==null?void 0:je[W];j||(j=Date.now(),history.replaceState(se(x({},history.state),{[W]:j}),"",location.href));const _e=re[j];_e&&(history.scrollRestoration="manual",scrollTo(_e.x,_e.y));let me=!1,ge,Pe;async function Ne(o,{noscroll:p=!1,replaceState:g=!1,keepfocus:u=!1,state:h={}},w){const $=new URL(o,Xe(document));if(X)return ye({url:$,scroll:p?Se():null,keepfocus:u,redirect_chain:w,details:{state:h,replaceState:g},accepted:()=>{},blocked:()=>{}});await te($)}async function xe(o){const p=Ie(o);if(!p)throw new Error("Attempted to prefetch a URL that does not belong to this app");return s.promise=Te(p,!1),s.id=p.id,s.promise}async function we(o,p,g,u,h){var R,U,A;const w=Ie(o),$=Pe={};let _=w&&await Te(w,g);if(!_&&o.origin===location.origin&&o.pathname===location.pathname&&(_=await ee({status:404,error:new Error(`Not found: ${o.pathname}`),url:o,routeId:null})),!_)return await te(o),!1;if(Pe!==$)return!1;if(c.length=0,_.redirect)if(p.length>10||p.includes(o.pathname))_=await ee({status:500,error:new Error("Redirect loop"),url:o,routeId:null});else return X?Ne(new URL(_.redirect,o).href,{},[...p,o.pathname]):await te(new URL(_.redirect,location.href)),!1;else((U=(R=_.props)==null?void 0:R.page)==null?void 0:U.status)>=400&&await f.updated.check()&&await te(o);if(E=!0,u&&u.details){const{details:y}=u,v=y.replaceState?0:1;y.state[W]=j+=v,history[y.replaceState?"replaceState":"pushState"](y.state,"",o)}if(d?(a=_.state,_.props.page&&(_.props.page.url=o),Ue.$set(_.props)):Ce(_),u){const{scroll:y,keepfocus:v}=u;if(!v){const b=document.body,k=b.getAttribute("tabindex");(A=getSelection())==null||A.removeAllRanges(),b.tabIndex=-1,b.focus({preventScroll:!0}),k!==null?b.setAttribute("tabindex",k):b.removeAttribute("tabindex")}if(await Ke(),L){const b=o.hash&&document.getElementById(o.hash.slice(1));y?scrollTo(y.x,y.y):b?b.scrollIntoView():scrollTo(0,0)}}else await Ke();s.promise=null,s.id=null,L=!0,_.props.page&&(ge=_.props.page);const m=_.state.branch[_.state.branch.length-1];X=(m==null?void 0:m.module.router)!==!1,h&&h(),E=!1}function Ce(o){a=o.state;const p=document.querySelector("style[data-sveltekit]");if(p&&p.remove(),ge=o.props.page,Ue=new Ut({target:n,props:se(x({},o.props),{stores:f}),hydrate:!0}),X){const g={from:null,to:new URL(location.href)};i.after_navigate.forEach(u=>u(g))}d=!0}async function be({url:o,params:p,stuff:g,branch:u,status:h,error:w,routeId:$}){var v,b;const _=u.filter(Boolean),m=_.find(k=>{var O;return(O=k.loaded)==null?void 0:O.redirect}),R={redirect:(v=m==null?void 0:m.loaded)==null?void 0:v.redirect,state:{url:o,params:p,branch:u,error:w,stuff:g,session_id:Z},props:{components:_.map(k=>k.module.default)}};for(let k=0;k<_.length;k+=1){const O=_[k].loaded;R.props[`props_${k}`]=O?await O.props:null}if(!a.url||o.href!==a.url.href||a.error!==w||a.stuff!==g){R.props.page={error:w,params:p,routeId:$,status:h,stuff:g,url:o};const k=(O,S)=>{Object.defineProperty(R.props.page,O,{get:()=>{throw new Error(`$page.${O} has been replaced by $page.url.${S}`)}})};k("origin","origin"),k("path","pathname"),k("query","searchParams")}const A=_[_.length-1],y=(b=A==null?void 0:A.loaded)==null?void 0:b.cache;if(y){const k=o.pathname+o.search;let O=!1;const S=()=>{l.get(k)===R&&l.delete(k),N(),clearTimeout(P)},P=setTimeout(S,y.maxage*1e3),N=f.session.subscribe(()=>{O&&S()});O=!0,l.set(k,R)}return R}async function Q({status:o,error:p,module:g,url:u,params:h,stuff:w,props:$,routeId:_}){const m={module:g,uses:{params:new Set,url:!1,session:!1,stuff:!1,dependencies:new Set},loaded:null,stuff:w};function R(y){const{href:v}=new URL(y,u);m.uses.dependencies.add(v)}$&&m.uses.dependencies.add(u.href);const U={};for(const y in h)Object.defineProperty(U,y,{get(){return m.uses.params.add(y),h[y]},enumerable:!0});const A=Ae;if(g.load){const y={routeId:_,params:U,props:$||{},get url(){return m.uses.url=!0,new Proxy(u,{get:(b,k)=>{if(k==="hash")throw new Error("url.hash is inaccessible from load. Consider accessing hash from the page store within the script tag of your component.");return Reflect.get(b,k,b)}})},get session(){return m.uses.session=!0,A},get stuff(){return m.uses.stuff=!0,x({},w)},async fetch(b,k){let O;typeof b=="string"?O=b:(O=b.url,k=x({body:b.method==="GET"||b.method==="HEAD"?void 0:await b.blob(),cache:b.cache,credentials:b.credentials,headers:b.headers,integrity:b.integrity,keepalive:b.keepalive,method:b.method,mode:b.mode,redirect:b.redirect,referrer:b.referrer,referrerPolicy:b.referrerPolicy,signal:b.signal},k));const S=new URL(O,u).href;return R(S),d?Le(S,k):jt(O,k)},status:o!=null?o:null,error:p!=null?p:null};let v;if(v=await g.load.call(null,y),!v)throw new Error("load function must return a value");m.loaded=Fe(v),m.loaded.stuff&&(m.stuff=m.loaded.stuff),m.loaded.dependencies&&m.loaded.dependencies.forEach(R)}else $&&(m.loaded=Fe({props:$}));return m}async function Te({id:o,url:p,params:g,route:u},h){var b,k,O;if(s.id===o&&s.promise)return s.promise;if(!h){const S=l.get(o);if(S)return S}const{a:w,b:$,has_shadow:_}=u,m=a.url&&{url:o!==a.url.pathname+a.url.search,params:Object.keys(g).filter(S=>a.params[S]!==g[S]),session:Z!==a.session_id};let R=[],U=et,A=!1,y=200,v=null;w.forEach(S=>S().catch(()=>{}));e:for(let S=0;SD.uses.params.has(Y))||m.session&&D.uses.session||Array.from(D.uses.dependencies).some(Y=>c.some(fe=>fe(Y)))||A&&D.uses.stuff){let Y={};const fe=_&&S===w.length-1;if(fe){const ne=await Le(`${p.pathname}${p.pathname.endsWith("/")?"":"/"}__data.json${p.search}`,{headers:{"x-sveltekit-load":"true"}});if(ne.ok){const De=ne.headers.get("x-sveltekit-location");if(De)return{redirect:De,props:{},state:a};Y=ne.status===204?{}:await ne.json()}else y=ne.status,v=new Error("Failed to load data")}if(v||(P=await Q({module:N,url:p,params:g,props:Y,stuff:U,routeId:u.id})),P&&(fe&&(P.uses.url=!0),P.loaded)){if(P.loaded.error&&(y=P.loaded.status,v=P.loaded.error),P.loaded.redirect)return{redirect:P.loaded.redirect,props:{},state:a};P.loaded.stuff&&(A=!0)}}else P=D}catch(N){y=500,v=Me(N)}if(v){for(;S--;)if($[S]){let N,D,le=S;for(;!(D=R[le]);)le-=1;try{if(N=await Q({status:y,error:v,module:await $[S](),url:p,params:g,stuff:D.stuff,routeId:u.id}),(b=N==null?void 0:N.loaded)!=null&&b.error)continue;(k=N==null?void 0:N.loaded)!=null&&k.stuff&&(U=x(x({},U),N.loaded.stuff)),R=R.slice(0,le+1).concat(N);break e}catch{continue}}return await ee({status:y,error:v,url:p,routeId:u.id})}else(O=P==null?void 0:P.loaded)!=null&&O.stuff&&(U=x(x({},U),P.loaded.stuff)),R.push(P)}return await be({url:p,params:g,stuff:U,branch:R,status:y,error:v,routeId:u.id})}async function ee({status:o,error:p,url:g,routeId:u}){var _,m;const h={},w=await Q({module:await Jt,url:g,params:h,stuff:{},routeId:u}),$=await Q({status:o,error:p,module:await Kt,url:g,params:h,stuff:w&&w.loaded&&w.loaded.stuff||{},routeId:u});return await be({url:g,params:h,stuff:x(x({},(_=w==null?void 0:w.loaded)==null?void 0:_.stuff),(m=$==null?void 0:$.loaded)==null?void 0:m.stuff),branch:[w,$],status:o,error:p,routeId:u})}function Ie(o){if(o.origin!==location.origin||!o.pathname.startsWith(t))return;const p=decodeURI(o.pathname.slice(t.length)||"/");for(const g of ke){const u=g.exec(p);if(u)return{id:o.pathname+o.search,route:g,params:u,url:o}}}async function ye({url:o,scroll:p,keepfocus:g,redirect_chain:u,details:h,accepted:w,blocked:$}){const _=a.url;let m=!1;const R={from:_,to:o,cancel:()=>m=!0};if(i.before_navigate.forEach(y=>y(R)),m){$();return}const U=Ct(o.pathname,r),A=new URL(o.origin+U+o.search+o.hash);Ee(j),w(),d&&f.navigating.set({from:a.url,to:A}),await we(A,u,!1,{scroll:p,keepfocus:g,details:h},()=>{const y={from:_,to:A};i.after_navigate.forEach(v=>v(y)),f.navigating.set(null)})}function te(o){return location.href=o.href,new Promise(()=>{})}return{after_navigate:o=>{Re(()=>(i.after_navigate.push(o),()=>{const p=i.after_navigate.indexOf(o);i.after_navigate.splice(p,1)}))},before_navigate:o=>{Re(()=>(i.before_navigate.push(o),()=>{const p=i.before_navigate.indexOf(o);i.before_navigate.splice(p,1)}))},disable_scroll_handling:()=>{(E||!d)&&(L=!1)},goto:(o,p={})=>Ne(o,p,[]),invalidate:o=>{if(typeof o=="function")c.push(o);else{const{href:p}=new URL(o,location.href);c.push(g=>g===p)}return F||(F=Promise.resolve().then(async()=>{await we(new URL(location.href),[],!0),F=null})),F},prefetch:async o=>{const p=new URL(o,Xe(document));await xe(p)},prefetch_routes:async o=>{const g=(o?ke.filter(u=>o.some(h=>u.exec(h))):ke).map(u=>Promise.all(u.a.map(h=>h())));await Promise.all(g)},_start_router:()=>{history.scrollRestoration="manual",addEventListener("beforeunload",u=>{let h=!1;const w={from:a.url,to:null,cancel:()=>h=!0};i.before_navigate.forEach($=>$(w)),h?(u.preventDefault(),u.returnValue=""):history.scrollRestoration="auto"}),addEventListener("visibilitychange",()=>{if(document.visibilityState==="hidden"){Ee(j);try{sessionStorage[st]=JSON.stringify(re)}catch{}}});const o=u=>{const h=He(u);h&&h.href&&h.hasAttribute("sveltekit:prefetch")&&xe(Ze(h))};let p;const g=u=>{clearTimeout(p),p=setTimeout(()=>{var h;(h=u.target)==null||h.dispatchEvent(new CustomEvent("sveltekit:trigger_prefetch",{bubbles:!0}))},20)};addEventListener("touchstart",o),addEventListener("mousemove",g),addEventListener("sveltekit:trigger_prefetch",o),addEventListener("click",u=>{if(!X||u.button||u.which!==1||u.metaKey||u.ctrlKey||u.shiftKey||u.altKey||u.defaultPrevented)return;const h=He(u);if(!h||!h.href)return;const w=h instanceof SVGAElement,$=Ze(h);if(!w&&$.origin==="null")return;const _=(h.getAttribute("rel")||"").split(/\s+/);if(h.hasAttribute("download")||_.includes("external")||h.hasAttribute("sveltekit:reload")||(w?h.target.baseVal:h.target))return;const[m,R]=$.href.split("#");if(R!==void 0&&m===location.href.split("#")[0]){me=!0,Ee(j),f.page.set(se(x({},ge),{url:$})),f.page.notify();return}ye({url:$,scroll:h.hasAttribute("sveltekit:noscroll")?Se():null,keepfocus:!1,redirect_chain:[],details:{state:{},replaceState:$.href===location.href},accepted:()=>u.preventDefault(),blocked:()=>u.preventDefault()})}),addEventListener("popstate",u=>{if(u.state&&X){if(u.state[W]===j)return;ye({url:new URL(location.href),scroll:re[u.state[W]],keepfocus:!1,redirect_chain:[],details:null,accepted:()=>{j=u.state[W]},blocked:()=>{const h=j-u.state[W];history.go(h)}})}}),addEventListener("hashchange",()=>{me&&(me=!1,history.replaceState(se(x({},history.state),{[W]:++j}),"",location.href))})},_hydrate:async({status:o,error:p,nodes:g,params:u,routeId:h})=>{const w=new URL(location.href),$=[];let _={},m,R;try{for(let U=0;ULANFS

LANFS


Welcome!

To get started, enter a new or existing room name...