chore(release): 0.2.6 v0.2.6
authorxangelo <me@xangelo.ca>
Wed, 9 Aug 2023 14:55:12 +0000 (10:55 -0400)
committerxangelo <me@xangelo.ca>
Wed, 9 Aug 2023 14:55:12 +0000 (10:55 -0400)
31 files changed:
CHANGELOG.md
migrations/20230808185745_armour-icons.ts [new file with mode: 0644]
package-lock.json
package.json
public/assets/bundle.js
public/assets/css/game.css
public/assets/img/icons/equipment/arm_t_02.PNG [new file with mode: 0755]
public/assets/img/icons/equipment/boot_t_02.png [new file with mode: 0755]
public/assets/img/icons/equipment/gl_t_07.png [new file with mode: 0755]
public/assets/img/icons/equipment/hlm_t_02.png [new file with mode: 0755]
public/assets/img/icons/equipment/pn_t_06.png [new file with mode: 0644]
public/index.html
seeds/shop_items.ts
src/client/chat.ts [deleted file]
src/client/custom-discord.ts [deleted file]
src/client/discord.ts [deleted file]
src/client/events.ts [deleted file]
src/client/htmx.ts
src/client/http.ts [deleted file]
src/client/index.ts [deleted file]
src/client/modal.ts [deleted file]
src/client/socket-event.client.ts [deleted file]
src/server/api.ts
src/server/auth.ts
src/server/inventory.ts
src/server/locations/healer/index.ts
src/server/views/fight.ts
src/server/views/inventory.ts
src/server/views/profile.ts
src/server/views/stores.ts
src/shared/inventory.ts

index 2be61f50b3fb18631a435f3ad63e93936733e540..b953fe83e4fddcd43e266d6c497470822c761f0e 100644 (file)
@@ -2,6 +2,16 @@
 
 All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
 
 
 All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
 
+### [0.2.6](https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff;h=v0.2.6;hp=v0.2.5;ds=sidebyside) (2023-08-09)
+
+
+### Bug Fixes
+
+* armour icon support 4f6823d
+* auto-load player object and place in request 7079401
+* chat history calls clearing chat 0d1626c
+* migrate stat increase to htmx 734e42d
+
 ### [0.2.5](https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff;h=v0.2.5;hp=v0.2.4;ds=sidebyside) (2023-08-05)
 
 
 ### [0.2.5](https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff;h=v0.2.5;hp=v0.2.4;ds=sidebyside) (2023-08-05)
 
 
diff --git a/migrations/20230808185745_armour-icons.ts b/migrations/20230808185745_armour-icons.ts
new file mode 100644 (file)
index 0000000..561d155
--- /dev/null
@@ -0,0 +1,20 @@
+import { Knex } from "knex";
+
+
+export async function up(knex: Knex): Promise<void> {
+  return knex.schema.alterTable('shop_equipment', function(table) {
+    table.string('icon').defaultTo('');
+  }).alterTable('inventory', function(table) {
+    table.string('icon').defaultTo('');
+  });
+}
+
+
+export async function down(knex: Knex): Promise<void> {
+  return knex.schema.alterTable('shop_equipment', function(table) {
+    table.dropColumn('icon');
+  }).alterTable('inventory', function(table) {
+    table.dropColumn('icon');
+  });
+}
+
index 3d3fe4720bd3f2ae384dbef35209f46916973d08..edf339e29d5cb2e3917fc2d57a82d0b296992d60 100644 (file)
@@ -1,12 +1,12 @@
 {
   "name": "rising-legends",
 {
   "name": "rising-legends",
-  "version": "0.2.5",
+  "version": "0.2.6",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "rising-legends",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "rising-legends",
-      "version": "0.2.5",
+      "version": "0.2.6",
       "dependencies": {
         "@honeycombio/opentelemetry-node": "^0.4.0",
         "@opentelemetry/auto-instrumentations-node": "^0.37.0",
       "dependencies": {
         "@honeycombio/opentelemetry-node": "^0.4.0",
         "@opentelemetry/auto-instrumentations-node": "^0.37.0",
index 7e36845b0dc2a820b285aba76bd4d9ffc70c6bdb..5166e73e2a7f08da9431bbb7d8994a96e9fd945d 100644 (file)
@@ -1,7 +1,7 @@
 {
   "name": "rising-legends",
   "private": true,
 {
   "name": "rising-legends",
   "private": true,
-  "version": "0.2.5",
+  "version": "0.2.6",
   "scripts": {
     "up": "npx prisma migrate dev --name \"init\"",
     "start": "pm2 start dist/server/api.js",
   "scripts": {
     "up": "npx prisma migrate dev --name \"init\"",
     "start": "pm2 start dist/server/api.js",
index 239b458de5390913d98e61adf20e4645916541ff..ecebb9cc9e16b8d78be72d2a0e8fc17dad8db3e7 100644 (file)
@@ -1 +1 @@
-(()=>{var e={802:(e,t,s)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const s="color: "+this.color;t.splice(1,0,s,"color: inherit");let n=0,r=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(n++,"%c"===e&&(r=n))})),t.splice(r,0,s)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=s(804)(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},804:(e,t,s)=>{e.exports=function(e){function t(e){let s,r,o,i=null;function a(...e){if(!a.enabled)return;const n=a,r=Number(new Date),o=r-(s||r);n.diff=o,n.prev=s,n.curr=r,s=r,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((s,r)=>{if("%%"===s)return"%";i++;const o=t.formatters[r];if("function"==typeof o){const t=e[i];s=o.call(n,t),e.splice(i,1),i--}return s})),t.formatArgs.call(n,e),(n.log||t.log).apply(n,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=n,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(r!==t.namespaces&&(r=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(a),a}function n(e,s){const n=t(this.namespace+(void 0===s?":":s)+e);return n.log=this.log,n}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let s;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").split(/[\s,]+/),r=n.length;for(s=0;s<r;s++)n[s]&&("-"===(e=n[s].replace(/\*/g,".*?"))[0]?t.skips.push(new RegExp("^"+e.slice(1)+"$")):t.names.push(new RegExp("^"+e+"$")))},t.enabled=function(e){if("*"===e[e.length-1])return!0;let s,n;for(s=0,n=t.skips.length;s<n;s++)if(t.skips[s].test(e))return!1;for(s=0,n=t.names.length;s<n;s++)if(t.names[s].test(e))return!0;return!1},t.humanize=s(810),t.destroy=function(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")},Object.keys(e).forEach((s=>{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t<e.length;t++)s=(s<<5)-s+e.charCodeAt(t),s|=0;return t.colors[Math.abs(s)%t.colors.length]},t.enable(t.load()),t}},810:e=>{var t=1e3,s=60*t,n=60*s,r=24*n;function o(e,t,s,n){var r=t>=1.5*s;return Math.round(e/s)+" "+n+(r?"s":"")}e.exports=function(e,i){i=i||{};var a,c,u=typeof e;if("string"===u&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(o){var i=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"weeks":case"week":case"w":return 6048e5*i;case"days":case"day":case"d":return i*r;case"hours":case"hour":case"hrs":case"hr":case"h":return i*n;case"minutes":case"minute":case"mins":case"min":case"m":return i*s;case"seconds":case"second":case"secs":case"sec":case"s":return i*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}}}(e);if("number"===u&&isFinite(e))return i.long?(a=e,(c=Math.abs(a))>=r?o(a,c,r,"day"):c>=n?o(a,c,n,"hour"):c>=s?o(a,c,s,"minute"):c>=t?o(a,c,t,"second"):a+" ms"):function(e){var o=Math.abs(e);return o>=r?Math.round(e/r)+"d":o>=n?Math.round(e/n)+"h":o>=s?Math.round(e/s)+"m":o>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},669:(e,t,s)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const s="color: "+this.color;t.splice(1,0,s,"color: inherit");let n=0,r=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(n++,"%c"===e&&(r=n))})),t.splice(r,0,s)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=s(231)(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},231:(e,t,s)=>{e.exports=function(e){function t(e){let s,r,o,i=null;function a(...e){if(!a.enabled)return;const n=a,r=Number(new Date),o=r-(s||r);n.diff=o,n.prev=s,n.curr=r,s=r,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((s,r)=>{if("%%"===s)return"%";i++;const o=t.formatters[r];if("function"==typeof o){const t=e[i];s=o.call(n,t),e.splice(i,1),i--}return s})),t.formatArgs.call(n,e),(n.log||t.log).apply(n,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=n,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(r!==t.namespaces&&(r=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(a),a}function n(e,s){const n=t(this.namespace+(void 0===s?":":s)+e);return n.log=this.log,n}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let s;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").split(/[\s,]+/),r=n.length;for(s=0;s<r;s++)n[s]&&("-"===(e=n[s].replace(/\*/g,".*?"))[0]?t.skips.push(new RegExp("^"+e.slice(1)+"$")):t.names.push(new RegExp("^"+e+"$")))},t.enabled=function(e){if("*"===e[e.length-1])return!0;let s,n;for(s=0,n=t.skips.length;s<n;s++)if(t.skips[s].test(e))return!1;for(s=0,n=t.names.length;s<n;s++)if(t.names[s].test(e))return!0;return!1},t.humanize=s(241),t.destroy=function(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")},Object.keys(e).forEach((s=>{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t<e.length;t++)s=(s<<5)-s+e.charCodeAt(t),s|=0;return t.colors[Math.abs(s)%t.colors.length]},t.enable(t.load()),t}},241:e=>{var t=1e3,s=60*t,n=60*s,r=24*n;function o(e,t,s,n){var r=t>=1.5*s;return Math.round(e/s)+" "+n+(r?"s":"")}e.exports=function(e,i){i=i||{};var a,c,u=typeof e;if("string"===u&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(o){var i=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"weeks":case"week":case"w":return 6048e5*i;case"days":case"day":case"d":return i*r;case"hours":case"hour":case"hrs":case"hr":case"h":return i*n;case"minutes":case"minute":case"mins":case"min":case"m":return i*s;case"seconds":case"second":case"secs":case"sec":case"s":return i*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}}}(e);if("number"===u&&isFinite(e))return i.long?(a=e,(c=Math.abs(a))>=r?o(a,c,r,"day"):c>=n?o(a,c,n,"hour"):c>=s?o(a,c,s,"minute"):c>=t?o(a,c,t,"second"):a+" ms"):function(e){var o=Math.abs(e);return o>=r?Math.round(e/r)+"d":o>=n?Math.round(e/n)+"h":o>=s?Math.round(e/s)+"m":o>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},618:(e,t,s)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const s="color: "+this.color;t.splice(1,0,s,"color: inherit");let n=0,r=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(n++,"%c"===e&&(r=n))})),t.splice(r,0,s)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=s(224)(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},224:(e,t,s)=>{e.exports=function(e){function t(e){let s,r,o,i=null;function a(...e){if(!a.enabled)return;const n=a,r=Number(new Date),o=r-(s||r);n.diff=o,n.prev=s,n.curr=r,s=r,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((s,r)=>{if("%%"===s)return"%";i++;const o=t.formatters[r];if("function"==typeof o){const t=e[i];s=o.call(n,t),e.splice(i,1),i--}return s})),t.formatArgs.call(n,e),(n.log||t.log).apply(n,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=n,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(r!==t.namespaces&&(r=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(a),a}function n(e,s){const n=t(this.namespace+(void 0===s?":":s)+e);return n.log=this.log,n}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let s;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").split(/[\s,]+/),r=n.length;for(s=0;s<r;s++)n[s]&&("-"===(e=n[s].replace(/\*/g,".*?"))[0]?t.skips.push(new RegExp("^"+e.slice(1)+"$")):t.names.push(new RegExp("^"+e+"$")))},t.enabled=function(e){if("*"===e[e.length-1])return!0;let s,n;for(s=0,n=t.skips.length;s<n;s++)if(t.skips[s].test(e))return!1;for(s=0,n=t.names.length;s<n;s++)if(t.names[s].test(e))return!0;return!1},t.humanize=s(896),t.destroy=function(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")},Object.keys(e).forEach((s=>{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t<e.length;t++)s=(s<<5)-s+e.charCodeAt(t),s|=0;return t.colors[Math.abs(s)%t.colors.length]},t.enable(t.load()),t}},896:e=>{var t=1e3,s=60*t,n=60*s,r=24*n;function o(e,t,s,n){var r=t>=1.5*s;return Math.round(e/s)+" "+n+(r?"s":"")}e.exports=function(e,i){i=i||{};var a,c,u=typeof e;if("string"===u&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(o){var i=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"weeks":case"week":case"w":return 6048e5*i;case"days":case"day":case"d":return i*r;case"hours":case"hour":case"hrs":case"hr":case"h":return i*n;case"minutes":case"minute":case"mins":case"min":case"m":return i*s;case"seconds":case"second":case"secs":case"sec":case"s":return i*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}}}(e);if("number"===u&&isFinite(e))return i.long?(a=e,(c=Math.abs(a))>=r?o(a,c,r,"day"):c>=n?o(a,c,n,"hour"):c>=s?o(a,c,s,"minute"):c>=t?o(a,c,t,"second"):a+" ms"):function(e){var o=Math.abs(e);return o>=r?Math.round(e/r)+"d":o>=n?Math.round(e/n)+"h":o>=s?Math.round(e/s)+"m":o>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},336:(e,t)=>{"use strict";let s;function n(e,t=document){return t.querySelector(e)}function r(e){n("#chat-messages").innerHTML+=`<div class="chat-message" title="${new Date(parseInt(e.sentAt))}" id="${e.id}">\n                             <span class="from">${e.from}</span>\n                             <span class="message">${e.msg}</span>\n                             </div>`,n("#chat-messages").scrollTop=n("#chat-messages").scrollHeight}Object.defineProperty(t,"__esModule",{value:!0}),t.configureChat=void 0,t.configureChat=function(e){s=e,s.on("chat",r),console.log("Chat Configured")}},862:function(e,t){"use strict";var s=this&&this.__awaiter||function(e,t,s,n){return new(s||(s=Promise))((function(r,o){function i(e){try{c(n.next(e))}catch(e){o(e)}}function a(e){try{c(n.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?r(e.value):(t=e.value,t instanceof s?t:new s((function(e){e(t)}))).then(i,a)}c((n=n.apply(e,t||[])).next())}))};function n(){return localStorage.getItem("authToken")}Object.defineProperty(t,"__esModule",{value:!0}),t.http=t.authToken=void 0,t.authToken=n,t.http={get:e=>s(void 0,void 0,void 0,(function*(){return(yield fetch(e,{headers:{"x-authtoken":n()}})).json()})),post:(e,t)=>s(void 0,void 0,void 0,(function*(){const s=yield fetch(e,{method:"post",body:JSON.stringify(t),headers:{"x-authtoken":n(),"content-type":"application/json"}});try{return s.json()}catch(e){return console.log("No valid JSON response"),null}}))}},182:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TimeManager=void 0,t.TimeManager=class{constructor(e=120){this.dayLength=e,this.scaleFactor=30,this.dayLengthAsMS=60*e*1e3}dayScaleFactor(){return this.dayLength/30}getTimePeriod(){return this.isMorning()?"morning":this.isAfternoon()?"afternoon":this.isEvening()?"evening":this.isNight()?"night":void 0}getAmPm(){return this.get24Hour()<12?"am":"pm"}get24Hour(){const e=new Date,t=(e.getMinutes()+e.getHours()%2*(this.dayLength/2))/this.dayLength;return Math.floor(24*t)}getHour(){const e=(new Date).getMinutes()/this.dayLength,t=Math.floor(24*e);return t>12?t-12:t}gradientName(){const e=Math.floor(this.get24Hour()/24*this.scaleFactor);return`sky-gradient-${e<10?"0":""}${e}`}isNight(){const e=this.get24Hour();return e>=0&&e<5||e>=21&&e<24}isMorning(){const e=this.get24Hour();return e>=5&&e<12}isAfternoon(){const e=this.get24Hour();return e>=12&&e<18}isEvening(){const e=this.get24Hour();return e>=18&&e<21}}},419:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.hasCORS=void 0;let s=!1;try{s="undefined"!=typeof XMLHttpRequest&&"withCredentials"in new XMLHttpRequest}catch(e){}t.hasCORS=s},754:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decode=t.encode=void 0,t.encode=function(e){let t="";for(let s in e)e.hasOwnProperty(s)&&(t.length&&(t+="&"),t+=encodeURIComponent(s)+"="+encodeURIComponent(e[s]));return t},t.decode=function(e){let t={},s=e.split("&");for(let e=0,n=s.length;e<n;e++){let n=s[e].split("=");t[decodeURIComponent(n[0])]=decodeURIComponent(n[1])}return t}},222:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.parse=void 0;const s=/^(?:(?![^:@\/?#]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@\/?#]*)(?::([^:@\/?#]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,n=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];t.parse=function(e){const t=e,r=e.indexOf("["),o=e.indexOf("]");-1!=r&&-1!=o&&(e=e.substring(0,r)+e.substring(r,o).replace(/:/g,";")+e.substring(o,e.length));let i=s.exec(e||""),a={},c=14;for(;c--;)a[n[c]]=i[c]||"";return-1!=r&&-1!=o&&(a.source=t,a.host=a.host.substring(1,a.host.length-1).replace(/;/g,":"),a.authority=a.authority.replace("[","").replace("]","").replace(/;/g,":"),a.ipv6uri=!0),a.pathNames=function(e,t){const s=t.replace(/\/{2,9}/g,"/").split("/");return"/"!=t.slice(0,1)&&0!==t.length||s.splice(0,1),"/"==t.slice(-1)&&s.splice(s.length-1,1),s}(0,a.path),a.queryKey=function(e,t){const s={};return t.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,(function(e,t,n){t&&(s[t]=n)})),s}(0,a.query),a}},726:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.yeast=t.decode=t.encode=void 0;const s="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(""),n={};let r,o=0,i=0;function a(e){let t="";do{t=s[e%64]+t,e=Math.floor(e/64)}while(e>0);return t}for(t.encode=a,t.decode=function(e){let t=0;for(i=0;i<e.length;i++)t=64*t+n[e.charAt(i)];return t},t.yeast=function(){const e=a(+new Date);return e!==r?(o=0,r=e):e+"."+a(o++)};i<64;i++)n[s[i]]=i},242:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.globalThisShim=void 0,t.globalThisShim="undefined"!=typeof self?self:"undefined"!=typeof window?window:Function("return this")()},679:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.nextTick=t.parse=t.installTimerFunctions=t.transports=t.Transport=t.protocol=t.Socket=void 0;const n=s(481);Object.defineProperty(t,"Socket",{enumerable:!0,get:function(){return n.Socket}}),t.protocol=n.Socket.protocol;var r=s(870);Object.defineProperty(t,"Transport",{enumerable:!0,get:function(){return r.Transport}});var o=s(385);Object.defineProperty(t,"transports",{enumerable:!0,get:function(){return o.transports}});var i=s(622);Object.defineProperty(t,"installTimerFunctions",{enumerable:!0,get:function(){return i.installTimerFunctions}});var a=s(222);Object.defineProperty(t,"parse",{enumerable:!0,get:function(){return a.parse}});var c=s(552);Object.defineProperty(t,"nextTick",{enumerable:!0,get:function(){return c.nextTick}})},481:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Socket=void 0;const r=s(385),o=s(622),i=s(754),a=s(222),c=n(s(802)),u=s(260),h=s(373),l=(0,c.default)("engine.io-client:socket");class d extends u.Emitter{constructor(e,t={}){super(),this.writeBuffer=[],e&&"object"==typeof e&&(t=e,e=null),e?(e=(0,a.parse)(e),t.hostname=e.host,t.secure="https"===e.protocol||"wss"===e.protocol,t.port=e.port,e.query&&(t.query=e.query)):t.host&&(t.hostname=(0,a.parse)(t.host).host),(0,o.installTimerFunctions)(this,t),this.secure=null!=t.secure?t.secure:"undefined"!=typeof location&&"https:"===location.protocol,t.hostname&&!t.port&&(t.port=this.secure?"443":"80"),this.hostname=t.hostname||("undefined"!=typeof location?location.hostname:"localhost"),this.port=t.port||("undefined"!=typeof location&&location.port?location.port:this.secure?"443":"80"),this.transports=t.transports||["polling","websocket"],this.writeBuffer=[],this.prevBufferLen=0,this.opts=Object.assign({path:"/engine.io",agent:!1,withCredentials:!1,upgrade:!0,timestampParam:"t",rememberUpgrade:!1,addTrailingSlash:!0,rejectUnauthorized:!0,perMessageDeflate:{threshold:1024},transportOptions:{},closeOnBeforeunload:!0},t),this.opts.path=this.opts.path.replace(/\/$/,"")+(this.opts.addTrailingSlash?"/":""),"string"==typeof this.opts.query&&(this.opts.query=(0,i.decode)(this.opts.query)),this.id=null,this.upgrades=null,this.pingInterval=null,this.pingTimeout=null,this.pingTimeoutTimer=null,"function"==typeof addEventListener&&(this.opts.closeOnBeforeunload&&(this.beforeunloadEventListener=()=>{this.transport&&(this.transport.removeAllListeners(),this.transport.close())},addEventListener("beforeunload",this.beforeunloadEventListener,!1)),"localhost"!==this.hostname&&(this.offlineEventListener=()=>{this.onClose("transport close",{description:"network connection lost"})},addEventListener("offline",this.offlineEventListener,!1))),this.open()}createTransport(e){l('creating transport "%s"',e);const t=Object.assign({},this.opts.query);t.EIO=h.protocol,t.transport=e,this.id&&(t.sid=this.id);const s=Object.assign({},this.opts.transportOptions[e],this.opts,{query:t,socket:this,hostname:this.hostname,secure:this.secure,port:this.port});return l("options: %j",s),new r.transports[e](s)}open(){let e;if(this.opts.rememberUpgrade&&d.priorWebsocketSuccess&&-1!==this.transports.indexOf("websocket"))e="websocket";else{if(0===this.transports.length)return void this.setTimeoutFn((()=>{this.emitReserved("error","No transports available")}),0);e=this.transports[0]}this.readyState="opening";try{e=this.createTransport(e)}catch(e){return l("error while creating transport: %s",e),this.transports.shift(),void this.open()}e.open(),this.setTransport(e)}setTransport(e){l("setting transport %s",e.name),this.transport&&(l("clearing existing transport %s",this.transport.name),this.transport.removeAllListeners()),this.transport=e,e.on("drain",this.onDrain.bind(this)).on("packet",this.onPacket.bind(this)).on("error",this.onError.bind(this)).on("close",(e=>this.onClose("transport close",e)))}probe(e){l('probing transport "%s"',e);let t=this.createTransport(e),s=!1;d.priorWebsocketSuccess=!1;const n=()=>{s||(l('probe transport "%s" opened',e),t.send([{type:"ping",data:"probe"}]),t.once("packet",(n=>{if(!s)if("pong"===n.type&&"probe"===n.data){if(l('probe transport "%s" pong',e),this.upgrading=!0,this.emitReserved("upgrading",t),!t)return;d.priorWebsocketSuccess="websocket"===t.name,l('pausing current transport "%s"',this.transport.name),this.transport.pause((()=>{s||"closed"!==this.readyState&&(l("changing transport and sending upgrade packet"),u(),this.setTransport(t),t.send([{type:"upgrade"}]),this.emitReserved("upgrade",t),t=null,this.upgrading=!1,this.flush())}))}else{l('probe transport "%s" failed',e);const s=new Error("probe error");s.transport=t.name,this.emitReserved("upgradeError",s)}})))};function r(){s||(s=!0,u(),t.close(),t=null)}const o=s=>{const n=new Error("probe error: "+s);n.transport=t.name,r(),l('probe transport "%s" failed because of error: %s',e,s),this.emitReserved("upgradeError",n)};function i(){o("transport closed")}function a(){o("socket closed")}function c(e){t&&e.name!==t.name&&(l('"%s" works - aborting "%s"',e.name,t.name),r())}const u=()=>{t.removeListener("open",n),t.removeListener("error",o),t.removeListener("close",i),this.off("close",a),this.off("upgrading",c)};t.once("open",n),t.once("error",o),t.once("close",i),this.once("close",a),this.once("upgrading",c),t.open()}onOpen(){if(l("socket open"),this.readyState="open",d.priorWebsocketSuccess="websocket"===this.transport.name,this.emitReserved("open"),this.flush(),"open"===this.readyState&&this.opts.upgrade){l("starting upgrade probes");let e=0;const t=this.upgrades.length;for(;e<t;e++)this.probe(this.upgrades[e])}}onPacket(e){if("opening"===this.readyState||"open"===this.readyState||"closing"===this.readyState)switch(l('socket receive: type "%s", data "%s"',e.type,e.data),this.emitReserved("packet",e),this.emitReserved("heartbeat"),e.type){case"open":this.onHandshake(JSON.parse(e.data));break;case"ping":this.resetPingTimeout(),this.sendPacket("pong"),this.emitReserved("ping"),this.emitReserved("pong");break;case"error":const t=new Error("server error");t.code=e.data,this.onError(t);break;case"message":this.emitReserved("data",e.data),this.emitReserved("message",e.data)}else l('packet received with socket readyState "%s"',this.readyState)}onHandshake(e){this.emitReserved("handshake",e),this.id=e.sid,this.transport.query.sid=e.sid,this.upgrades=this.filterUpgrades(e.upgrades),this.pingInterval=e.pingInterval,this.pingTimeout=e.pingTimeout,this.maxPayload=e.maxPayload,this.onOpen(),"closed"!==this.readyState&&this.resetPingTimeout()}resetPingTimeout(){this.clearTimeoutFn(this.pingTimeoutTimer),this.pingTimeoutTimer=this.setTimeoutFn((()=>{this.onClose("ping timeout")}),this.pingInterval+this.pingTimeout),this.opts.autoUnref&&this.pingTimeoutTimer.unref()}onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBufferLen=0,0===this.writeBuffer.length?this.emitReserved("drain"):this.flush()}flush(){if("closed"!==this.readyState&&this.transport.writable&&!this.upgrading&&this.writeBuffer.length){const e=this.getWritablePackets();l("flushing %d packets in socket",e.length),this.transport.send(e),this.prevBufferLen=e.length,this.emitReserved("flush")}}getWritablePackets(){if(!(this.maxPayload&&"polling"===this.transport.name&&this.writeBuffer.length>1))return this.writeBuffer;let e=1;for(let t=0;t<this.writeBuffer.length;t++){const s=this.writeBuffer[t].data;if(s&&(e+=(0,o.byteLength)(s)),t>0&&e>this.maxPayload)return l("only send %d out of %d packets",t,this.writeBuffer.length),this.writeBuffer.slice(0,t);e+=2}return l("payload size is %d (max: %d)",e,this.maxPayload),this.writeBuffer}write(e,t,s){return this.sendPacket("message",e,t,s),this}send(e,t,s){return this.sendPacket("message",e,t,s),this}sendPacket(e,t,s,n){if("function"==typeof t&&(n=t,t=void 0),"function"==typeof s&&(n=s,s=null),"closing"===this.readyState||"closed"===this.readyState)return;(s=s||{}).compress=!1!==s.compress;const r={type:e,data:t,options:s};this.emitReserved("packetCreate",r),this.writeBuffer.push(r),n&&this.once("flush",n),this.flush()}close(){const e=()=>{this.onClose("forced close"),l("socket closing - telling transport to close"),this.transport.close()},t=()=>{this.off("upgrade",t),this.off("upgradeError",t),e()},s=()=>{this.once("upgrade",t),this.once("upgradeError",t)};return"opening"!==this.readyState&&"open"!==this.readyState||(this.readyState="closing",this.writeBuffer.length?this.once("drain",(()=>{this.upgrading?s():e()})):this.upgrading?s():e()),this}onError(e){l("socket error %j",e),d.priorWebsocketSuccess=!1,this.emitReserved("error",e),this.onClose("transport error",e)}onClose(e,t){"opening"!==this.readyState&&"open"!==this.readyState&&"closing"!==this.readyState||(l('socket close with reason: "%s"',e),this.clearTimeoutFn(this.pingTimeoutTimer),this.transport.removeAllListeners("close"),this.transport.close(),this.transport.removeAllListeners(),"function"==typeof removeEventListener&&(removeEventListener("beforeunload",this.beforeunloadEventListener,!1),removeEventListener("offline",this.offlineEventListener,!1)),this.readyState="closed",this.id=null,this.emitReserved("close",e,t),this.writeBuffer=[],this.prevBufferLen=0)}filterUpgrades(e){const t=[];let s=0;const n=e.length;for(;s<n;s++)~this.transports.indexOf(e[s])&&t.push(e[s]);return t}}t.Socket=d,d.protocol=h.protocol},870:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Transport=void 0;const r=s(373),o=s(260),i=s(622),a=(0,n(s(802)).default)("engine.io-client:transport");class c extends Error{constructor(e,t,s){super(e),this.description=t,this.context=s,this.type="TransportError"}}class u extends o.Emitter{constructor(e){super(),this.writable=!1,(0,i.installTimerFunctions)(this,e),this.opts=e,this.query=e.query,this.socket=e.socket}onError(e,t,s){return super.emitReserved("error",new c(e,t,s)),this}open(){return this.readyState="opening",this.doOpen(),this}close(){return"opening"!==this.readyState&&"open"!==this.readyState||(this.doClose(),this.onClose()),this}send(e){"open"===this.readyState?this.write(e):a("transport is not open, discarding packets")}onOpen(){this.readyState="open",this.writable=!0,super.emitReserved("open")}onData(e){const t=(0,r.decodePacket)(e,this.socket.binaryType);this.onPacket(t)}onPacket(e){super.emitReserved("packet",e)}onClose(e){this.readyState="closed",super.emitReserved("close",e)}pause(e){}}t.Transport=u},385:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.transports=void 0;const n=s(484),r=s(308);t.transports={websocket:r.WS,polling:n.Polling}},484:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Request=t.Polling=void 0;const r=s(870),o=n(s(802)),i=s(726),a=s(754),c=s(373),u=s(666),h=s(260),l=s(622),d=s(242),p=(0,o.default)("engine.io-client:polling");function f(){}const g=null!=new u.XHR({xdomain:!1}).responseType;class m extends r.Transport{constructor(e){if(super(e),this.polling=!1,"undefined"!=typeof location){const t="https:"===location.protocol;let s=location.port;s||(s=t?"443":"80"),this.xd="undefined"!=typeof location&&e.hostname!==location.hostname||s!==e.port,this.xs=e.secure!==t}const t=e&&e.forceBase64;this.supportsBinary=g&&!t}get name(){return"polling"}doOpen(){this.poll()}pause(e){this.readyState="pausing";const t=()=>{p("paused"),this.readyState="paused",e()};if(this.polling||!this.writable){let e=0;this.polling&&(p("we are currently polling - waiting to pause"),e++,this.once("pollComplete",(function(){p("pre-pause polling complete"),--e||t()}))),this.writable||(p("we are currently writing - waiting to pause"),e++,this.once("drain",(function(){p("pre-pause writing complete"),--e||t()})))}else t()}poll(){p("polling"),this.polling=!0,this.doPoll(),this.emitReserved("poll")}onData(e){p("polling got data %s",e),(0,c.decodePayload)(e,this.socket.binaryType).forEach((e=>{if("opening"===this.readyState&&"open"===e.type&&this.onOpen(),"close"===e.type)return this.onClose({description:"transport closed by the server"}),!1;this.onPacket(e)})),"closed"!==this.readyState&&(this.polling=!1,this.emitReserved("pollComplete"),"open"===this.readyState?this.poll():p('ignoring poll - transport state "%s"',this.readyState))}doClose(){const e=()=>{p("writing close packet"),this.write([{type:"close"}])};"open"===this.readyState?(p("transport open - closing"),e()):(p("transport not open - deferring close"),this.once("open",e))}write(e){this.writable=!1,(0,c.encodePayload)(e,(e=>{this.doWrite(e,(()=>{this.writable=!0,this.emitReserved("drain")}))}))}uri(){let e=this.query||{};const t=this.opts.secure?"https":"http";let s="";!1!==this.opts.timestampRequests&&(e[this.opts.timestampParam]=(0,i.yeast)()),this.supportsBinary||e.sid||(e.b64=1),this.opts.port&&("https"===t&&443!==Number(this.opts.port)||"http"===t&&80!==Number(this.opts.port))&&(s=":"+this.opts.port);const n=(0,a.encode)(e);return t+"://"+(-1!==this.opts.hostname.indexOf(":")?"["+this.opts.hostname+"]":this.opts.hostname)+s+this.opts.path+(n.length?"?"+n:"")}request(e={}){return Object.assign(e,{xd:this.xd,xs:this.xs},this.opts),new y(this.uri(),e)}doWrite(e,t){const s=this.request({method:"POST",data:e});s.on("success",t),s.on("error",((e,t)=>{this.onError("xhr post error",e,t)}))}doPoll(){p("xhr poll");const e=this.request();e.on("data",this.onData.bind(this)),e.on("error",((e,t)=>{this.onError("xhr poll error",e,t)})),this.pollXhr=e}}t.Polling=m;class y extends h.Emitter{constructor(e,t){super(),(0,l.installTimerFunctions)(this,t),this.opts=t,this.method=t.method||"GET",this.uri=e,this.async=!1!==t.async,this.data=void 0!==t.data?t.data:null,this.create()}create(){const e=(0,l.pick)(this.opts,"agent","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","autoUnref");e.xdomain=!!this.opts.xd,e.xscheme=!!this.opts.xs;const t=this.xhr=new u.XHR(e);try{p("xhr open %s: %s",this.method,this.uri),t.open(this.method,this.uri,this.async);try{if(this.opts.extraHeaders){t.setDisableHeaderCheck&&t.setDisableHeaderCheck(!0);for(let e in this.opts.extraHeaders)this.opts.extraHeaders.hasOwnProperty(e)&&t.setRequestHeader(e,this.opts.extraHeaders[e])}}catch(e){}if("POST"===this.method)try{t.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(e){}try{t.setRequestHeader("Accept","*/*")}catch(e){}"withCredentials"in t&&(t.withCredentials=this.opts.withCredentials),this.opts.requestTimeout&&(t.timeout=this.opts.requestTimeout),t.onreadystatechange=()=>{4===t.readyState&&(200===t.status||1223===t.status?this.onLoad():this.setTimeoutFn((()=>{this.onError("number"==typeof t.status?t.status:0)}),0))},p("xhr data %s",this.data),t.send(this.data)}catch(e){return void this.setTimeoutFn((()=>{this.onError(e)}),0)}"undefined"!=typeof document&&(this.index=y.requestsCount++,y.requests[this.index]=this)}onError(e){this.emitReserved("error",e,this.xhr),this.cleanup(!0)}cleanup(e){if(void 0!==this.xhr&&null!==this.xhr){if(this.xhr.onreadystatechange=f,e)try{this.xhr.abort()}catch(e){}"undefined"!=typeof document&&delete y.requests[this.index],this.xhr=null}}onLoad(){const e=this.xhr.responseText;null!==e&&(this.emitReserved("data",e),this.emitReserved("success"),this.cleanup())}abort(){this.cleanup()}}if(t.Request=y,y.requestsCount=0,y.requests={},"undefined"!=typeof document)if("function"==typeof attachEvent)attachEvent("onunload",C);else if("function"==typeof addEventListener){const e="onpagehide"in d.globalThisShim?"pagehide":"unload";addEventListener(e,C,!1)}function C(){for(let e in y.requests)y.requests.hasOwnProperty(e)&&y.requests[e].abort()}},552:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.defaultBinaryType=t.usingBrowserWebSocket=t.WebSocket=t.nextTick=void 0;const n=s(242);t.nextTick="function"==typeof Promise&&"function"==typeof Promise.resolve?e=>Promise.resolve().then(e):(e,t)=>t(e,0),t.WebSocket=n.globalThisShim.WebSocket||n.globalThisShim.MozWebSocket,t.usingBrowserWebSocket=!0,t.defaultBinaryType="arraybuffer"},308:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.WS=void 0;const r=s(870),o=s(754),i=s(726),a=s(622),c=s(552),u=n(s(802)),h=s(373),l=(0,u.default)("engine.io-client:websocket"),d="undefined"!=typeof navigator&&"string"==typeof navigator.product&&"reactnative"===navigator.product.toLowerCase();class p extends r.Transport{constructor(e){super(e),this.supportsBinary=!e.forceBase64}get name(){return"websocket"}doOpen(){if(!this.check())return;const e=this.uri(),t=this.opts.protocols,s=d?{}:(0,a.pick)(this.opts,"agent","perMessageDeflate","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","localAddress","protocolVersion","origin","maxPayload","family","checkServerIdentity");this.opts.extraHeaders&&(s.headers=this.opts.extraHeaders);try{this.ws=c.usingBrowserWebSocket&&!d?t?new c.WebSocket(e,t):new c.WebSocket(e):new c.WebSocket(e,t,s)}catch(e){return this.emitReserved("error",e)}this.ws.binaryType=this.socket.binaryType||c.defaultBinaryType,this.addEventListeners()}addEventListeners(){this.ws.onopen=()=>{this.opts.autoUnref&&this.ws._socket.unref(),this.onOpen()},this.ws.onclose=e=>this.onClose({description:"websocket connection closed",context:e}),this.ws.onmessage=e=>this.onData(e.data),this.ws.onerror=e=>this.onError("websocket error",e)}write(e){this.writable=!1;for(let t=0;t<e.length;t++){const s=e[t],n=t===e.length-1;(0,h.encodePacket)(s,this.supportsBinary,(e=>{const t={};!c.usingBrowserWebSocket&&(s.options&&(t.compress=s.options.compress),this.opts.perMessageDeflate)&&("string"==typeof e?Buffer.byteLength(e):e.length)<this.opts.perMessageDeflate.threshold&&(t.compress=!1);try{c.usingBrowserWebSocket?this.ws.send(e):this.ws.send(e,t)}catch(e){l("websocket closed before onclose event")}n&&(0,c.nextTick)((()=>{this.writable=!0,this.emitReserved("drain")}),this.setTimeoutFn)}))}}doClose(){void 0!==this.ws&&(this.ws.close(),this.ws=null)}uri(){let e=this.query||{};const t=this.opts.secure?"wss":"ws";let s="";this.opts.port&&("wss"===t&&443!==Number(this.opts.port)||"ws"===t&&80!==Number(this.opts.port))&&(s=":"+this.opts.port),this.opts.timestampRequests&&(e[this.opts.timestampParam]=(0,i.yeast)()),this.supportsBinary||(e.b64=1);const n=(0,o.encode)(e);return t+"://"+(-1!==this.opts.hostname.indexOf(":")?"["+this.opts.hostname+"]":this.opts.hostname)+s+this.opts.path+(n.length?"?"+n:"")}check(){return!!c.WebSocket}}t.WS=p},666:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.XHR=void 0;const n=s(419),r=s(242);t.XHR=function(e){const t=e.xdomain;try{if("undefined"!=typeof XMLHttpRequest&&(!t||n.hasCORS))return new XMLHttpRequest}catch(e){}if(!t)try{return new(r.globalThisShim[["Active"].concat("Object").join("X")])("Microsoft.XMLHTTP")}catch(e){}}},622:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.byteLength=t.installTimerFunctions=t.pick=void 0;const n=s(242);t.pick=function(e,...t){return t.reduce(((t,s)=>(e.hasOwnProperty(s)&&(t[s]=e[s]),t)),{})};const r=n.globalThisShim.setTimeout,o=n.globalThisShim.clearTimeout;t.installTimerFunctions=function(e,t){t.useNativeTimers?(e.setTimeoutFn=r.bind(n.globalThisShim),e.clearTimeoutFn=o.bind(n.globalThisShim)):(e.setTimeoutFn=n.globalThisShim.setTimeout.bind(n.globalThisShim),e.clearTimeoutFn=n.globalThisShim.clearTimeout.bind(n.globalThisShim))},t.byteLength=function(e){return"string"==typeof e?function(e){let t=0,s=0;for(let n=0,r=e.length;n<r;n++)t=e.charCodeAt(n),t<128?s+=1:t<2048?s+=2:t<55296||t>=57344?s+=3:(n++,s+=4);return s}(e):Math.ceil(1.33*(e.byteLength||e.size))}},87:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ERROR_PACKET=t.PACKET_TYPES_REVERSE=t.PACKET_TYPES=void 0;const s=Object.create(null);t.PACKET_TYPES=s,s.open="0",s.close="1",s.ping="2",s.pong="3",s.message="4",s.upgrade="5",s.noop="6";const n=Object.create(null);t.PACKET_TYPES_REVERSE=n,Object.keys(s).forEach((e=>{n[s[e]]=e})),t.ERROR_PACKET={type:"error",data:"parser error"}},469:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decode=t.encode=void 0;const s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",n="undefined"==typeof Uint8Array?[]:new Uint8Array(256);for(let e=0;e<64;e++)n[s.charCodeAt(e)]=e;t.encode=e=>{let t,n=new Uint8Array(e),r=n.length,o="";for(t=0;t<r;t+=3)o+=s[n[t]>>2],o+=s[(3&n[t])<<4|n[t+1]>>4],o+=s[(15&n[t+1])<<2|n[t+2]>>6],o+=s[63&n[t+2]];return r%3==2?o=o.substring(0,o.length-1)+"=":r%3==1&&(o=o.substring(0,o.length-2)+"=="),o},t.decode=e=>{let t,s,r,o,i,a=.75*e.length,c=e.length,u=0;"="===e[e.length-1]&&(a--,"="===e[e.length-2]&&a--);const h=new ArrayBuffer(a),l=new Uint8Array(h);for(t=0;t<c;t+=4)s=n[e.charCodeAt(t)],r=n[e.charCodeAt(t+1)],o=n[e.charCodeAt(t+2)],i=n[e.charCodeAt(t+3)],l[u++]=s<<2|r>>4,l[u++]=(15&r)<<4|o>>2,l[u++]=(3&o)<<6|63&i;return h}},572:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=s(87),r=s(469),o="function"==typeof ArrayBuffer,i=(e,t)=>{if(o){const s=(0,r.decode)(e);return a(s,t)}return{base64:!0,data:e}},a=(e,t)=>"blob"===t&&e instanceof ArrayBuffer?new Blob([e]):e;t.default=(e,t)=>{if("string"!=typeof e)return{type:"message",data:a(e,t)};const s=e.charAt(0);return"b"===s?{type:"message",data:i(e.substring(1),t)}:n.PACKET_TYPES_REVERSE[s]?e.length>1?{type:n.PACKET_TYPES_REVERSE[s],data:e.substring(1)}:{type:n.PACKET_TYPES_REVERSE[s]}:n.ERROR_PACKET}},908:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=s(87),r="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===Object.prototype.toString.call(Blob),o="function"==typeof ArrayBuffer,i=(e,t)=>{const s=new FileReader;return s.onload=function(){const e=s.result.split(",")[1];t("b"+(e||""))},s.readAsDataURL(e)};t.default=({type:e,data:t},s,a)=>{return r&&t instanceof Blob?s?a(t):i(t,a):o&&(t instanceof ArrayBuffer||(c=t,"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(c):c&&c.buffer instanceof ArrayBuffer))?s?a(t):i(new Blob([t]),a):a(n.PACKET_TYPES[e]+(t||""));var c}},373:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decodePayload=t.decodePacket=t.encodePayload=t.encodePacket=t.protocol=void 0;const n=s(908);t.encodePacket=n.default;const r=s(572);t.decodePacket=r.default;const o=String.fromCharCode(30);t.encodePayload=(e,t)=>{const s=e.length,r=new Array(s);let i=0;e.forEach(((e,a)=>{(0,n.default)(e,!1,(e=>{r[a]=e,++i===s&&t(r.join(o))}))}))},t.decodePayload=(e,t)=>{const s=e.split(o),n=[];for(let e=0;e<s.length;e++){const o=(0,r.default)(s[e],t);if(n.push(o),"error"===o.type)break}return n},t.protocol=4},159:(e,t)=>{"use strict";function s(e){e=e||{},this.ms=e.min||100,this.max=e.max||1e4,this.factor=e.factor||2,this.jitter=e.jitter>0&&e.jitter<=1?e.jitter:0,this.attempts=0}Object.defineProperty(t,"__esModule",{value:!0}),t.Backoff=void 0,t.Backoff=s,s.prototype.duration=function(){var e=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var t=Math.random(),s=Math.floor(t*this.jitter*e);e=0==(1&Math.floor(10*t))?e-s:e+s}return 0|Math.min(e,this.max)},s.prototype.reset=function(){this.attempts=0},s.prototype.setMin=function(e){this.ms=e},s.prototype.setMax=function(e){this.max=e},s.prototype.setJitter=function(e){this.jitter=e}},46:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.connect=t.io=t.Socket=t.Manager=t.protocol=void 0;const r=s(84),o=s(168);Object.defineProperty(t,"Manager",{enumerable:!0,get:function(){return o.Manager}});const i=s(312);Object.defineProperty(t,"Socket",{enumerable:!0,get:function(){return i.Socket}});const a=n(s(669)).default("socket.io-client"),c={};function u(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};const s=r.url(e,t.path||"/socket.io"),n=s.source,i=s.id,u=s.path,h=c[i]&&u in c[i].nsps;let l;return t.forceNew||t["force new connection"]||!1===t.multiplex||h?(a("ignoring socket cache for %s",n),l=new o.Manager(n,t)):(c[i]||(a("new io instance for %s",n),c[i]=new o.Manager(n,t)),l=c[i]),s.query&&!t.query&&(t.query=s.queryKey),l.socket(s.path,t)}t.io=u,t.connect=u,t.default=u,Object.assign(u,{Manager:o.Manager,Socket:i.Socket,io:u,connect:u});var h=s(514);Object.defineProperty(t,"protocol",{enumerable:!0,get:function(){return h.protocol}}),e.exports=u},168:function(e,t,s){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,s,n){void 0===n&&(n=s),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[s]}})}:function(e,t,s,n){void 0===n&&(n=s),e[n]=t[s]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var s in e)"default"!==s&&Object.prototype.hasOwnProperty.call(e,s)&&n(t,e,s);return r(t,e),t},i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Manager=void 0;const a=s(679),c=s(312),u=o(s(514)),h=s(149),l=s(159),d=s(260),p=i(s(669)).default("socket.io-client:manager");class f extends d.Emitter{constructor(e,t){var s;super(),this.nsps={},this.subs=[],e&&"object"==typeof e&&(t=e,e=void 0),(t=t||{}).path=t.path||"/socket.io",this.opts=t,a.installTimerFunctions(this,t),this.reconnection(!1!==t.reconnection),this.reconnectionAttempts(t.reconnectionAttempts||1/0),this.reconnectionDelay(t.reconnectionDelay||1e3),this.reconnectionDelayMax(t.reconnectionDelayMax||5e3),this.randomizationFactor(null!==(s=t.randomizationFactor)&&void 0!==s?s:.5),this.backoff=new l.Backoff({min:this.reconnectionDelay(),max:this.reconnectionDelayMax(),jitter:this.randomizationFactor()}),this.timeout(null==t.timeout?2e4:t.timeout),this._readyState="closed",this.uri=e;const n=t.parser||u;this.encoder=new n.Encoder,this.decoder=new n.Decoder,this._autoConnect=!1!==t.autoConnect,this._autoConnect&&this.open()}reconnection(e){return arguments.length?(this._reconnection=!!e,this):this._reconnection}reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(this._reconnectionAttempts=e,this)}reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(this._reconnectionDelay=e,null===(t=this.backoff)||void 0===t||t.setMin(e),this)}randomizationFactor(e){var t;return void 0===e?this._randomizationFactor:(this._randomizationFactor=e,null===(t=this.backoff)||void 0===t||t.setJitter(e),this)}reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDelayMax:(this._reconnectionDelayMax=e,null===(t=this.backoff)||void 0===t||t.setMax(e),this)}timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===this.backoff.attempts&&this.reconnect()}open(e){if(p("readyState %s",this._readyState),~this._readyState.indexOf("open"))return this;p("opening %s",this.uri),this.engine=new a.Socket(this.uri,this.opts);const t=this.engine,s=this;this._readyState="opening",this.skipReconnect=!1;const n=h.on(t,"open",(function(){s.onopen(),e&&e()})),r=h.on(t,"error",(t=>{p("error"),s.cleanup(),s._readyState="closed",this.emitReserved("error",t),e?e(t):s.maybeReconnectOnOpen()}));if(!1!==this._timeout){const e=this._timeout;p("connect attempt will timeout after %d",e),0===e&&n();const s=this.setTimeoutFn((()=>{p("connect attempt timed out after %d",e),n(),t.close(),t.emit("error",new Error("timeout"))}),e);this.opts.autoUnref&&s.unref(),this.subs.push((function(){clearTimeout(s)}))}return this.subs.push(n),this.subs.push(r),this}connect(e){return this.open(e)}onopen(){p("open"),this.cleanup(),this._readyState="open",this.emitReserved("open");const e=this.engine;this.subs.push(h.on(e,"ping",this.onping.bind(this)),h.on(e,"data",this.ondata.bind(this)),h.on(e,"error",this.onerror.bind(this)),h.on(e,"close",this.onclose.bind(this)),h.on(this.decoder,"decoded",this.ondecoded.bind(this)))}onping(){this.emitReserved("ping")}ondata(e){try{this.decoder.add(e)}catch(e){this.onclose("parse error",e)}}ondecoded(e){a.nextTick((()=>{this.emitReserved("packet",e)}),this.setTimeoutFn)}onerror(e){p("error",e),this.emitReserved("error",e)}socket(e,t){let s=this.nsps[e];return s?this._autoConnect&&!s.active&&s.connect():(s=new c.Socket(this,e,t),this.nsps[e]=s),s}_destroy(e){const t=Object.keys(this.nsps);for(const e of t)if(this.nsps[e].active)return void p("socket %s is still active, skipping close",e);this._close()}_packet(e){p("writing packet %j",e);const t=this.encoder.encode(e);for(let s=0;s<t.length;s++)this.engine.write(t[s],e.options)}cleanup(){p("cleanup"),this.subs.forEach((e=>e())),this.subs.length=0,this.decoder.destroy()}_close(){p("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,this.onclose("forced close"),this.engine&&this.engine.close()}disconnect(){return this._close()}onclose(e,t){p("closed due to %s",e),this.cleanup(),this.backoff.reset(),this._readyState="closed",this.emitReserved("close",e,t),this._reconnection&&!this.skipReconnect&&this.reconnect()}reconnect(){if(this._reconnecting||this.skipReconnect)return this;const e=this;if(this.backoff.attempts>=this._reconnectionAttempts)p("reconnect failed"),this.backoff.reset(),this.emitReserved("reconnect_failed"),this._reconnecting=!1;else{const t=this.backoff.duration();p("will wait %dms before reconnect attempt",t),this._reconnecting=!0;const s=this.setTimeoutFn((()=>{e.skipReconnect||(p("attempting reconnect"),this.emitReserved("reconnect_attempt",e.backoff.attempts),e.skipReconnect||e.open((t=>{t?(p("reconnect attempt error"),e._reconnecting=!1,e.reconnect(),this.emitReserved("reconnect_error",t)):(p("reconnect success"),e.onreconnect())})))}),t);this.opts.autoUnref&&s.unref(),this.subs.push((function(){clearTimeout(s)}))}}onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this.backoff.reset(),this.emitReserved("reconnect",e)}}t.Manager=f},149:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.on=void 0,t.on=function(e,t,s){return e.on(t,s),function(){e.off(t,s)}}},312:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Socket=void 0;const r=s(514),o=s(149),i=s(260),a=n(s(669)).default("socket.io-client:socket"),c=Object.freeze({connect:1,connect_error:1,disconnect:1,disconnecting:1,newListener:1,removeListener:1});class u extends i.Emitter{constructor(e,t,s){super(),this.connected=!1,this.recovered=!1,this.receiveBuffer=[],this.sendBuffer=[],this._queue=[],this._queueSeq=0,this.ids=0,this.acks={},this.flags={},this.io=e,this.nsp=t,s&&s.auth&&(this.auth=s.auth),this._opts=Object.assign({},s),this.io._autoConnect&&this.open()}get disconnected(){return!this.connected}subEvents(){if(this.subs)return;const e=this.io;this.subs=[o.on(e,"open",this.onopen.bind(this)),o.on(e,"packet",this.onpacket.bind(this)),o.on(e,"error",this.onerror.bind(this)),o.on(e,"close",this.onclose.bind(this))]}get active(){return!!this.subs}connect(){return this.connected||(this.subEvents(),this.io._reconnecting||this.io.open(),"open"===this.io._readyState&&this.onopen()),this}open(){return this.connect()}send(...e){return e.unshift("message"),this.emit.apply(this,e),this}emit(e,...t){if(c.hasOwnProperty(e))throw new Error('"'+e.toString()+'" is a reserved event name');if(t.unshift(e),this._opts.retries&&!this.flags.fromQueue&&!this.flags.volatile)return this._addToQueue(t),this;const s={type:r.PacketType.EVENT,data:t,options:{}};if(s.options.compress=!1!==this.flags.compress,"function"==typeof t[t.length-1]){const e=this.ids++;a("emitting packet with ack id %d",e);const n=t.pop();this._registerAckCallback(e,n),s.id=e}const n=this.io.engine&&this.io.engine.transport&&this.io.engine.transport.writable;return!this.flags.volatile||n&&this.connected?this.connected?(this.notifyOutgoingListeners(s),this.packet(s)):this.sendBuffer.push(s):a("discard packet as the transport is not currently writable"),this.flags={},this}_registerAckCallback(e,t){var s;const n=null!==(s=this.flags.timeout)&&void 0!==s?s:this._opts.ackTimeout;if(void 0===n)return void(this.acks[e]=t);const r=this.io.setTimeoutFn((()=>{delete this.acks[e];for(let t=0;t<this.sendBuffer.length;t++)this.sendBuffer[t].id===e&&(a("removing packet with ack id %d from the buffer",e),this.sendBuffer.splice(t,1));a("event with ack id %d has timed out after %d ms",e,n),t.call(this,new Error("operation has timed out"))}),n);this.acks[e]=(...e)=>{this.io.clearTimeoutFn(r),t.apply(this,[null,...e])}}emitWithAck(e,...t){const s=void 0!==this.flags.timeout||void 0!==this._opts.ackTimeout;return new Promise(((n,r)=>{t.push(((e,t)=>s?e?r(e):n(t):n(e))),this.emit(e,...t)}))}_addToQueue(e){let t;"function"==typeof e[e.length-1]&&(t=e.pop());const s={id:this._queueSeq++,tryCount:0,pending:!1,args:e,flags:Object.assign({fromQueue:!0},this.flags)};e.push(((e,...n)=>{if(s===this._queue[0])return null!==e?s.tryCount>this._opts.retries&&(a("packet [%d] is discarded after %d tries",s.id,s.tryCount),this._queue.shift(),t&&t(e)):(a("packet [%d] was successfully sent",s.id),this._queue.shift(),t&&t(null,...n)),s.pending=!1,this._drainQueue()})),this._queue.push(s),this._drainQueue()}_drainQueue(e=!1){if(a("draining queue"),!this.connected||0===this._queue.length)return;const t=this._queue[0];!t.pending||e?(t.pending=!0,t.tryCount++,a("sending packet [%d] (try n°%d)",t.id,t.tryCount),this.flags=t.flags,this.emit.apply(this,t.args)):a("packet [%d] has already been sent and is waiting for an ack",t.id)}packet(e){e.nsp=this.nsp,this.io._packet(e)}onopen(){a("transport is open - connecting"),"function"==typeof this.auth?this.auth((e=>{this._sendConnectPacket(e)})):this._sendConnectPacket(this.auth)}_sendConnectPacket(e){this.packet({type:r.PacketType.CONNECT,data:this._pid?Object.assign({pid:this._pid,offset:this._lastOffset},e):e})}onerror(e){this.connected||this.emitReserved("connect_error",e)}onclose(e,t){a("close (%s)",e),this.connected=!1,delete this.id,this.emitReserved("disconnect",e,t)}onpacket(e){if(e.nsp===this.nsp)switch(e.type){case r.PacketType.CONNECT:e.data&&e.data.sid?this.onconnect(e.data.sid,e.data.pid):this.emitReserved("connect_error",new Error("It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)"));break;case r.PacketType.EVENT:case r.PacketType.BINARY_EVENT:this.onevent(e);break;case r.PacketType.ACK:case r.PacketType.BINARY_ACK:this.onack(e);break;case r.PacketType.DISCONNECT:this.ondisconnect();break;case r.PacketType.CONNECT_ERROR:this.destroy();const t=new Error(e.data.message);t.data=e.data.data,this.emitReserved("connect_error",t)}}onevent(e){const t=e.data||[];a("emitting event %j",t),null!=e.id&&(a("attaching ack callback to event"),t.push(this.ack(e.id))),this.connected?this.emitEvent(t):this.receiveBuffer.push(Object.freeze(t))}emitEvent(e){if(this._anyListeners&&this._anyListeners.length){const t=this._anyListeners.slice();for(const s of t)s.apply(this,e)}super.emit.apply(this,e),this._pid&&e.length&&"string"==typeof e[e.length-1]&&(this._lastOffset=e[e.length-1])}ack(e){const t=this;let s=!1;return function(...n){s||(s=!0,a("sending ack %j",n),t.packet({type:r.PacketType.ACK,id:e,data:n}))}}onack(e){const t=this.acks[e.id];"function"==typeof t?(a("calling ack %s with %j",e.id,e.data),t.apply(this,e.data),delete this.acks[e.id]):a("bad ack %s",e.id)}onconnect(e,t){a("socket connected with id %s",e),this.id=e,this.recovered=t&&this._pid===t,this._pid=t,this.connected=!0,this.emitBuffered(),this.emitReserved("connect"),this._drainQueue(!0)}emitBuffered(){this.receiveBuffer.forEach((e=>this.emitEvent(e))),this.receiveBuffer=[],this.sendBuffer.forEach((e=>{this.notifyOutgoingListeners(e),this.packet(e)})),this.sendBuffer=[]}ondisconnect(){a("server disconnect (%s)",this.nsp),this.destroy(),this.onclose("io server disconnect")}destroy(){this.subs&&(this.subs.forEach((e=>e())),this.subs=void 0),this.io._destroy(this)}disconnect(){return this.connected&&(a("performing disconnect (%s)",this.nsp),this.packet({type:r.PacketType.DISCONNECT})),this.destroy(),this.connected&&this.onclose("io client disconnect"),this}close(){return this.disconnect()}compress(e){return this.flags.compress=e,this}get volatile(){return this.flags.volatile=!0,this}timeout(e){return this.flags.timeout=e,this}onAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.push(e),this}prependAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.unshift(e),this}offAny(e){if(!this._anyListeners)return this;if(e){const t=this._anyListeners;for(let s=0;s<t.length;s++)if(e===t[s])return t.splice(s,1),this}else this._anyListeners=[];return this}listenersAny(){return this._anyListeners||[]}onAnyOutgoing(e){return this._anyOutgoingListeners=this._anyOutgoingListeners||[],this._anyOutgoingListeners.push(e),this}prependAnyOutgoing(e){return this._anyOutgoingListeners=this._anyOutgoingListeners||[],this._anyOutgoingListeners.unshift(e),this}offAnyOutgoing(e){if(!this._anyOutgoingListeners)return this;if(e){const t=this._anyOutgoingListeners;for(let s=0;s<t.length;s++)if(e===t[s])return t.splice(s,1),this}else this._anyOutgoingListeners=[];return this}listenersAnyOutgoing(){return this._anyOutgoingListeners||[]}notifyOutgoingListeners(e){if(this._anyOutgoingListeners&&this._anyOutgoingListeners.length){const t=this._anyOutgoingListeners.slice();for(const s of t)s.apply(this,e.data)}}}t.Socket=u},84:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.url=void 0;const r=s(679),o=n(s(669)).default("socket.io-client:url");t.url=function(e,t="",s){let n=e;s=s||"undefined"!=typeof location&&location,null==e&&(e=s.protocol+"//"+s.host),"string"==typeof e&&("/"===e.charAt(0)&&(e="/"===e.charAt(1)?s.protocol+e:s.host+e),/^(https?|wss?):\/\//.test(e)||(o("protocol-less url %s",e),e=void 0!==s?s.protocol+"//"+e:"https://"+e),o("parse %s",e),n=r.parse(e)),n.port||(/^(http|ws)$/.test(n.protocol)?n.port="80":/^(http|ws)s$/.test(n.protocol)&&(n.port="443")),n.path=n.path||"/";const i=-1!==n.host.indexOf(":")?"["+n.host+"]":n.host;return n.id=n.protocol+"://"+i+":"+n.port+t,n.href=n.protocol+"://"+i+(s&&s.port===n.port?"":":"+n.port),n}},880:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.reconstructPacket=t.deconstructPacket=void 0;const n=s(665);function r(e,t){if(!e)return e;if((0,n.isBinary)(e)){const s={_placeholder:!0,num:t.length};return t.push(e),s}if(Array.isArray(e)){const s=new Array(e.length);for(let n=0;n<e.length;n++)s[n]=r(e[n],t);return s}if("object"==typeof e&&!(e instanceof Date)){const s={};for(const n in e)Object.prototype.hasOwnProperty.call(e,n)&&(s[n]=r(e[n],t));return s}return e}function o(e,t){if(!e)return e;if(e&&!0===e._placeholder){if("number"==typeof e.num&&e.num>=0&&e.num<t.length)return t[e.num];throw new Error("illegal attachments")}if(Array.isArray(e))for(let s=0;s<e.length;s++)e[s]=o(e[s],t);else if("object"==typeof e)for(const s in e)Object.prototype.hasOwnProperty.call(e,s)&&(e[s]=o(e[s],t));return e}t.deconstructPacket=function(e){const t=[],s=e.data,n=e;return n.data=r(s,t),n.attachments=t.length,{packet:n,buffers:t}},t.reconstructPacket=function(e,t){return e.data=o(e.data,t),delete e.attachments,e}},514:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Decoder=t.Encoder=t.PacketType=t.protocol=void 0;const n=s(260),r=s(880),o=s(665),i=(0,s(618).default)("socket.io-parser");var a;t.protocol=5,function(e){e[e.CONNECT=0]="CONNECT",e[e.DISCONNECT=1]="DISCONNECT",e[e.EVENT=2]="EVENT",e[e.ACK=3]="ACK",e[e.CONNECT_ERROR=4]="CONNECT_ERROR",e[e.BINARY_EVENT=5]="BINARY_EVENT",e[e.BINARY_ACK=6]="BINARY_ACK"}(a=t.PacketType||(t.PacketType={})),t.Encoder=class{constructor(e){this.replacer=e}encode(e){return i("encoding packet %j",e),e.type!==a.EVENT&&e.type!==a.ACK||!(0,o.hasBinary)(e)?[this.encodeAsString(e)]:this.encodeAsBinary({type:e.type===a.EVENT?a.BINARY_EVENT:a.BINARY_ACK,nsp:e.nsp,data:e.data,id:e.id})}encodeAsString(e){let t=""+e.type;return e.type!==a.BINARY_EVENT&&e.type!==a.BINARY_ACK||(t+=e.attachments+"-"),e.nsp&&"/"!==e.nsp&&(t+=e.nsp+","),null!=e.id&&(t+=e.id),null!=e.data&&(t+=JSON.stringify(e.data,this.replacer)),i("encoded %j as %s",e,t),t}encodeAsBinary(e){const t=(0,r.deconstructPacket)(e),s=this.encodeAsString(t.packet),n=t.buffers;return n.unshift(s),n}};class c extends n.Emitter{constructor(e){super(),this.reviver=e}add(e){let t;if("string"==typeof e){if(this.reconstructor)throw new Error("got plaintext data when reconstructing a packet");t=this.decodeString(e);const s=t.type===a.BINARY_EVENT;s||t.type===a.BINARY_ACK?(t.type=s?a.EVENT:a.ACK,this.reconstructor=new u(t),0===t.attachments&&super.emitReserved("decoded",t)):super.emitReserved("decoded",t)}else{if(!(0,o.isBinary)(e)&&!e.base64)throw new Error("Unknown type: "+e);if(!this.reconstructor)throw new Error("got binary data when not reconstructing a packet");t=this.reconstructor.takeBinaryData(e),t&&(this.reconstructor=null,super.emitReserved("decoded",t))}}decodeString(e){let t=0;const s={type:Number(e.charAt(0))};if(void 0===a[s.type])throw new Error("unknown packet type "+s.type);if(s.type===a.BINARY_EVENT||s.type===a.BINARY_ACK){const n=t+1;for(;"-"!==e.charAt(++t)&&t!=e.length;);const r=e.substring(n,t);if(r!=Number(r)||"-"!==e.charAt(t))throw new Error("Illegal attachments");s.attachments=Number(r)}if("/"===e.charAt(t+1)){const n=t+1;for(;++t&&","!==e.charAt(t)&&t!==e.length;);s.nsp=e.substring(n,t)}else s.nsp="/";const n=e.charAt(t+1);if(""!==n&&Number(n)==n){const n=t+1;for(;++t;){const s=e.charAt(t);if(null==s||Number(s)!=s){--t;break}if(t===e.length)break}s.id=Number(e.substring(n,t+1))}if(e.charAt(++t)){const n=this.tryParse(e.substr(t));if(!c.isPayloadValid(s.type,n))throw new Error("invalid payload");s.data=n}return i("decoded %s as %j",e,s),s}tryParse(e){try{return JSON.parse(e,this.reviver)}catch(e){return!1}}static isPayloadValid(e,t){switch(e){case a.CONNECT:return"object"==typeof t;case a.DISCONNECT:return void 0===t;case a.CONNECT_ERROR:return"string"==typeof t||"object"==typeof t;case a.EVENT:case a.BINARY_EVENT:return Array.isArray(t)&&("string"==typeof t[0]||"number"==typeof t[0]);case a.ACK:case a.BINARY_ACK:return Array.isArray(t)}}destroy(){this.reconstructor&&(this.reconstructor.finishedReconstruction(),this.reconstructor=null)}}t.Decoder=c;class u{constructor(e){this.packet=e,this.buffers=[],this.reconPack=e}takeBinaryData(e){if(this.buffers.push(e),this.buffers.length===this.reconPack.attachments){const e=(0,r.reconstructPacket)(this.reconPack,this.buffers);return this.finishedReconstruction(),e}return null}finishedReconstruction(){this.reconPack=null,this.buffers=[]}}},665:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.hasBinary=t.isBinary=void 0;const s="function"==typeof ArrayBuffer,n=Object.prototype.toString,r="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===n.call(Blob),o="function"==typeof File||"undefined"!=typeof File&&"[object FileConstructor]"===n.call(File);function i(e){return s&&(e instanceof ArrayBuffer||(e=>"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(e):e.buffer instanceof ArrayBuffer)(e))||r&&e instanceof Blob||o&&e instanceof File}t.isBinary=i,t.hasBinary=function e(t,s){if(!t||"object"!=typeof t)return!1;if(Array.isArray(t)){for(let s=0,n=t.length;s<n;s++)if(e(t[s]))return!0;return!1}if(i(t))return!0;if(t.toJSON&&"function"==typeof t.toJSON&&1===arguments.length)return e(t.toJSON(),!0);for(const s in t)if(Object.prototype.hasOwnProperty.call(t,s)&&e(t[s]))return!0;return!1}},260:(e,t,s)=>{"use strict";function n(e){if(e)return function(e){for(var t in n.prototype)e[t]=n.prototype[t];return e}(e)}s.r(t),s.d(t,{Emitter:()=>n}),n.prototype.on=n.prototype.addEventListener=function(e,t){return this._callbacks=this._callbacks||{},(this._callbacks["$"+e]=this._callbacks["$"+e]||[]).push(t),this},n.prototype.once=function(e,t){function s(){this.off(e,s),t.apply(this,arguments)}return s.fn=t,this.on(e,s),this},n.prototype.off=n.prototype.removeListener=n.prototype.removeAllListeners=n.prototype.removeEventListener=function(e,t){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var s,n=this._callbacks["$"+e];if(!n)return this;if(1==arguments.length)return delete this._callbacks["$"+e],this;for(var r=0;r<n.length;r++)if((s=n[r])===t||s.fn===t){n.splice(r,1);break}return 0===n.length&&delete this._callbacks["$"+e],this},n.prototype.emit=function(e){this._callbacks=this._callbacks||{};for(var t=new Array(arguments.length-1),s=this._callbacks["$"+e],n=1;n<arguments.length;n++)t[n-1]=arguments[n];if(s){n=0;for(var r=(s=s.slice(0)).length;n<r;++n)s[n].apply(this,t)}return this},n.prototype.emitReserved=n.prototype.emit,n.prototype.listeners=function(e){return this._callbacks=this._callbacks||{},this._callbacks["$"+e]||[]},n.prototype.hasListeners=function(e){return!!this.listeners(e).length}}},t={};function s(n){var r=t[n];if(void 0!==r)return r.exports;var o=t[n]={exports:{}};return e[n].call(o.exports,o,o.exports,s),o.exports}s.d=(e,t)=>{for(var n in t)s.o(t,n)&&!s.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},s.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),s.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{"use strict";const e=s(46),t=s(862),n=s(182),r=s(336);function o(e,t=document){return t.querySelector(e)}function i(e,t=document){return Array.from(t.querySelectorAll(e))}function a(){const e=c.gradientName(),t=o("body");let s;t.classList.value=e,t.classList.add(c.getTimePeriod()),s=c.get24Hour()>=5&&c.get24Hour()<9?"morning":c.get24Hour()>=9&&c.get24Hour()<17?"afternoon":c.get24Hour()>=17&&c.get24Hour()<20?"evening":"night",o("#time-of-day").innerHTML=`<img src="/assets/img/icons/time-of-day/${s}.png"> ${c.getHour()}${c.getAmPm()}`}const c=new n.TimeManager,u=(0,e.io)({extraHeaders:{"x-authtoken":(0,t.authToken)()}});a(),setInterval(a,6e4),u.on("connect",(()=>{console.log(`Connected: ${u.id}`)})),u.on("authToken",(e=>{console.log(`recv auth token ${e}`),localStorage.setItem("authToken",e)})),u.on("ready",(function(){console.log("Server connection verified"),(0,r.configureChat)(u),i("nav a")[0].click()})),i("nav a").forEach((e=>{e.addEventListener("click",(e=>{const t=e.target;i("a",t.closest("nav")).forEach((e=>{e.classList.remove("active")})),t.classList.add("active");const s=o(t.getAttribute("hx-target").toString());Array.from(s.parentElement.children).forEach((e=>{e.classList.remove("active")})),s.classList.add("active")}))})),o("body").addEventListener("click",(e=>{var t;const s=e.target;if(s.parentElement.classList.contains("filter")){Array.from(s.parentElement.children).forEach((e=>e.classList.remove("active"))),s.classList.add("active");const e=s.getAttribute("data-filter"),t=o(`.filter-result[data-filter="${e}"]`,s.closest(".filter-container"));t&&Array.from(t.parentElement.children).forEach((t=>{t.getAttribute("data-filter")===e?(t.classList.remove("hidden"),t.classList.add("active")):(t.classList.add("hidden"),t.classList.remove("active"))}))}"dialog"===s.getAttribute("formmethod")&&"cancel"===s.getAttribute("value")&&(null===(t=s.closest("dialog"))||void 0===t||t.close())}));const h=new MutationObserver(((e,t)=>{const s={modal:!1,alert:!1};e.forEach((e=>{switch(e.target.id){case"modal-wrapper":s.modal=!0;break;case"alerts":s.alert=!0}})),s.modal&&o("#modal-wrapper").children.length&&i("#modal-wrapper dialog").forEach((e=>{e.open||e.showModal()})),s.alert&&o("#alerts").children.length&&i("#alerts .alert").forEach((e=>{if(!e.getAttribute("data-dismiss-at")){const t=Date.now()+3e3;e.setAttribute("data-dismiss-at",t.toString()),setTimeout((()=>{e.remove()}),3e3)}}))}));h.observe(o("#modal-wrapper"),{childList:!0}),h.observe(o("#alerts"),{childList:!0}),document.body.addEventListener("htmx:configRequest",(function(e){e.detail.headers["x-authtoken"]=(0,t.authToken)()})),document.body.addEventListener("htmx:load",(function(e){i(".disabled[data-block]").forEach((e=>{setTimeout((()=>{e.removeAttribute("disabled")}),3e3)}))})),document.body.addEventListener("htmx:beforeSwap",(function(e){"chat-form"===e.target.id&&(o("#message").value="")}))})()})();
\ No newline at end of file
+(()=>{var e={802:(e,t,s)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const s="color: "+this.color;t.splice(1,0,s,"color: inherit");let n=0,r=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(n++,"%c"===e&&(r=n))})),t.splice(r,0,s)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=s(804)(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},804:(e,t,s)=>{e.exports=function(e){function t(e){let s,r,o,i=null;function a(...e){if(!a.enabled)return;const n=a,r=Number(new Date),o=r-(s||r);n.diff=o,n.prev=s,n.curr=r,s=r,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((s,r)=>{if("%%"===s)return"%";i++;const o=t.formatters[r];if("function"==typeof o){const t=e[i];s=o.call(n,t),e.splice(i,1),i--}return s})),t.formatArgs.call(n,e),(n.log||t.log).apply(n,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=n,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(r!==t.namespaces&&(r=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(a),a}function n(e,s){const n=t(this.namespace+(void 0===s?":":s)+e);return n.log=this.log,n}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let s;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").split(/[\s,]+/),r=n.length;for(s=0;s<r;s++)n[s]&&("-"===(e=n[s].replace(/\*/g,".*?"))[0]?t.skips.push(new RegExp("^"+e.slice(1)+"$")):t.names.push(new RegExp("^"+e+"$")))},t.enabled=function(e){if("*"===e[e.length-1])return!0;let s,n;for(s=0,n=t.skips.length;s<n;s++)if(t.skips[s].test(e))return!1;for(s=0,n=t.names.length;s<n;s++)if(t.names[s].test(e))return!0;return!1},t.humanize=s(810),t.destroy=function(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")},Object.keys(e).forEach((s=>{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t<e.length;t++)s=(s<<5)-s+e.charCodeAt(t),s|=0;return t.colors[Math.abs(s)%t.colors.length]},t.enable(t.load()),t}},810:e=>{var t=1e3,s=60*t,n=60*s,r=24*n;function o(e,t,s,n){var r=t>=1.5*s;return Math.round(e/s)+" "+n+(r?"s":"")}e.exports=function(e,i){i=i||{};var a,c,u=typeof e;if("string"===u&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(o){var i=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"weeks":case"week":case"w":return 6048e5*i;case"days":case"day":case"d":return i*r;case"hours":case"hour":case"hrs":case"hr":case"h":return i*n;case"minutes":case"minute":case"mins":case"min":case"m":return i*s;case"seconds":case"second":case"secs":case"sec":case"s":return i*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}}}(e);if("number"===u&&isFinite(e))return i.long?(a=e,(c=Math.abs(a))>=r?o(a,c,r,"day"):c>=n?o(a,c,n,"hour"):c>=s?o(a,c,s,"minute"):c>=t?o(a,c,t,"second"):a+" ms"):function(e){var o=Math.abs(e);return o>=r?Math.round(e/r)+"d":o>=n?Math.round(e/n)+"h":o>=s?Math.round(e/s)+"m":o>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},669:(e,t,s)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const s="color: "+this.color;t.splice(1,0,s,"color: inherit");let n=0,r=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(n++,"%c"===e&&(r=n))})),t.splice(r,0,s)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=s(231)(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},231:(e,t,s)=>{e.exports=function(e){function t(e){let s,r,o,i=null;function a(...e){if(!a.enabled)return;const n=a,r=Number(new Date),o=r-(s||r);n.diff=o,n.prev=s,n.curr=r,s=r,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((s,r)=>{if("%%"===s)return"%";i++;const o=t.formatters[r];if("function"==typeof o){const t=e[i];s=o.call(n,t),e.splice(i,1),i--}return s})),t.formatArgs.call(n,e),(n.log||t.log).apply(n,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=n,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(r!==t.namespaces&&(r=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(a),a}function n(e,s){const n=t(this.namespace+(void 0===s?":":s)+e);return n.log=this.log,n}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let s;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").split(/[\s,]+/),r=n.length;for(s=0;s<r;s++)n[s]&&("-"===(e=n[s].replace(/\*/g,".*?"))[0]?t.skips.push(new RegExp("^"+e.slice(1)+"$")):t.names.push(new RegExp("^"+e+"$")))},t.enabled=function(e){if("*"===e[e.length-1])return!0;let s,n;for(s=0,n=t.skips.length;s<n;s++)if(t.skips[s].test(e))return!1;for(s=0,n=t.names.length;s<n;s++)if(t.names[s].test(e))return!0;return!1},t.humanize=s(241),t.destroy=function(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")},Object.keys(e).forEach((s=>{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t<e.length;t++)s=(s<<5)-s+e.charCodeAt(t),s|=0;return t.colors[Math.abs(s)%t.colors.length]},t.enable(t.load()),t}},241:e=>{var t=1e3,s=60*t,n=60*s,r=24*n;function o(e,t,s,n){var r=t>=1.5*s;return Math.round(e/s)+" "+n+(r?"s":"")}e.exports=function(e,i){i=i||{};var a,c,u=typeof e;if("string"===u&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(o){var i=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"weeks":case"week":case"w":return 6048e5*i;case"days":case"day":case"d":return i*r;case"hours":case"hour":case"hrs":case"hr":case"h":return i*n;case"minutes":case"minute":case"mins":case"min":case"m":return i*s;case"seconds":case"second":case"secs":case"sec":case"s":return i*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}}}(e);if("number"===u&&isFinite(e))return i.long?(a=e,(c=Math.abs(a))>=r?o(a,c,r,"day"):c>=n?o(a,c,n,"hour"):c>=s?o(a,c,s,"minute"):c>=t?o(a,c,t,"second"):a+" ms"):function(e){var o=Math.abs(e);return o>=r?Math.round(e/r)+"d":o>=n?Math.round(e/n)+"h":o>=s?Math.round(e/s)+"m":o>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},618:(e,t,s)=>{t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const s="color: "+this.color;t.splice(1,0,s,"color: inherit");let n=0,r=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(n++,"%c"===e&&(r=n))})),t.splice(r,0,s)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=s(224)(t);const{formatters:n}=e.exports;n.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},224:(e,t,s)=>{e.exports=function(e){function t(e){let s,r,o,i=null;function a(...e){if(!a.enabled)return;const n=a,r=Number(new Date),o=r-(s||r);n.diff=o,n.prev=s,n.curr=r,s=r,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let i=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((s,r)=>{if("%%"===s)return"%";i++;const o=t.formatters[r];if("function"==typeof o){const t=e[i];s=o.call(n,t),e.splice(i,1),i--}return s})),t.formatArgs.call(n,e),(n.log||t.log).apply(n,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=n,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==i?i:(r!==t.namespaces&&(r=t.namespaces,o=t.enabled(e)),o),set:e=>{i=e}}),"function"==typeof t.init&&t.init(a),a}function n(e,s){const n=t(this.namespace+(void 0===s?":":s)+e);return n.log=this.log,n}function r(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(r),...t.skips.map(r).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let s;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const n=("string"==typeof e?e:"").split(/[\s,]+/),r=n.length;for(s=0;s<r;s++)n[s]&&("-"===(e=n[s].replace(/\*/g,".*?"))[0]?t.skips.push(new RegExp("^"+e.slice(1)+"$")):t.names.push(new RegExp("^"+e+"$")))},t.enabled=function(e){if("*"===e[e.length-1])return!0;let s,n;for(s=0,n=t.skips.length;s<n;s++)if(t.skips[s].test(e))return!1;for(s=0,n=t.names.length;s<n;s++)if(t.names[s].test(e))return!0;return!1},t.humanize=s(896),t.destroy=function(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")},Object.keys(e).forEach((s=>{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t<e.length;t++)s=(s<<5)-s+e.charCodeAt(t),s|=0;return t.colors[Math.abs(s)%t.colors.length]},t.enable(t.load()),t}},896:e=>{var t=1e3,s=60*t,n=60*s,r=24*n;function o(e,t,s,n){var r=t>=1.5*s;return Math.round(e/s)+" "+n+(r?"s":"")}e.exports=function(e,i){i=i||{};var a,c,u=typeof e;if("string"===u&&e.length>0)return function(e){if(!((e=String(e)).length>100)){var o=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(o){var i=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*i;case"weeks":case"week":case"w":return 6048e5*i;case"days":case"day":case"d":return i*r;case"hours":case"hour":case"hrs":case"hr":case"h":return i*n;case"minutes":case"minute":case"mins":case"min":case"m":return i*s;case"seconds":case"second":case"secs":case"sec":case"s":return i*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return i;default:return}}}}(e);if("number"===u&&isFinite(e))return i.long?(a=e,(c=Math.abs(a))>=r?o(a,c,r,"day"):c>=n?o(a,c,n,"hour"):c>=s?o(a,c,s,"minute"):c>=t?o(a,c,t,"second"):a+" ms"):function(e){var o=Math.abs(e);return o>=r?Math.round(e/r)+"d":o>=n?Math.round(e/n)+"h":o>=s?Math.round(e/s)+"m":o>=t?Math.round(e/t)+"s":e+"ms"}(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},182:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TimeManager=void 0,t.TimeManager=class{constructor(e=120){this.dayLength=e,this.scaleFactor=30,this.dayLengthAsMS=60*e*1e3}dayScaleFactor(){return this.dayLength/30}getTimePeriod(){return this.isMorning()?"morning":this.isAfternoon()?"afternoon":this.isEvening()?"evening":this.isNight()?"night":void 0}getAmPm(){return this.get24Hour()<12?"am":"pm"}get24Hour(){const e=new Date,t=(e.getMinutes()+e.getHours()%2*(this.dayLength/2))/this.dayLength;return Math.floor(24*t)}getHour(){const e=(new Date).getMinutes()/this.dayLength,t=Math.floor(24*e);return t>12?t-12:t}gradientName(){const e=Math.floor(this.get24Hour()/24*this.scaleFactor);return`sky-gradient-${e<10?"0":""}${e}`}isNight(){const e=this.get24Hour();return e>=0&&e<5||e>=21&&e<24}isMorning(){const e=this.get24Hour();return e>=5&&e<12}isAfternoon(){const e=this.get24Hour();return e>=12&&e<18}isEvening(){const e=this.get24Hour();return e>=18&&e<21}}},419:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.hasCORS=void 0;let s=!1;try{s="undefined"!=typeof XMLHttpRequest&&"withCredentials"in new XMLHttpRequest}catch(e){}t.hasCORS=s},754:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decode=t.encode=void 0,t.encode=function(e){let t="";for(let s in e)e.hasOwnProperty(s)&&(t.length&&(t+="&"),t+=encodeURIComponent(s)+"="+encodeURIComponent(e[s]));return t},t.decode=function(e){let t={},s=e.split("&");for(let e=0,n=s.length;e<n;e++){let n=s[e].split("=");t[decodeURIComponent(n[0])]=decodeURIComponent(n[1])}return t}},222:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.parse=void 0;const s=/^(?:(?![^:@\/?#]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@\/?#]*)(?::([^:@\/?#]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,n=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];t.parse=function(e){const t=e,r=e.indexOf("["),o=e.indexOf("]");-1!=r&&-1!=o&&(e=e.substring(0,r)+e.substring(r,o).replace(/:/g,";")+e.substring(o,e.length));let i=s.exec(e||""),a={},c=14;for(;c--;)a[n[c]]=i[c]||"";return-1!=r&&-1!=o&&(a.source=t,a.host=a.host.substring(1,a.host.length-1).replace(/;/g,":"),a.authority=a.authority.replace("[","").replace("]","").replace(/;/g,":"),a.ipv6uri=!0),a.pathNames=function(e,t){const s=t.replace(/\/{2,9}/g,"/").split("/");return"/"!=t.slice(0,1)&&0!==t.length||s.splice(0,1),"/"==t.slice(-1)&&s.splice(s.length-1,1),s}(0,a.path),a.queryKey=function(e,t){const s={};return t.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,(function(e,t,n){t&&(s[t]=n)})),s}(0,a.query),a}},726:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.yeast=t.decode=t.encode=void 0;const s="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(""),n={};let r,o=0,i=0;function a(e){let t="";do{t=s[e%64]+t,e=Math.floor(e/64)}while(e>0);return t}for(t.encode=a,t.decode=function(e){let t=0;for(i=0;i<e.length;i++)t=64*t+n[e.charAt(i)];return t},t.yeast=function(){const e=a(+new Date);return e!==r?(o=0,r=e):e+"."+a(o++)};i<64;i++)n[s[i]]=i},242:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.globalThisShim=void 0,t.globalThisShim="undefined"!=typeof self?self:"undefined"!=typeof window?window:Function("return this")()},679:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.nextTick=t.parse=t.installTimerFunctions=t.transports=t.Transport=t.protocol=t.Socket=void 0;const n=s(481);Object.defineProperty(t,"Socket",{enumerable:!0,get:function(){return n.Socket}}),t.protocol=n.Socket.protocol;var r=s(870);Object.defineProperty(t,"Transport",{enumerable:!0,get:function(){return r.Transport}});var o=s(385);Object.defineProperty(t,"transports",{enumerable:!0,get:function(){return o.transports}});var i=s(622);Object.defineProperty(t,"installTimerFunctions",{enumerable:!0,get:function(){return i.installTimerFunctions}});var a=s(222);Object.defineProperty(t,"parse",{enumerable:!0,get:function(){return a.parse}});var c=s(552);Object.defineProperty(t,"nextTick",{enumerable:!0,get:function(){return c.nextTick}})},481:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Socket=void 0;const r=s(385),o=s(622),i=s(754),a=s(222),c=n(s(802)),u=s(260),h=s(373),l=(0,c.default)("engine.io-client:socket");class d extends u.Emitter{constructor(e,t={}){super(),this.writeBuffer=[],e&&"object"==typeof e&&(t=e,e=null),e?(e=(0,a.parse)(e),t.hostname=e.host,t.secure="https"===e.protocol||"wss"===e.protocol,t.port=e.port,e.query&&(t.query=e.query)):t.host&&(t.hostname=(0,a.parse)(t.host).host),(0,o.installTimerFunctions)(this,t),this.secure=null!=t.secure?t.secure:"undefined"!=typeof location&&"https:"===location.protocol,t.hostname&&!t.port&&(t.port=this.secure?"443":"80"),this.hostname=t.hostname||("undefined"!=typeof location?location.hostname:"localhost"),this.port=t.port||("undefined"!=typeof location&&location.port?location.port:this.secure?"443":"80"),this.transports=t.transports||["polling","websocket"],this.writeBuffer=[],this.prevBufferLen=0,this.opts=Object.assign({path:"/engine.io",agent:!1,withCredentials:!1,upgrade:!0,timestampParam:"t",rememberUpgrade:!1,addTrailingSlash:!0,rejectUnauthorized:!0,perMessageDeflate:{threshold:1024},transportOptions:{},closeOnBeforeunload:!0},t),this.opts.path=this.opts.path.replace(/\/$/,"")+(this.opts.addTrailingSlash?"/":""),"string"==typeof this.opts.query&&(this.opts.query=(0,i.decode)(this.opts.query)),this.id=null,this.upgrades=null,this.pingInterval=null,this.pingTimeout=null,this.pingTimeoutTimer=null,"function"==typeof addEventListener&&(this.opts.closeOnBeforeunload&&(this.beforeunloadEventListener=()=>{this.transport&&(this.transport.removeAllListeners(),this.transport.close())},addEventListener("beforeunload",this.beforeunloadEventListener,!1)),"localhost"!==this.hostname&&(this.offlineEventListener=()=>{this.onClose("transport close",{description:"network connection lost"})},addEventListener("offline",this.offlineEventListener,!1))),this.open()}createTransport(e){l('creating transport "%s"',e);const t=Object.assign({},this.opts.query);t.EIO=h.protocol,t.transport=e,this.id&&(t.sid=this.id);const s=Object.assign({},this.opts.transportOptions[e],this.opts,{query:t,socket:this,hostname:this.hostname,secure:this.secure,port:this.port});return l("options: %j",s),new r.transports[e](s)}open(){let e;if(this.opts.rememberUpgrade&&d.priorWebsocketSuccess&&-1!==this.transports.indexOf("websocket"))e="websocket";else{if(0===this.transports.length)return void this.setTimeoutFn((()=>{this.emitReserved("error","No transports available")}),0);e=this.transports[0]}this.readyState="opening";try{e=this.createTransport(e)}catch(e){return l("error while creating transport: %s",e),this.transports.shift(),void this.open()}e.open(),this.setTransport(e)}setTransport(e){l("setting transport %s",e.name),this.transport&&(l("clearing existing transport %s",this.transport.name),this.transport.removeAllListeners()),this.transport=e,e.on("drain",this.onDrain.bind(this)).on("packet",this.onPacket.bind(this)).on("error",this.onError.bind(this)).on("close",(e=>this.onClose("transport close",e)))}probe(e){l('probing transport "%s"',e);let t=this.createTransport(e),s=!1;d.priorWebsocketSuccess=!1;const n=()=>{s||(l('probe transport "%s" opened',e),t.send([{type:"ping",data:"probe"}]),t.once("packet",(n=>{if(!s)if("pong"===n.type&&"probe"===n.data){if(l('probe transport "%s" pong',e),this.upgrading=!0,this.emitReserved("upgrading",t),!t)return;d.priorWebsocketSuccess="websocket"===t.name,l('pausing current transport "%s"',this.transport.name),this.transport.pause((()=>{s||"closed"!==this.readyState&&(l("changing transport and sending upgrade packet"),u(),this.setTransport(t),t.send([{type:"upgrade"}]),this.emitReserved("upgrade",t),t=null,this.upgrading=!1,this.flush())}))}else{l('probe transport "%s" failed',e);const s=new Error("probe error");s.transport=t.name,this.emitReserved("upgradeError",s)}})))};function r(){s||(s=!0,u(),t.close(),t=null)}const o=s=>{const n=new Error("probe error: "+s);n.transport=t.name,r(),l('probe transport "%s" failed because of error: %s',e,s),this.emitReserved("upgradeError",n)};function i(){o("transport closed")}function a(){o("socket closed")}function c(e){t&&e.name!==t.name&&(l('"%s" works - aborting "%s"',e.name,t.name),r())}const u=()=>{t.removeListener("open",n),t.removeListener("error",o),t.removeListener("close",i),this.off("close",a),this.off("upgrading",c)};t.once("open",n),t.once("error",o),t.once("close",i),this.once("close",a),this.once("upgrading",c),t.open()}onOpen(){if(l("socket open"),this.readyState="open",d.priorWebsocketSuccess="websocket"===this.transport.name,this.emitReserved("open"),this.flush(),"open"===this.readyState&&this.opts.upgrade){l("starting upgrade probes");let e=0;const t=this.upgrades.length;for(;e<t;e++)this.probe(this.upgrades[e])}}onPacket(e){if("opening"===this.readyState||"open"===this.readyState||"closing"===this.readyState)switch(l('socket receive: type "%s", data "%s"',e.type,e.data),this.emitReserved("packet",e),this.emitReserved("heartbeat"),e.type){case"open":this.onHandshake(JSON.parse(e.data));break;case"ping":this.resetPingTimeout(),this.sendPacket("pong"),this.emitReserved("ping"),this.emitReserved("pong");break;case"error":const t=new Error("server error");t.code=e.data,this.onError(t);break;case"message":this.emitReserved("data",e.data),this.emitReserved("message",e.data)}else l('packet received with socket readyState "%s"',this.readyState)}onHandshake(e){this.emitReserved("handshake",e),this.id=e.sid,this.transport.query.sid=e.sid,this.upgrades=this.filterUpgrades(e.upgrades),this.pingInterval=e.pingInterval,this.pingTimeout=e.pingTimeout,this.maxPayload=e.maxPayload,this.onOpen(),"closed"!==this.readyState&&this.resetPingTimeout()}resetPingTimeout(){this.clearTimeoutFn(this.pingTimeoutTimer),this.pingTimeoutTimer=this.setTimeoutFn((()=>{this.onClose("ping timeout")}),this.pingInterval+this.pingTimeout),this.opts.autoUnref&&this.pingTimeoutTimer.unref()}onDrain(){this.writeBuffer.splice(0,this.prevBufferLen),this.prevBufferLen=0,0===this.writeBuffer.length?this.emitReserved("drain"):this.flush()}flush(){if("closed"!==this.readyState&&this.transport.writable&&!this.upgrading&&this.writeBuffer.length){const e=this.getWritablePackets();l("flushing %d packets in socket",e.length),this.transport.send(e),this.prevBufferLen=e.length,this.emitReserved("flush")}}getWritablePackets(){if(!(this.maxPayload&&"polling"===this.transport.name&&this.writeBuffer.length>1))return this.writeBuffer;let e=1;for(let t=0;t<this.writeBuffer.length;t++){const s=this.writeBuffer[t].data;if(s&&(e+=(0,o.byteLength)(s)),t>0&&e>this.maxPayload)return l("only send %d out of %d packets",t,this.writeBuffer.length),this.writeBuffer.slice(0,t);e+=2}return l("payload size is %d (max: %d)",e,this.maxPayload),this.writeBuffer}write(e,t,s){return this.sendPacket("message",e,t,s),this}send(e,t,s){return this.sendPacket("message",e,t,s),this}sendPacket(e,t,s,n){if("function"==typeof t&&(n=t,t=void 0),"function"==typeof s&&(n=s,s=null),"closing"===this.readyState||"closed"===this.readyState)return;(s=s||{}).compress=!1!==s.compress;const r={type:e,data:t,options:s};this.emitReserved("packetCreate",r),this.writeBuffer.push(r),n&&this.once("flush",n),this.flush()}close(){const e=()=>{this.onClose("forced close"),l("socket closing - telling transport to close"),this.transport.close()},t=()=>{this.off("upgrade",t),this.off("upgradeError",t),e()},s=()=>{this.once("upgrade",t),this.once("upgradeError",t)};return"opening"!==this.readyState&&"open"!==this.readyState||(this.readyState="closing",this.writeBuffer.length?this.once("drain",(()=>{this.upgrading?s():e()})):this.upgrading?s():e()),this}onError(e){l("socket error %j",e),d.priorWebsocketSuccess=!1,this.emitReserved("error",e),this.onClose("transport error",e)}onClose(e,t){"opening"!==this.readyState&&"open"!==this.readyState&&"closing"!==this.readyState||(l('socket close with reason: "%s"',e),this.clearTimeoutFn(this.pingTimeoutTimer),this.transport.removeAllListeners("close"),this.transport.close(),this.transport.removeAllListeners(),"function"==typeof removeEventListener&&(removeEventListener("beforeunload",this.beforeunloadEventListener,!1),removeEventListener("offline",this.offlineEventListener,!1)),this.readyState="closed",this.id=null,this.emitReserved("close",e,t),this.writeBuffer=[],this.prevBufferLen=0)}filterUpgrades(e){const t=[];let s=0;const n=e.length;for(;s<n;s++)~this.transports.indexOf(e[s])&&t.push(e[s]);return t}}t.Socket=d,d.protocol=h.protocol},870:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Transport=void 0;const r=s(373),o=s(260),i=s(622),a=(0,n(s(802)).default)("engine.io-client:transport");class c extends Error{constructor(e,t,s){super(e),this.description=t,this.context=s,this.type="TransportError"}}class u extends o.Emitter{constructor(e){super(),this.writable=!1,(0,i.installTimerFunctions)(this,e),this.opts=e,this.query=e.query,this.socket=e.socket}onError(e,t,s){return super.emitReserved("error",new c(e,t,s)),this}open(){return this.readyState="opening",this.doOpen(),this}close(){return"opening"!==this.readyState&&"open"!==this.readyState||(this.doClose(),this.onClose()),this}send(e){"open"===this.readyState?this.write(e):a("transport is not open, discarding packets")}onOpen(){this.readyState="open",this.writable=!0,super.emitReserved("open")}onData(e){const t=(0,r.decodePacket)(e,this.socket.binaryType);this.onPacket(t)}onPacket(e){super.emitReserved("packet",e)}onClose(e){this.readyState="closed",super.emitReserved("close",e)}pause(e){}}t.Transport=u},385:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.transports=void 0;const n=s(484),r=s(308);t.transports={websocket:r.WS,polling:n.Polling}},484:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Request=t.Polling=void 0;const r=s(870),o=n(s(802)),i=s(726),a=s(754),c=s(373),u=s(666),h=s(260),l=s(622),d=s(242),p=(0,o.default)("engine.io-client:polling");function f(){}const g=null!=new u.XHR({xdomain:!1}).responseType;class m extends r.Transport{constructor(e){if(super(e),this.polling=!1,"undefined"!=typeof location){const t="https:"===location.protocol;let s=location.port;s||(s=t?"443":"80"),this.xd="undefined"!=typeof location&&e.hostname!==location.hostname||s!==e.port,this.xs=e.secure!==t}const t=e&&e.forceBase64;this.supportsBinary=g&&!t}get name(){return"polling"}doOpen(){this.poll()}pause(e){this.readyState="pausing";const t=()=>{p("paused"),this.readyState="paused",e()};if(this.polling||!this.writable){let e=0;this.polling&&(p("we are currently polling - waiting to pause"),e++,this.once("pollComplete",(function(){p("pre-pause polling complete"),--e||t()}))),this.writable||(p("we are currently writing - waiting to pause"),e++,this.once("drain",(function(){p("pre-pause writing complete"),--e||t()})))}else t()}poll(){p("polling"),this.polling=!0,this.doPoll(),this.emitReserved("poll")}onData(e){p("polling got data %s",e),(0,c.decodePayload)(e,this.socket.binaryType).forEach((e=>{if("opening"===this.readyState&&"open"===e.type&&this.onOpen(),"close"===e.type)return this.onClose({description:"transport closed by the server"}),!1;this.onPacket(e)})),"closed"!==this.readyState&&(this.polling=!1,this.emitReserved("pollComplete"),"open"===this.readyState?this.poll():p('ignoring poll - transport state "%s"',this.readyState))}doClose(){const e=()=>{p("writing close packet"),this.write([{type:"close"}])};"open"===this.readyState?(p("transport open - closing"),e()):(p("transport not open - deferring close"),this.once("open",e))}write(e){this.writable=!1,(0,c.encodePayload)(e,(e=>{this.doWrite(e,(()=>{this.writable=!0,this.emitReserved("drain")}))}))}uri(){let e=this.query||{};const t=this.opts.secure?"https":"http";let s="";!1!==this.opts.timestampRequests&&(e[this.opts.timestampParam]=(0,i.yeast)()),this.supportsBinary||e.sid||(e.b64=1),this.opts.port&&("https"===t&&443!==Number(this.opts.port)||"http"===t&&80!==Number(this.opts.port))&&(s=":"+this.opts.port);const n=(0,a.encode)(e);return t+"://"+(-1!==this.opts.hostname.indexOf(":")?"["+this.opts.hostname+"]":this.opts.hostname)+s+this.opts.path+(n.length?"?"+n:"")}request(e={}){return Object.assign(e,{xd:this.xd,xs:this.xs},this.opts),new y(this.uri(),e)}doWrite(e,t){const s=this.request({method:"POST",data:e});s.on("success",t),s.on("error",((e,t)=>{this.onError("xhr post error",e,t)}))}doPoll(){p("xhr poll");const e=this.request();e.on("data",this.onData.bind(this)),e.on("error",((e,t)=>{this.onError("xhr poll error",e,t)})),this.pollXhr=e}}t.Polling=m;class y extends h.Emitter{constructor(e,t){super(),(0,l.installTimerFunctions)(this,t),this.opts=t,this.method=t.method||"GET",this.uri=e,this.async=!1!==t.async,this.data=void 0!==t.data?t.data:null,this.create()}create(){const e=(0,l.pick)(this.opts,"agent","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","autoUnref");e.xdomain=!!this.opts.xd,e.xscheme=!!this.opts.xs;const t=this.xhr=new u.XHR(e);try{p("xhr open %s: %s",this.method,this.uri),t.open(this.method,this.uri,this.async);try{if(this.opts.extraHeaders){t.setDisableHeaderCheck&&t.setDisableHeaderCheck(!0);for(let e in this.opts.extraHeaders)this.opts.extraHeaders.hasOwnProperty(e)&&t.setRequestHeader(e,this.opts.extraHeaders[e])}}catch(e){}if("POST"===this.method)try{t.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(e){}try{t.setRequestHeader("Accept","*/*")}catch(e){}"withCredentials"in t&&(t.withCredentials=this.opts.withCredentials),this.opts.requestTimeout&&(t.timeout=this.opts.requestTimeout),t.onreadystatechange=()=>{4===t.readyState&&(200===t.status||1223===t.status?this.onLoad():this.setTimeoutFn((()=>{this.onError("number"==typeof t.status?t.status:0)}),0))},p("xhr data %s",this.data),t.send(this.data)}catch(e){return void this.setTimeoutFn((()=>{this.onError(e)}),0)}"undefined"!=typeof document&&(this.index=y.requestsCount++,y.requests[this.index]=this)}onError(e){this.emitReserved("error",e,this.xhr),this.cleanup(!0)}cleanup(e){if(void 0!==this.xhr&&null!==this.xhr){if(this.xhr.onreadystatechange=f,e)try{this.xhr.abort()}catch(e){}"undefined"!=typeof document&&delete y.requests[this.index],this.xhr=null}}onLoad(){const e=this.xhr.responseText;null!==e&&(this.emitReserved("data",e),this.emitReserved("success"),this.cleanup())}abort(){this.cleanup()}}if(t.Request=y,y.requestsCount=0,y.requests={},"undefined"!=typeof document)if("function"==typeof attachEvent)attachEvent("onunload",C);else if("function"==typeof addEventListener){const e="onpagehide"in d.globalThisShim?"pagehide":"unload";addEventListener(e,C,!1)}function C(){for(let e in y.requests)y.requests.hasOwnProperty(e)&&y.requests[e].abort()}},552:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.defaultBinaryType=t.usingBrowserWebSocket=t.WebSocket=t.nextTick=void 0;const n=s(242);t.nextTick="function"==typeof Promise&&"function"==typeof Promise.resolve?e=>Promise.resolve().then(e):(e,t)=>t(e,0),t.WebSocket=n.globalThisShim.WebSocket||n.globalThisShim.MozWebSocket,t.usingBrowserWebSocket=!0,t.defaultBinaryType="arraybuffer"},308:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.WS=void 0;const r=s(870),o=s(754),i=s(726),a=s(622),c=s(552),u=n(s(802)),h=s(373),l=(0,u.default)("engine.io-client:websocket"),d="undefined"!=typeof navigator&&"string"==typeof navigator.product&&"reactnative"===navigator.product.toLowerCase();class p extends r.Transport{constructor(e){super(e),this.supportsBinary=!e.forceBase64}get name(){return"websocket"}doOpen(){if(!this.check())return;const e=this.uri(),t=this.opts.protocols,s=d?{}:(0,a.pick)(this.opts,"agent","perMessageDeflate","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","localAddress","protocolVersion","origin","maxPayload","family","checkServerIdentity");this.opts.extraHeaders&&(s.headers=this.opts.extraHeaders);try{this.ws=c.usingBrowserWebSocket&&!d?t?new c.WebSocket(e,t):new c.WebSocket(e):new c.WebSocket(e,t,s)}catch(e){return this.emitReserved("error",e)}this.ws.binaryType=this.socket.binaryType||c.defaultBinaryType,this.addEventListeners()}addEventListeners(){this.ws.onopen=()=>{this.opts.autoUnref&&this.ws._socket.unref(),this.onOpen()},this.ws.onclose=e=>this.onClose({description:"websocket connection closed",context:e}),this.ws.onmessage=e=>this.onData(e.data),this.ws.onerror=e=>this.onError("websocket error",e)}write(e){this.writable=!1;for(let t=0;t<e.length;t++){const s=e[t],n=t===e.length-1;(0,h.encodePacket)(s,this.supportsBinary,(e=>{const t={};!c.usingBrowserWebSocket&&(s.options&&(t.compress=s.options.compress),this.opts.perMessageDeflate)&&("string"==typeof e?Buffer.byteLength(e):e.length)<this.opts.perMessageDeflate.threshold&&(t.compress=!1);try{c.usingBrowserWebSocket?this.ws.send(e):this.ws.send(e,t)}catch(e){l("websocket closed before onclose event")}n&&(0,c.nextTick)((()=>{this.writable=!0,this.emitReserved("drain")}),this.setTimeoutFn)}))}}doClose(){void 0!==this.ws&&(this.ws.close(),this.ws=null)}uri(){let e=this.query||{};const t=this.opts.secure?"wss":"ws";let s="";this.opts.port&&("wss"===t&&443!==Number(this.opts.port)||"ws"===t&&80!==Number(this.opts.port))&&(s=":"+this.opts.port),this.opts.timestampRequests&&(e[this.opts.timestampParam]=(0,i.yeast)()),this.supportsBinary||(e.b64=1);const n=(0,o.encode)(e);return t+"://"+(-1!==this.opts.hostname.indexOf(":")?"["+this.opts.hostname+"]":this.opts.hostname)+s+this.opts.path+(n.length?"?"+n:"")}check(){return!!c.WebSocket}}t.WS=p},666:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.XHR=void 0;const n=s(419),r=s(242);t.XHR=function(e){const t=e.xdomain;try{if("undefined"!=typeof XMLHttpRequest&&(!t||n.hasCORS))return new XMLHttpRequest}catch(e){}if(!t)try{return new(r.globalThisShim[["Active"].concat("Object").join("X")])("Microsoft.XMLHTTP")}catch(e){}}},622:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.byteLength=t.installTimerFunctions=t.pick=void 0;const n=s(242);t.pick=function(e,...t){return t.reduce(((t,s)=>(e.hasOwnProperty(s)&&(t[s]=e[s]),t)),{})};const r=n.globalThisShim.setTimeout,o=n.globalThisShim.clearTimeout;t.installTimerFunctions=function(e,t){t.useNativeTimers?(e.setTimeoutFn=r.bind(n.globalThisShim),e.clearTimeoutFn=o.bind(n.globalThisShim)):(e.setTimeoutFn=n.globalThisShim.setTimeout.bind(n.globalThisShim),e.clearTimeoutFn=n.globalThisShim.clearTimeout.bind(n.globalThisShim))},t.byteLength=function(e){return"string"==typeof e?function(e){let t=0,s=0;for(let n=0,r=e.length;n<r;n++)t=e.charCodeAt(n),t<128?s+=1:t<2048?s+=2:t<55296||t>=57344?s+=3:(n++,s+=4);return s}(e):Math.ceil(1.33*(e.byteLength||e.size))}},87:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ERROR_PACKET=t.PACKET_TYPES_REVERSE=t.PACKET_TYPES=void 0;const s=Object.create(null);t.PACKET_TYPES=s,s.open="0",s.close="1",s.ping="2",s.pong="3",s.message="4",s.upgrade="5",s.noop="6";const n=Object.create(null);t.PACKET_TYPES_REVERSE=n,Object.keys(s).forEach((e=>{n[s[e]]=e})),t.ERROR_PACKET={type:"error",data:"parser error"}},469:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decode=t.encode=void 0;const s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",n="undefined"==typeof Uint8Array?[]:new Uint8Array(256);for(let e=0;e<64;e++)n[s.charCodeAt(e)]=e;t.encode=e=>{let t,n=new Uint8Array(e),r=n.length,o="";for(t=0;t<r;t+=3)o+=s[n[t]>>2],o+=s[(3&n[t])<<4|n[t+1]>>4],o+=s[(15&n[t+1])<<2|n[t+2]>>6],o+=s[63&n[t+2]];return r%3==2?o=o.substring(0,o.length-1)+"=":r%3==1&&(o=o.substring(0,o.length-2)+"=="),o},t.decode=e=>{let t,s,r,o,i,a=.75*e.length,c=e.length,u=0;"="===e[e.length-1]&&(a--,"="===e[e.length-2]&&a--);const h=new ArrayBuffer(a),l=new Uint8Array(h);for(t=0;t<c;t+=4)s=n[e.charCodeAt(t)],r=n[e.charCodeAt(t+1)],o=n[e.charCodeAt(t+2)],i=n[e.charCodeAt(t+3)],l[u++]=s<<2|r>>4,l[u++]=(15&r)<<4|o>>2,l[u++]=(3&o)<<6|63&i;return h}},572:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=s(87),r=s(469),o="function"==typeof ArrayBuffer,i=(e,t)=>{if(o){const s=(0,r.decode)(e);return a(s,t)}return{base64:!0,data:e}},a=(e,t)=>"blob"===t&&e instanceof ArrayBuffer?new Blob([e]):e;t.default=(e,t)=>{if("string"!=typeof e)return{type:"message",data:a(e,t)};const s=e.charAt(0);return"b"===s?{type:"message",data:i(e.substring(1),t)}:n.PACKET_TYPES_REVERSE[s]?e.length>1?{type:n.PACKET_TYPES_REVERSE[s],data:e.substring(1)}:{type:n.PACKET_TYPES_REVERSE[s]}:n.ERROR_PACKET}},908:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});const n=s(87),r="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===Object.prototype.toString.call(Blob),o="function"==typeof ArrayBuffer,i=(e,t)=>{const s=new FileReader;return s.onload=function(){const e=s.result.split(",")[1];t("b"+(e||""))},s.readAsDataURL(e)};t.default=({type:e,data:t},s,a)=>{return r&&t instanceof Blob?s?a(t):i(t,a):o&&(t instanceof ArrayBuffer||(c=t,"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(c):c&&c.buffer instanceof ArrayBuffer))?s?a(t):i(new Blob([t]),a):a(n.PACKET_TYPES[e]+(t||""));var c}},373:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.decodePayload=t.decodePacket=t.encodePayload=t.encodePacket=t.protocol=void 0;const n=s(908);t.encodePacket=n.default;const r=s(572);t.decodePacket=r.default;const o=String.fromCharCode(30);t.encodePayload=(e,t)=>{const s=e.length,r=new Array(s);let i=0;e.forEach(((e,a)=>{(0,n.default)(e,!1,(e=>{r[a]=e,++i===s&&t(r.join(o))}))}))},t.decodePayload=(e,t)=>{const s=e.split(o),n=[];for(let e=0;e<s.length;e++){const o=(0,r.default)(s[e],t);if(n.push(o),"error"===o.type)break}return n},t.protocol=4},159:(e,t)=>{"use strict";function s(e){e=e||{},this.ms=e.min||100,this.max=e.max||1e4,this.factor=e.factor||2,this.jitter=e.jitter>0&&e.jitter<=1?e.jitter:0,this.attempts=0}Object.defineProperty(t,"__esModule",{value:!0}),t.Backoff=void 0,t.Backoff=s,s.prototype.duration=function(){var e=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var t=Math.random(),s=Math.floor(t*this.jitter*e);e=0==(1&Math.floor(10*t))?e-s:e+s}return 0|Math.min(e,this.max)},s.prototype.reset=function(){this.attempts=0},s.prototype.setMin=function(e){this.ms=e},s.prototype.setMax=function(e){this.max=e},s.prototype.setJitter=function(e){this.jitter=e}},46:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.connect=t.io=t.Socket=t.Manager=t.protocol=void 0;const r=s(84),o=s(168);Object.defineProperty(t,"Manager",{enumerable:!0,get:function(){return o.Manager}});const i=s(312);Object.defineProperty(t,"Socket",{enumerable:!0,get:function(){return i.Socket}});const a=n(s(669)).default("socket.io-client"),c={};function u(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};const s=r.url(e,t.path||"/socket.io"),n=s.source,i=s.id,u=s.path,h=c[i]&&u in c[i].nsps;let l;return t.forceNew||t["force new connection"]||!1===t.multiplex||h?(a("ignoring socket cache for %s",n),l=new o.Manager(n,t)):(c[i]||(a("new io instance for %s",n),c[i]=new o.Manager(n,t)),l=c[i]),s.query&&!t.query&&(t.query=s.queryKey),l.socket(s.path,t)}t.io=u,t.connect=u,t.default=u,Object.assign(u,{Manager:o.Manager,Socket:i.Socket,io:u,connect:u});var h=s(514);Object.defineProperty(t,"protocol",{enumerable:!0,get:function(){return h.protocol}}),e.exports=u},168:function(e,t,s){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,s,n){void 0===n&&(n=s),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[s]}})}:function(e,t,s,n){void 0===n&&(n=s),e[n]=t[s]}),r=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),o=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var s in e)"default"!==s&&Object.prototype.hasOwnProperty.call(e,s)&&n(t,e,s);return r(t,e),t},i=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Manager=void 0;const a=s(679),c=s(312),u=o(s(514)),h=s(149),l=s(159),d=s(260),p=i(s(669)).default("socket.io-client:manager");class f extends d.Emitter{constructor(e,t){var s;super(),this.nsps={},this.subs=[],e&&"object"==typeof e&&(t=e,e=void 0),(t=t||{}).path=t.path||"/socket.io",this.opts=t,a.installTimerFunctions(this,t),this.reconnection(!1!==t.reconnection),this.reconnectionAttempts(t.reconnectionAttempts||1/0),this.reconnectionDelay(t.reconnectionDelay||1e3),this.reconnectionDelayMax(t.reconnectionDelayMax||5e3),this.randomizationFactor(null!==(s=t.randomizationFactor)&&void 0!==s?s:.5),this.backoff=new l.Backoff({min:this.reconnectionDelay(),max:this.reconnectionDelayMax(),jitter:this.randomizationFactor()}),this.timeout(null==t.timeout?2e4:t.timeout),this._readyState="closed",this.uri=e;const n=t.parser||u;this.encoder=new n.Encoder,this.decoder=new n.Decoder,this._autoConnect=!1!==t.autoConnect,this._autoConnect&&this.open()}reconnection(e){return arguments.length?(this._reconnection=!!e,this):this._reconnection}reconnectionAttempts(e){return void 0===e?this._reconnectionAttempts:(this._reconnectionAttempts=e,this)}reconnectionDelay(e){var t;return void 0===e?this._reconnectionDelay:(this._reconnectionDelay=e,null===(t=this.backoff)||void 0===t||t.setMin(e),this)}randomizationFactor(e){var t;return void 0===e?this._randomizationFactor:(this._randomizationFactor=e,null===(t=this.backoff)||void 0===t||t.setJitter(e),this)}reconnectionDelayMax(e){var t;return void 0===e?this._reconnectionDelayMax:(this._reconnectionDelayMax=e,null===(t=this.backoff)||void 0===t||t.setMax(e),this)}timeout(e){return arguments.length?(this._timeout=e,this):this._timeout}maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===this.backoff.attempts&&this.reconnect()}open(e){if(p("readyState %s",this._readyState),~this._readyState.indexOf("open"))return this;p("opening %s",this.uri),this.engine=new a.Socket(this.uri,this.opts);const t=this.engine,s=this;this._readyState="opening",this.skipReconnect=!1;const n=h.on(t,"open",(function(){s.onopen(),e&&e()})),r=h.on(t,"error",(t=>{p("error"),s.cleanup(),s._readyState="closed",this.emitReserved("error",t),e?e(t):s.maybeReconnectOnOpen()}));if(!1!==this._timeout){const e=this._timeout;p("connect attempt will timeout after %d",e),0===e&&n();const s=this.setTimeoutFn((()=>{p("connect attempt timed out after %d",e),n(),t.close(),t.emit("error",new Error("timeout"))}),e);this.opts.autoUnref&&s.unref(),this.subs.push((function(){clearTimeout(s)}))}return this.subs.push(n),this.subs.push(r),this}connect(e){return this.open(e)}onopen(){p("open"),this.cleanup(),this._readyState="open",this.emitReserved("open");const e=this.engine;this.subs.push(h.on(e,"ping",this.onping.bind(this)),h.on(e,"data",this.ondata.bind(this)),h.on(e,"error",this.onerror.bind(this)),h.on(e,"close",this.onclose.bind(this)),h.on(this.decoder,"decoded",this.ondecoded.bind(this)))}onping(){this.emitReserved("ping")}ondata(e){try{this.decoder.add(e)}catch(e){this.onclose("parse error",e)}}ondecoded(e){a.nextTick((()=>{this.emitReserved("packet",e)}),this.setTimeoutFn)}onerror(e){p("error",e),this.emitReserved("error",e)}socket(e,t){let s=this.nsps[e];return s?this._autoConnect&&!s.active&&s.connect():(s=new c.Socket(this,e,t),this.nsps[e]=s),s}_destroy(e){const t=Object.keys(this.nsps);for(const e of t)if(this.nsps[e].active)return void p("socket %s is still active, skipping close",e);this._close()}_packet(e){p("writing packet %j",e);const t=this.encoder.encode(e);for(let s=0;s<t.length;s++)this.engine.write(t[s],e.options)}cleanup(){p("cleanup"),this.subs.forEach((e=>e())),this.subs.length=0,this.decoder.destroy()}_close(){p("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,this.onclose("forced close"),this.engine&&this.engine.close()}disconnect(){return this._close()}onclose(e,t){p("closed due to %s",e),this.cleanup(),this.backoff.reset(),this._readyState="closed",this.emitReserved("close",e,t),this._reconnection&&!this.skipReconnect&&this.reconnect()}reconnect(){if(this._reconnecting||this.skipReconnect)return this;const e=this;if(this.backoff.attempts>=this._reconnectionAttempts)p("reconnect failed"),this.backoff.reset(),this.emitReserved("reconnect_failed"),this._reconnecting=!1;else{const t=this.backoff.duration();p("will wait %dms before reconnect attempt",t),this._reconnecting=!0;const s=this.setTimeoutFn((()=>{e.skipReconnect||(p("attempting reconnect"),this.emitReserved("reconnect_attempt",e.backoff.attempts),e.skipReconnect||e.open((t=>{t?(p("reconnect attempt error"),e._reconnecting=!1,e.reconnect(),this.emitReserved("reconnect_error",t)):(p("reconnect success"),e.onreconnect())})))}),t);this.opts.autoUnref&&s.unref(),this.subs.push((function(){clearTimeout(s)}))}}onreconnect(){const e=this.backoff.attempts;this._reconnecting=!1,this.backoff.reset(),this.emitReserved("reconnect",e)}}t.Manager=f},149:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.on=void 0,t.on=function(e,t,s){return e.on(t,s),function(){e.off(t,s)}}},312:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.Socket=void 0;const r=s(514),o=s(149),i=s(260),a=n(s(669)).default("socket.io-client:socket"),c=Object.freeze({connect:1,connect_error:1,disconnect:1,disconnecting:1,newListener:1,removeListener:1});class u extends i.Emitter{constructor(e,t,s){super(),this.connected=!1,this.recovered=!1,this.receiveBuffer=[],this.sendBuffer=[],this._queue=[],this._queueSeq=0,this.ids=0,this.acks={},this.flags={},this.io=e,this.nsp=t,s&&s.auth&&(this.auth=s.auth),this._opts=Object.assign({},s),this.io._autoConnect&&this.open()}get disconnected(){return!this.connected}subEvents(){if(this.subs)return;const e=this.io;this.subs=[o.on(e,"open",this.onopen.bind(this)),o.on(e,"packet",this.onpacket.bind(this)),o.on(e,"error",this.onerror.bind(this)),o.on(e,"close",this.onclose.bind(this))]}get active(){return!!this.subs}connect(){return this.connected||(this.subEvents(),this.io._reconnecting||this.io.open(),"open"===this.io._readyState&&this.onopen()),this}open(){return this.connect()}send(...e){return e.unshift("message"),this.emit.apply(this,e),this}emit(e,...t){if(c.hasOwnProperty(e))throw new Error('"'+e.toString()+'" is a reserved event name');if(t.unshift(e),this._opts.retries&&!this.flags.fromQueue&&!this.flags.volatile)return this._addToQueue(t),this;const s={type:r.PacketType.EVENT,data:t,options:{}};if(s.options.compress=!1!==this.flags.compress,"function"==typeof t[t.length-1]){const e=this.ids++;a("emitting packet with ack id %d",e);const n=t.pop();this._registerAckCallback(e,n),s.id=e}const n=this.io.engine&&this.io.engine.transport&&this.io.engine.transport.writable;return!this.flags.volatile||n&&this.connected?this.connected?(this.notifyOutgoingListeners(s),this.packet(s)):this.sendBuffer.push(s):a("discard packet as the transport is not currently writable"),this.flags={},this}_registerAckCallback(e,t){var s;const n=null!==(s=this.flags.timeout)&&void 0!==s?s:this._opts.ackTimeout;if(void 0===n)return void(this.acks[e]=t);const r=this.io.setTimeoutFn((()=>{delete this.acks[e];for(let t=0;t<this.sendBuffer.length;t++)this.sendBuffer[t].id===e&&(a("removing packet with ack id %d from the buffer",e),this.sendBuffer.splice(t,1));a("event with ack id %d has timed out after %d ms",e,n),t.call(this,new Error("operation has timed out"))}),n);this.acks[e]=(...e)=>{this.io.clearTimeoutFn(r),t.apply(this,[null,...e])}}emitWithAck(e,...t){const s=void 0!==this.flags.timeout||void 0!==this._opts.ackTimeout;return new Promise(((n,r)=>{t.push(((e,t)=>s?e?r(e):n(t):n(e))),this.emit(e,...t)}))}_addToQueue(e){let t;"function"==typeof e[e.length-1]&&(t=e.pop());const s={id:this._queueSeq++,tryCount:0,pending:!1,args:e,flags:Object.assign({fromQueue:!0},this.flags)};e.push(((e,...n)=>{if(s===this._queue[0])return null!==e?s.tryCount>this._opts.retries&&(a("packet [%d] is discarded after %d tries",s.id,s.tryCount),this._queue.shift(),t&&t(e)):(a("packet [%d] was successfully sent",s.id),this._queue.shift(),t&&t(null,...n)),s.pending=!1,this._drainQueue()})),this._queue.push(s),this._drainQueue()}_drainQueue(e=!1){if(a("draining queue"),!this.connected||0===this._queue.length)return;const t=this._queue[0];!t.pending||e?(t.pending=!0,t.tryCount++,a("sending packet [%d] (try n°%d)",t.id,t.tryCount),this.flags=t.flags,this.emit.apply(this,t.args)):a("packet [%d] has already been sent and is waiting for an ack",t.id)}packet(e){e.nsp=this.nsp,this.io._packet(e)}onopen(){a("transport is open - connecting"),"function"==typeof this.auth?this.auth((e=>{this._sendConnectPacket(e)})):this._sendConnectPacket(this.auth)}_sendConnectPacket(e){this.packet({type:r.PacketType.CONNECT,data:this._pid?Object.assign({pid:this._pid,offset:this._lastOffset},e):e})}onerror(e){this.connected||this.emitReserved("connect_error",e)}onclose(e,t){a("close (%s)",e),this.connected=!1,delete this.id,this.emitReserved("disconnect",e,t)}onpacket(e){if(e.nsp===this.nsp)switch(e.type){case r.PacketType.CONNECT:e.data&&e.data.sid?this.onconnect(e.data.sid,e.data.pid):this.emitReserved("connect_error",new Error("It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)"));break;case r.PacketType.EVENT:case r.PacketType.BINARY_EVENT:this.onevent(e);break;case r.PacketType.ACK:case r.PacketType.BINARY_ACK:this.onack(e);break;case r.PacketType.DISCONNECT:this.ondisconnect();break;case r.PacketType.CONNECT_ERROR:this.destroy();const t=new Error(e.data.message);t.data=e.data.data,this.emitReserved("connect_error",t)}}onevent(e){const t=e.data||[];a("emitting event %j",t),null!=e.id&&(a("attaching ack callback to event"),t.push(this.ack(e.id))),this.connected?this.emitEvent(t):this.receiveBuffer.push(Object.freeze(t))}emitEvent(e){if(this._anyListeners&&this._anyListeners.length){const t=this._anyListeners.slice();for(const s of t)s.apply(this,e)}super.emit.apply(this,e),this._pid&&e.length&&"string"==typeof e[e.length-1]&&(this._lastOffset=e[e.length-1])}ack(e){const t=this;let s=!1;return function(...n){s||(s=!0,a("sending ack %j",n),t.packet({type:r.PacketType.ACK,id:e,data:n}))}}onack(e){const t=this.acks[e.id];"function"==typeof t?(a("calling ack %s with %j",e.id,e.data),t.apply(this,e.data),delete this.acks[e.id]):a("bad ack %s",e.id)}onconnect(e,t){a("socket connected with id %s",e),this.id=e,this.recovered=t&&this._pid===t,this._pid=t,this.connected=!0,this.emitBuffered(),this.emitReserved("connect"),this._drainQueue(!0)}emitBuffered(){this.receiveBuffer.forEach((e=>this.emitEvent(e))),this.receiveBuffer=[],this.sendBuffer.forEach((e=>{this.notifyOutgoingListeners(e),this.packet(e)})),this.sendBuffer=[]}ondisconnect(){a("server disconnect (%s)",this.nsp),this.destroy(),this.onclose("io server disconnect")}destroy(){this.subs&&(this.subs.forEach((e=>e())),this.subs=void 0),this.io._destroy(this)}disconnect(){return this.connected&&(a("performing disconnect (%s)",this.nsp),this.packet({type:r.PacketType.DISCONNECT})),this.destroy(),this.connected&&this.onclose("io client disconnect"),this}close(){return this.disconnect()}compress(e){return this.flags.compress=e,this}get volatile(){return this.flags.volatile=!0,this}timeout(e){return this.flags.timeout=e,this}onAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.push(e),this}prependAny(e){return this._anyListeners=this._anyListeners||[],this._anyListeners.unshift(e),this}offAny(e){if(!this._anyListeners)return this;if(e){const t=this._anyListeners;for(let s=0;s<t.length;s++)if(e===t[s])return t.splice(s,1),this}else this._anyListeners=[];return this}listenersAny(){return this._anyListeners||[]}onAnyOutgoing(e){return this._anyOutgoingListeners=this._anyOutgoingListeners||[],this._anyOutgoingListeners.push(e),this}prependAnyOutgoing(e){return this._anyOutgoingListeners=this._anyOutgoingListeners||[],this._anyOutgoingListeners.unshift(e),this}offAnyOutgoing(e){if(!this._anyOutgoingListeners)return this;if(e){const t=this._anyOutgoingListeners;for(let s=0;s<t.length;s++)if(e===t[s])return t.splice(s,1),this}else this._anyOutgoingListeners=[];return this}listenersAnyOutgoing(){return this._anyOutgoingListeners||[]}notifyOutgoingListeners(e){if(this._anyOutgoingListeners&&this._anyOutgoingListeners.length){const t=this._anyOutgoingListeners.slice();for(const s of t)s.apply(this,e.data)}}}t.Socket=u},84:function(e,t,s){"use strict";var n=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.url=void 0;const r=s(679),o=n(s(669)).default("socket.io-client:url");t.url=function(e,t="",s){let n=e;s=s||"undefined"!=typeof location&&location,null==e&&(e=s.protocol+"//"+s.host),"string"==typeof e&&("/"===e.charAt(0)&&(e="/"===e.charAt(1)?s.protocol+e:s.host+e),/^(https?|wss?):\/\//.test(e)||(o("protocol-less url %s",e),e=void 0!==s?s.protocol+"//"+e:"https://"+e),o("parse %s",e),n=r.parse(e)),n.port||(/^(http|ws)$/.test(n.protocol)?n.port="80":/^(http|ws)s$/.test(n.protocol)&&(n.port="443")),n.path=n.path||"/";const i=-1!==n.host.indexOf(":")?"["+n.host+"]":n.host;return n.id=n.protocol+"://"+i+":"+n.port+t,n.href=n.protocol+"://"+i+(s&&s.port===n.port?"":":"+n.port),n}},880:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.reconstructPacket=t.deconstructPacket=void 0;const n=s(665);function r(e,t){if(!e)return e;if((0,n.isBinary)(e)){const s={_placeholder:!0,num:t.length};return t.push(e),s}if(Array.isArray(e)){const s=new Array(e.length);for(let n=0;n<e.length;n++)s[n]=r(e[n],t);return s}if("object"==typeof e&&!(e instanceof Date)){const s={};for(const n in e)Object.prototype.hasOwnProperty.call(e,n)&&(s[n]=r(e[n],t));return s}return e}function o(e,t){if(!e)return e;if(e&&!0===e._placeholder){if("number"==typeof e.num&&e.num>=0&&e.num<t.length)return t[e.num];throw new Error("illegal attachments")}if(Array.isArray(e))for(let s=0;s<e.length;s++)e[s]=o(e[s],t);else if("object"==typeof e)for(const s in e)Object.prototype.hasOwnProperty.call(e,s)&&(e[s]=o(e[s],t));return e}t.deconstructPacket=function(e){const t=[],s=e.data,n=e;return n.data=r(s,t),n.attachments=t.length,{packet:n,buffers:t}},t.reconstructPacket=function(e,t){return e.data=o(e.data,t),delete e.attachments,e}},514:(e,t,s)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Decoder=t.Encoder=t.PacketType=t.protocol=void 0;const n=s(260),r=s(880),o=s(665),i=(0,s(618).default)("socket.io-parser");var a;t.protocol=5,function(e){e[e.CONNECT=0]="CONNECT",e[e.DISCONNECT=1]="DISCONNECT",e[e.EVENT=2]="EVENT",e[e.ACK=3]="ACK",e[e.CONNECT_ERROR=4]="CONNECT_ERROR",e[e.BINARY_EVENT=5]="BINARY_EVENT",e[e.BINARY_ACK=6]="BINARY_ACK"}(a=t.PacketType||(t.PacketType={})),t.Encoder=class{constructor(e){this.replacer=e}encode(e){return i("encoding packet %j",e),e.type!==a.EVENT&&e.type!==a.ACK||!(0,o.hasBinary)(e)?[this.encodeAsString(e)]:this.encodeAsBinary({type:e.type===a.EVENT?a.BINARY_EVENT:a.BINARY_ACK,nsp:e.nsp,data:e.data,id:e.id})}encodeAsString(e){let t=""+e.type;return e.type!==a.BINARY_EVENT&&e.type!==a.BINARY_ACK||(t+=e.attachments+"-"),e.nsp&&"/"!==e.nsp&&(t+=e.nsp+","),null!=e.id&&(t+=e.id),null!=e.data&&(t+=JSON.stringify(e.data,this.replacer)),i("encoded %j as %s",e,t),t}encodeAsBinary(e){const t=(0,r.deconstructPacket)(e),s=this.encodeAsString(t.packet),n=t.buffers;return n.unshift(s),n}};class c extends n.Emitter{constructor(e){super(),this.reviver=e}add(e){let t;if("string"==typeof e){if(this.reconstructor)throw new Error("got plaintext data when reconstructing a packet");t=this.decodeString(e);const s=t.type===a.BINARY_EVENT;s||t.type===a.BINARY_ACK?(t.type=s?a.EVENT:a.ACK,this.reconstructor=new u(t),0===t.attachments&&super.emitReserved("decoded",t)):super.emitReserved("decoded",t)}else{if(!(0,o.isBinary)(e)&&!e.base64)throw new Error("Unknown type: "+e);if(!this.reconstructor)throw new Error("got binary data when not reconstructing a packet");t=this.reconstructor.takeBinaryData(e),t&&(this.reconstructor=null,super.emitReserved("decoded",t))}}decodeString(e){let t=0;const s={type:Number(e.charAt(0))};if(void 0===a[s.type])throw new Error("unknown packet type "+s.type);if(s.type===a.BINARY_EVENT||s.type===a.BINARY_ACK){const n=t+1;for(;"-"!==e.charAt(++t)&&t!=e.length;);const r=e.substring(n,t);if(r!=Number(r)||"-"!==e.charAt(t))throw new Error("Illegal attachments");s.attachments=Number(r)}if("/"===e.charAt(t+1)){const n=t+1;for(;++t&&","!==e.charAt(t)&&t!==e.length;);s.nsp=e.substring(n,t)}else s.nsp="/";const n=e.charAt(t+1);if(""!==n&&Number(n)==n){const n=t+1;for(;++t;){const s=e.charAt(t);if(null==s||Number(s)!=s){--t;break}if(t===e.length)break}s.id=Number(e.substring(n,t+1))}if(e.charAt(++t)){const n=this.tryParse(e.substr(t));if(!c.isPayloadValid(s.type,n))throw new Error("invalid payload");s.data=n}return i("decoded %s as %j",e,s),s}tryParse(e){try{return JSON.parse(e,this.reviver)}catch(e){return!1}}static isPayloadValid(e,t){switch(e){case a.CONNECT:return"object"==typeof t;case a.DISCONNECT:return void 0===t;case a.CONNECT_ERROR:return"string"==typeof t||"object"==typeof t;case a.EVENT:case a.BINARY_EVENT:return Array.isArray(t)&&("string"==typeof t[0]||"number"==typeof t[0]);case a.ACK:case a.BINARY_ACK:return Array.isArray(t)}}destroy(){this.reconstructor&&(this.reconstructor.finishedReconstruction(),this.reconstructor=null)}}t.Decoder=c;class u{constructor(e){this.packet=e,this.buffers=[],this.reconPack=e}takeBinaryData(e){if(this.buffers.push(e),this.buffers.length===this.reconPack.attachments){const e=(0,r.reconstructPacket)(this.reconPack,this.buffers);return this.finishedReconstruction(),e}return null}finishedReconstruction(){this.reconPack=null,this.buffers=[]}}},665:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.hasBinary=t.isBinary=void 0;const s="function"==typeof ArrayBuffer,n=Object.prototype.toString,r="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===n.call(Blob),o="function"==typeof File||"undefined"!=typeof File&&"[object FileConstructor]"===n.call(File);function i(e){return s&&(e instanceof ArrayBuffer||(e=>"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(e):e.buffer instanceof ArrayBuffer)(e))||r&&e instanceof Blob||o&&e instanceof File}t.isBinary=i,t.hasBinary=function e(t,s){if(!t||"object"!=typeof t)return!1;if(Array.isArray(t)){for(let s=0,n=t.length;s<n;s++)if(e(t[s]))return!0;return!1}if(i(t))return!0;if(t.toJSON&&"function"==typeof t.toJSON&&1===arguments.length)return e(t.toJSON(),!0);for(const s in t)if(Object.prototype.hasOwnProperty.call(t,s)&&e(t[s]))return!0;return!1}},260:(e,t,s)=>{"use strict";function n(e){if(e)return function(e){for(var t in n.prototype)e[t]=n.prototype[t];return e}(e)}s.r(t),s.d(t,{Emitter:()=>n}),n.prototype.on=n.prototype.addEventListener=function(e,t){return this._callbacks=this._callbacks||{},(this._callbacks["$"+e]=this._callbacks["$"+e]||[]).push(t),this},n.prototype.once=function(e,t){function s(){this.off(e,s),t.apply(this,arguments)}return s.fn=t,this.on(e,s),this},n.prototype.off=n.prototype.removeListener=n.prototype.removeAllListeners=n.prototype.removeEventListener=function(e,t){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var s,n=this._callbacks["$"+e];if(!n)return this;if(1==arguments.length)return delete this._callbacks["$"+e],this;for(var r=0;r<n.length;r++)if((s=n[r])===t||s.fn===t){n.splice(r,1);break}return 0===n.length&&delete this._callbacks["$"+e],this},n.prototype.emit=function(e){this._callbacks=this._callbacks||{};for(var t=new Array(arguments.length-1),s=this._callbacks["$"+e],n=1;n<arguments.length;n++)t[n-1]=arguments[n];if(s){n=0;for(var r=(s=s.slice(0)).length;n<r;++n)s[n].apply(this,t)}return this},n.prototype.emitReserved=n.prototype.emit,n.prototype.listeners=function(e){return this._callbacks=this._callbacks||{},this._callbacks["$"+e]||[]},n.prototype.hasListeners=function(e){return!!this.listeners(e).length}}},t={};function s(n){var r=t[n];if(void 0!==r)return r.exports;var o=t[n]={exports:{}};return e[n].call(o.exports,o,o.exports,s),o.exports}s.d=(e,t)=>{for(var n in t)s.o(t,n)&&!s.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},s.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),s.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{"use strict";const e=s(46);function t(e,t=document){return t.querySelector(e)}function n(e,t=document){return Array.from(t.querySelectorAll(e))}function r(){return localStorage.getItem("authToken")||""}function o(){const e=i.gradientName(),s=t("body");let n;s.classList.value=e,s.classList.add(i.getTimePeriod()),n=i.get24Hour()>=5&&i.get24Hour()<9?"morning":i.get24Hour()>=9&&i.get24Hour()<17?"afternoon":i.get24Hour()>=17&&i.get24Hour()<20?"evening":"night",t("#time-of-day").innerHTML=`<img src="/assets/img/icons/time-of-day/${n}.png"> ${i.getHour()}${i.getAmPm()}`}const i=new(s(182).TimeManager),a=(0,e.io)({extraHeaders:{"x-authtoken":r()}});o(),setInterval(o,6e4),a.on("connect",(()=>{console.log(`Connected: ${a.id}`)})),a.on("authToken",(e=>{console.log(`recv auth token ${e}`),localStorage.setItem("authToken",e)})),a.on("chat",(function(e){t("#chat-messages").innerHTML+=e,t("#chat-messages").scrollTop=t("#chat-messages").scrollHeight})),a.on("ready",(function(){console.log("Server connection verified"),n("nav a")[0].click()})),n("nav a").forEach((e=>{e.addEventListener("click",(e=>{const s=e.target;n("a",s.closest("nav")).forEach((e=>{e.classList.remove("active")})),s.classList.add("active");const r=t(s.getAttribute("hx-target").toString());Array.from(r.parentElement.children).forEach((e=>{e.classList.remove("active")})),r.classList.add("active")}))})),t("body").addEventListener("click",(e=>{var s;const n=e.target;if(n.parentElement.classList.contains("filter")){Array.from(n.parentElement.children).forEach((e=>e.classList.remove("active"))),n.classList.add("active");const e=n.getAttribute("data-filter"),s=t(`.filter-result[data-filter="${e}"]`,n.closest(".filter-container"));s&&Array.from(s.parentElement.children).forEach((t=>{t.getAttribute("data-filter")===e?(t.classList.remove("hidden"),t.classList.add("active")):(t.classList.add("hidden"),t.classList.remove("active"))}))}"dialog"===n.getAttribute("formmethod")&&"cancel"===n.getAttribute("value")&&(null===(s=n.closest("dialog"))||void 0===s||s.close())}));const c=new MutationObserver(((e,s)=>{const r={modal:!1,alert:!1};e.forEach((e=>{switch(e.target.id){case"modal-wrapper":r.modal=!0;break;case"alerts":r.alert=!0}})),r.modal&&t("#modal-wrapper").children.length&&n("#modal-wrapper dialog").forEach((e=>{e.open||e.showModal()})),r.alert&&t("#alerts").children.length&&n("#alerts .alert").forEach((e=>{if(!e.getAttribute("data-dismiss-at")){const t=Date.now()+3e3;e.setAttribute("data-dismiss-at",t.toString()),setTimeout((()=>{e.remove()}),3e3)}}))}));c.observe(t("#modal-wrapper"),{childList:!0}),c.observe(t("#alerts"),{childList:!0}),document.body.addEventListener("htmx:configRequest",(function(e){e.detail.headers["x-authtoken"]=r()})),document.body.addEventListener("htmx:load",(function(e){n(".disabled[data-block]").forEach((e=>{setTimeout((()=>{e.removeAttribute("disabled")}),3e3)}))})),document.body.addEventListener("htmx:beforeSwap",(function(e){"chat-form"===e.target.id?t("#message").value="":"logout"===e.detail.serverResponse&&(localStorage.removeItem("authToken"),window.location.reload())}))})()})();
\ No newline at end of file
index edb597de6cf56f460816e988cbbcb57b46ae9b9c..13b092946e1adc78c59941162a6572619a7fe634 100644 (file)
@@ -291,6 +291,10 @@ nav.filter-result.active {
   height: 64px;
   margin: 0 1rem 1rem 0;
 }
   height: 64px;
   margin: 0 1rem 1rem 0;
 }
+.item-modal-overview .icon img {
+  width: 64px;
+  height: 64px;
+}
 .item-modal-overview .name {
   margin-top: 0;
   font-weight: bold;
 .item-modal-overview .name {
   margin-top: 0;
   font-weight: bold;
@@ -390,7 +394,7 @@ h3 {
 .store-list {
   display: flex;
   text-align: left;
 .store-list {
   display: flex;
   text-align: left;
-  margin-bottom: 0.3rem;
+  margin: 0 0 0.3rem 0.3rem;
 }
 .store-list:last-child {
   margin-bottom: 0;
 }
 .store-list:last-child {
   margin-bottom: 0;
@@ -447,6 +451,7 @@ h3 {
   font-size: 0.7rem;
   background-repeat: no-repeat;
   overflow: hidden;
   font-size: 0.7rem;
   background-repeat: no-repeat;
   overflow: hidden;
+  background-size: contain;
 }
 #extra-inventory-info {
   margin-top: 1rem;
 }
 #extra-inventory-info {
   margin-top: 1rem;
diff --git a/public/assets/img/icons/equipment/arm_t_02.PNG b/public/assets/img/icons/equipment/arm_t_02.PNG
new file mode 100755 (executable)
index 0000000..be71a7c
Binary files /dev/null and b/public/assets/img/icons/equipment/arm_t_02.PNG differ
diff --git a/public/assets/img/icons/equipment/boot_t_02.png b/public/assets/img/icons/equipment/boot_t_02.png
new file mode 100755 (executable)
index 0000000..0134c45
Binary files /dev/null and b/public/assets/img/icons/equipment/boot_t_02.png differ
diff --git a/public/assets/img/icons/equipment/gl_t_07.png b/public/assets/img/icons/equipment/gl_t_07.png
new file mode 100755 (executable)
index 0000000..90ffe1d
Binary files /dev/null and b/public/assets/img/icons/equipment/gl_t_07.png differ
diff --git a/public/assets/img/icons/equipment/hlm_t_02.png b/public/assets/img/icons/equipment/hlm_t_02.png
new file mode 100755 (executable)
index 0000000..23e8073
Binary files /dev/null and b/public/assets/img/icons/equipment/hlm_t_02.png differ
diff --git a/public/assets/img/icons/equipment/pn_t_06.png b/public/assets/img/icons/equipment/pn_t_06.png
new file mode 100644 (file)
index 0000000..9a3fca9
Binary files /dev/null and b/public/assets/img/icons/equipment/pn_t_06.png differ
index 83f18c6ea617fe7b7f459e241a8bc3e1ad9c877c..ef4a192d7df0ee5a63211fcb7aee5013d2580af0 100644 (file)
@@ -11,7 +11,6 @@
     <link rel="stylesheet" href="/assets/css/game.css">
     <link rel="stylesheet" href="/assets/css/sky.css">
     <script src="https://unpkg.com/htmx.org@1.9.4" integrity="sha384-zUfuhFKKZCbHTY6aRR46gxiqszMk5tcHjsVFxnUo8VMus4kHGVdIYVbOYYNlKmHV" crossorigin="anonymous"></script>
     <link rel="stylesheet" href="/assets/css/game.css">
     <link rel="stylesheet" href="/assets/css/sky.css">
     <script src="https://unpkg.com/htmx.org@1.9.4" integrity="sha384-zUfuhFKKZCbHTY6aRR46gxiqszMk5tcHjsVFxnUo8VMus4kHGVdIYVbOYYNlKmHV" crossorigin="anonymous"></script>
-    <script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script>
     <script src="/socket.io/socket.io.js"></script>
   </head>
   <body>
     <script src="/socket.io/socket.io.js"></script>
   </head>
   <body>
@@ -63,7 +62,7 @@
       </div>
 
       <section id="chat">
       </div>
 
       <section id="chat">
-        <div id="chat-messages" hx-trigger="load delay:1s" hx-get="/chat/history"></div>
+        <div id="chat-messages" hx-trigger="load delay:1s" hx-get="/chat/history" hx-swap="afterend"></div>
         <form id="chat-form" hx-post="/chat">
           <input type="text" id="message" name="message" autocomplete="off"><button type="submit">Send</button>
         </form>
         <form id="chat-form" hx-post="/chat">
           <input type="text" id="message" name="message" autocomplete="off"><button type="submit">Send</button>
         </form>
@@ -72,7 +71,7 @@
       <section id="game-footer">
         <div>
           <nav>
       <section id="game-footer">
         <div>
           <nav>
-            <a href="#" data-section="settings" data-container="main-nav">Settings</a>
+            <a href="#" data-section="settings" data-container="main-nav" hx-get="/settings" hx-target="#settings">Settings</a>
           </nav>
         </div>
         <div id="server-stats" hx-trigger="load delay:1s" hx-get="/status" hx-swap="outerHTML">...Loading</div>
           </nav>
         </div>
         <div id="server-stats" hx-trigger="load delay:1s" hx-get="/status" hx-swap="outerHTML">...Loading</div>
index 18a754ccab059027628a0ef946c9ee66eb23fa91..55e558de4871d219eceb41198e94e648b25ee28d 100644 (file)
@@ -20,6 +20,7 @@ export async function createShopEquipment(): Promise<void> {
           type: r.fields['Equipment Type'],
           equipment_slot: r.fields['Equipment Slot'],
           cost: r.fields.Cost,
           type: r.fields['Equipment Type'],
           equipment_slot: r.fields['Equipment Slot'],
           cost: r.fields.Cost,
+          icon: r.fields.Icon,
           count: 1,
           requirements: {
             level: r.fields['Required Level'],
           count: 1,
           requirements: {
             level: r.fields['Required Level'],
diff --git a/src/client/chat.ts b/src/client/chat.ts
deleted file mode 100644 (file)
index 287207e..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-import {Socket} from 'socket.io-client';
-import {Message} from '../shared/message';
-
-// disable chat temporarily to test widgetbot
-let socket: Socket;
-function $<T>(selector: string, root: any = document): T {
-  return root.querySelector(selector) as T;
-}
-
-function $$<T>(selector: string, root: any = document): T[] {
-  return Array.from(root.querySelectorAll(selector)) as T[];
-}
-
-function renderChatMessage(msg: Message) {
-  $<HTMLElement>('#chat-messages').innerHTML += `<div class="chat-message" title="${new Date(parseInt(msg.sentAt))}" id="${msg.id}">
-                             <span class="from">${msg.from}</span>
-                             <span class="message">${msg.msg}</span>
-                             </div>`;
-  $<HTMLElement>('#chat-messages').scrollTop = $<HTMLElement>('#chat-messages').scrollHeight;
-}
-
-function configureStandardChat() {
-  socket.on('chat', renderChatMessage);
-}
-
-export function configureChat(_socket: Socket) {
-  // disable chat temporarily to test discord chat
-  socket = _socket;
-
-  configureStandardChat();
-
-  console.log('Chat Configured');
-}
diff --git a/src/client/custom-discord.ts b/src/client/custom-discord.ts
deleted file mode 100644 (file)
index 377ac40..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-import {Socket} from "socket.io-client";
-
-export function configureChat(socket: Socket) {
-
-}
diff --git a/src/client/discord.ts b/src/client/discord.ts
deleted file mode 100644 (file)
index 76bb0f5..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-import $ from 'jquery';
-import {Socket} from 'socket.io-client';
-import {Message} from '../shared/message';
-
-type DiscordWidget = HTMLElement & {
-  on: (event: string, handler: any) => void;
-  emit: (event: string, data: any) => void;
-}
-
-type DiscordUser = {
-  _id: string;
-  avatar: string;
-  blockedUsers: string[],
-  discriminator: string;
-  provider: "Discord",
-  username: string
-}
-
-function $el(): DiscordWidget {
-  return document.getElementById('discord-widget') as DiscordWidget;
-}
-
-function loadPersistedUser(): DiscordUser {
-  let user = localStorage.getItem('discordChat');
-  if(user) {
-    return JSON.parse(user) as DiscordUser;
-  }
-  else {
-    throw new Error('No discord user');
-  }
-}
-
-//@ts-ignore
-$el().on('signIn', (user: DiscordUser) => {
-  localStorage.setItem('discordChat', JSON.stringify(user));
-
-  setUserAvatarFromDiscord(user.avatar);
-});
-
-function setUserAvatarFromDiscord(url: string) {
-  $('#avatar').attr('src', url);
-}
-
-export function configureDiscordChat(socket: Socket) {
-  try {
-    const user = loadPersistedUser();
-    setUserAvatarFromDiscord(user.avatar);
-
-    socket.on('login', (msg: Message) => {
-
-      console.log('ok logged in');
-      $el().emit('sendMessage', {
-        message: msg.msg
-      });
-    });
-  }
-  catch(e) {
-
-  }
-}
diff --git a/src/client/events.ts b/src/client/events.ts
deleted file mode 100644 (file)
index faf1ce1..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-export class CustomEventManager {
-  events: Record<string, any[]>;
-  constructor() {
-    this.events = {};
-  }
-
-  on(eventName: string, handler: any) {
-    if(!this.events[eventName]) {
-      this.events[eventName] = [];
-    }
-
-    this.events[eventName].push(handler);
-  }
-
-  emit(eventName: string, args: any[] = []) {
-    if(this.events[eventName]) {
-      this.events[eventName].forEach(h => h.apply(null, args));
-    }
-  }
-}
index a4107d8b90da1b45cd7fc4f1a8562f6a0ac0722d..a17db597f5c74706cd348f001d840e7a9819b001 100644 (file)
@@ -1,7 +1,5 @@
 import { io } from 'socket.io-client';
 import { io } from 'socket.io-client';
-import { authToken } from './http';
 import { TimeManager } from '../shared/time';
 import { TimeManager } from '../shared/time';
-import { configureChat } from './chat';
 
 function $<T>(selector: string, root: any = document): T {
   return root.querySelector(selector) as T;
 
 function $<T>(selector: string, root: any = document): T {
   return root.querySelector(selector) as T;
@@ -10,6 +8,12 @@ function $<T>(selector: string, root: any = document): T {
 function $$<T>(selector: string, root: any = document): T[] {
   return Array.from(root.querySelectorAll(selector)) as T[];
 }
 function $$<T>(selector: string, root: any = document): T[] {
   return Array.from(root.querySelectorAll(selector)) as T[];
 }
+
+export function authToken(): string {
+  const token = localStorage.getItem('authToken');
+  return token || '';
+}
+
 function setTimeGradient() {
   const gradientName = time.gradientName();
   const $body = $<HTMLElement>('body');
 function setTimeGradient() {
   const gradientName = time.gradientName();
   const $body = $<HTMLElement>('body');
@@ -34,6 +38,10 @@ function setTimeGradient() {
   $<HTMLElement>('#time-of-day').innerHTML = `<img src="/assets/img/icons/time-of-day/${icon}.png"> ${time.getHour()}${time.getAmPm()}`;
 }
 
   $<HTMLElement>('#time-of-day').innerHTML = `<img src="/assets/img/icons/time-of-day/${icon}.png"> ${time.getHour()}${time.getAmPm()}`;
 }
 
+function renderChatMessage(msg: string) {
+  $<HTMLElement>('#chat-messages').innerHTML += msg;
+  $<HTMLElement>('#chat-messages').scrollTop = $<HTMLElement>('#chat-messages').scrollHeight;
+}
 
 const time = new TimeManager();
 const socket = io({
 
 const time = new TimeManager();
 const socket = io({
@@ -53,7 +61,7 @@ socket.on('authToken', (authToken: string) => {
   localStorage.setItem('authToken', authToken);
 });
 
   localStorage.setItem('authToken', authToken);
 });
 
-
+socket.on('chat', renderChatMessage);
 socket.on('ready', bootstrap);
 
 
 socket.on('ready', bootstrap);
 
 
@@ -157,7 +165,6 @@ modalMutations.observe($<HTMLElement>('#alerts'), { childList: true });
 
 function bootstrap() {
   console.log('Server connection verified');
 
 function bootstrap() {
   console.log('Server connection verified');
-  configureChat(socket);
   $$<HTMLElement>('nav a')[0].click();
 }
 document.body.addEventListener('htmx:configRequest', function(evt) {
   $$<HTMLElement>('nav a')[0].click();
 }
 document.body.addEventListener('htmx:configRequest', function(evt) {
@@ -174,5 +181,10 @@ document.body.addEventListener('htmx:beforeSwap', function(e) {
   if(el.id === 'chat-form') {
     $<HTMLInputElement>('#message').value = '';
   }
   if(el.id === 'chat-form') {
     $<HTMLInputElement>('#message').value = '';
   }
+  //@ts-ignore
+  else if(e.detail.serverResponse === 'logout') {
+    localStorage.removeItem('authToken');
+    window.location.reload();
+  }
 });
 
 });
 
diff --git a/src/client/http.ts b/src/client/http.ts
deleted file mode 100644 (file)
index 312cea1..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-export function authToken(): string {
-  return localStorage.getItem('authToken');
-}
-
-export const http = {
-  get: async (path: string) => {
-    const res = await fetch(path, {
-      headers: {
-        'x-authtoken': authToken()
-      }
-    });
-    return res.json();
-  },
-  post: async (path: string, data: any) => {
-    const res = await fetch(path, {
-      method: 'post',
-      body: JSON.stringify(data),
-      headers: {
-        'x-authtoken': authToken(),
-        'content-type': 'application/json'
-      }
-    });
-
-    try {
-      return res.json();
-    }
-    catch {
-      console.log('No valid JSON response');
-      return null;
-    }
-  }
-}
diff --git a/src/client/index.ts b/src/client/index.ts
deleted file mode 100644 (file)
index b460ead..0000000
+++ /dev/null
@@ -1,1117 +0,0 @@
-import { io } from 'socket.io-client';
-import $ from 'jquery';
-import {expToLevel, maxHp, Player, StatDef, StatDisplay} from '../shared/player';
-import { authToken, http } from './http';
-import { CustomEventManager } from './events';
-import {Fight, FightTrigger, MonsterForFight, MonsterForList} from '../shared/monsters';
-import {FightRound} from '../shared/fight';
-import { City, Location, LocationType, Path } from '../shared/map'
-import { v4 as uuid } from 'uuid';
-import {EquipmentSlot, ShopEquipment} from '../shared/inventory';
-import { capitalize, each } from 'lodash';
-import {EquippedItemDetails} from '../shared/equipped';
-import { Skill, Skills } from '../shared/skills';
-import { configureChat } from './chat';
-import { SocketEvent } from './socket-event.client';
-import * as EventList from '../events/client';
-import { TimeManager } from '../shared/time';
-import { TravelDTO } from '../events/travel/shared';
-import { Item, PlayerItem, ShopItem } from '../shared/items';
-import { Modal } from './modal';
-
-
-const time = new TimeManager();
-const cache = new Map<string, any>();
-const events = new CustomEventManager();
-const socket = io({
-  extraHeaders: {
-    'x-authtoken': authToken()
-  }
-});
-
-configureChat(socket);
-
-function setTimeGradient() {
-  const gradientName = time.gradientName();
-  const $body = $('body');
-  $body.removeClass(Array.from($body[0].classList)).addClass(gradientName);
-  $body.addClass(time.getTimePeriod());
-
-  let icon: string;
-  if(time.get24Hour() >= 5 && time.get24Hour() < 9) {
-    icon = 'morning';
-  }
-  else if(time.get24Hour() >= 9 && time.get24Hour() < 17) {
-    icon = 'afternoon';
-  }
-  else if(time.get24Hour() >= 17 && time.get24Hour() < 20) {
-    icon = 'evening'
-  }
-  else {
-    icon = 'night';
-  }
-  
-  $('#time-of-day').html(`<img src="/assets/img/icons/time-of-day/${icon}.png"> ${time.getHour()}${time.getAmPm()}`);
-}
-
-setTimeGradient();
-setInterval(setTimeGradient, 60 * 1000);
-
-function icon(name: string): string {
-  return `<img src="/assets/img/${name}.png" class="icon">`;
-}
-
-
-function generateProgressBar(current: number, max: number, color: string, displayPercent: boolean = true): string {
-  let percent = 0;
-  if(max > 0) {
-    percent = Math.floor((current / max) * 100);
-  }
-  const display = `${displayPercent? `${percent}% - `: ''}`;
-  return `<div class="progress-bar" style="background: linear-gradient(to right, ${color}, ${color} ${percent}%, transparent ${percent}%, transparent)" title="${display}${current}/${max}">${display}${current}/${max}</div>`;
-}
-
-function progressBar(current: number, max: number, el: string, color: string) {
-  let percent = 0;
-  if(max > 0) {
-    percent = Math.floor((current / max) * 100);
-  }
-  $(`#${el}`).css(
-    'background',
-    `linear-gradient(to right, ${color}, ${color} ${percent}%, transparent ${percent}%, transparent)`
-  ).attr('title', `${percent}% - ${current}/${max}`).html(`${current}/${max} - ${percent}%`);
-}
-
-function updatePlayer() {
-  const player: Player = cache.get('player');
-
-  $('#username').html(`${player.username}, level ${player.level} ${player.profession}`);
-
-  progressBar(
-    player.hp,
-    maxHp(player.constitution, player.level),
-    'hp-bar',
-    '#ff7070'
-  );
-
-  progressBar(
-    player.exp,
-    expToLevel(player.level + 1),
-    'exp-bar',
-    '#5997f9'
-  );
-
-  ['strength', 'constitution', 'dexterity', 'intelligence','hp','exp'].forEach(s => {
-    $(`.${s}`).html(player[s]);
-  });
-
-  $('.maxHp').html(maxHp(player.constitution, player.level).toString());
-  $('.expToLevel').html(expToLevel(player.level + 1).toString());
-  $('.gold').html(player.gold.toLocaleString());
-
-  if(player.account_type === 'session') {
-    $('#signup-prompt').html(`<p>Hey there! It looks like you're using a SESSION account. This allows you to play with away, but the account is tied to your current device, and will be lost if you ever clear your cookies.</p><p>
-          <form id="signup">
-            <div class="form-group">
-              <label>Username:</label>
-              <input type="text" name="username">
-            </div>
-            <div class="form-group">
-              <label>Password:</label>
-              <input type="password" name="password">
-            </div>
-            <button type="submit" class="success">Create your Account</button>
-            <button type="button" id="login">Login To Existing Account</button>
-          </form></p>`).removeClass('hidden');
-  }
-
-  $('#extra-inventory-info').html(renderStatDetails());
-}
-
-socket.on('connect', () => {
-  console.log(`Connected: ${socket.id}`);
-});
-
-socket.on('ready', bootstrap);
-
-socket.on('server-stats', (data: {onlinePlayers: number}) => {
-  $('#server-stats').html(`${data.onlinePlayers} players online`);
-});
-
-each(EventList, event => {
-  console.log(`Binding Event ${event.eventName}`);
-  if(event instanceof SocketEvent) {
-    socket.on(event.eventName, event.handler.bind(null, {
-      cache,
-      socket,
-      events
-    }));
-  }
-  else {
-    console.log('Skipped binding', event);
-  }
-});
-
-socket.on('calc:ap', (data: {ap: Record<EquipmentSlot, { currentAp: number, maxAp: number}>}) => {
-  const { ap } = data;
-  const html = `
-  <div>
-    ${icon('helm')}
-    ${generateProgressBar(ap.HEAD?.currentAp || 0, ap.HEAD?.maxAp || 0, '#7be67b')}
-  </div>
-  <div>
-    ${icon('arms')}
-    ${generateProgressBar(ap.ARMS?.currentAp || 0, ap.ARMS?.maxAp || 0, '#7be67b')}
-  </div>
-  <div>
-    ${icon('chest')}
-    ${generateProgressBar(ap.CHEST?.currentAp || 0, ap.CHEST?.maxAp || 0, '#7be67b')}
-  </div>
-  <div>
-    ${icon('legs')}
-    ${generateProgressBar(ap.LEGS?.currentAp || 0, ap.LEGS?.maxAp || 0, '#7be67b')}
-  </div>
-  `;
-  $('#ap-bar').html(html);
-});
-
-events.on('tab:skills', () => {
-  $('#skills').html('');
-  socket.emit('skills');
-});
-
-socket.on('skills', (data: {skills: Skill[]}) => {
-  let html = `<table id="skill-list">
-  ${data.skills.map((skill: Skill) => {
-    const definition = Skills.get(skill.id);
-    const percent = skill.exp / definition.expToLevel(skill.level + 1);
-    return `
-    <tr>
-    <td class="skill-level">${skill.level.toLocaleString()}</td>
-    <td class="skill-description" title="Total Exp: ${skill.exp.toLocaleString()}/${definition.expToLevel(skill.level + 1).toLocaleString()}">
-      <span class="skill-exp">${(percent * 100).toPrecision(2)}% to next level</span>
-      <b>${definition.display}</b>
-      <p>${definition.description}</p>
-    </td>
-    </tr>
-    `;
-  }).join("\n")}
-  </table>`;
-
-  $('#skills').html(html);
-});
-
-function Alert(text: string, type: string = 'error') {
-  let id = uuid();
-  $('#alerts').append(`<div class="alert ${type}" id="alert-${id}">${text}</div>`);
-
-  setTimeout(() => {
-    $(`#alert-${id}`).remove();
-  }, 3000);
-}
-
-events.on('alert', (data: {type: string, text: string}) => {
-  Alert(data.text, data.type);
-});
-
-socket.on('alert', data => {
-  events.emit('alert', [data]);
-});
-
-socket.on('init', (data: {version: string}) => {
-  $('#version').html(`v${data.version}`);
-});
-
-socket.on('authToken', (authToken: string) => {
-  console.log(`recv auth token ${authToken}`);
-  localStorage.setItem('authToken', authToken);
-});
-
-
-socket.on('player', (player: Player) => {
-  cache.set('player', player);
-  updatePlayer();
-});
-
-async function fetchState() {
-  const res = await http.get('/state');
-  cache.set('state', res);
-}
-
-$('nav a').on('click', async e => {
-  e.preventDefault();
-  e.stopPropagation();
-
-  const tabsDisabledInFight = [
-    'skills',
-    'inventory'
-  ];
-
-  await fetchState();
-  const state = cache.get('state');
-
-  const $tabContainer = $(`#${$(e.target).data('container')}`);
-  let tabSection = $(e.target).data('section');
-
-  if(tabsDisabledInFight.includes(tabSection) && state?.fight !== null) {
-    Alert('You are currently in a fight', 'error');
-    // we want to force users over to the explore tab 
-    // if they are currently in a fight and trying to 
-    // access a disabled section
-    tabSection = 'explore';
-  }
-
-  $tabContainer.find('.tab').removeClass('active');
-
-  $(`#${tabSection}`).addClass('active');
-
-  if(e.target.innerHTML !== 'Settings') {
-    $(e.target).closest('nav').find('a').removeClass('active');
-    $(`nav a[data-section=${tabSection}]`).addClass('active');
-  }
-
-  events.emit(`tab:${tabSection}`);
-});
-
-events.on('tab:inventory', () => {
-  socket.emit('inventory');
-});
-
-function renderEquipmentPlacementGrid(items: EquippedItemDetails[]) {
-  const placeholder = 'https://via.placeholder.com/64x64';
-  // @ts-ignore
-  const map: Record<EquipmentSlot, EquippedItemDetails> = items.filter(item => item.is_equipped).reduce((acc, item) => {
-    acc[item.equipment_slot] = item;
-    return acc;
-  }, {});
-
-  const html = `
-  <table id="character-equipment-placement">
-  <tr>
-    <td>
-    </td>
-    <td style="background-image: url('${placeholder}');" title="${map.HEAD ? map.HEAD.name : 'Empty'}">
-    ${map.HEAD ? map.HEAD.name : 'HEAD'}
-    </td>
-    <td style="background-image: url('${placeholder}');" title="${map.ARMS ? map.ARMS.name : 'Empty'}">
-    ${map.ARMS ? map.ARMS.name : 'ARMS'}
-    </td>
-  </tr>
-  <tr>
-    <td style="background-image: url('${placeholder}');" title="${map.LEFT_HAND ? map.LEFT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : '')}">
-    ${map.LEFT_HAND ? map.LEFT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : 'L_HAND')}
-    </td>
-    <td style="background-image: url('${placeholder}');" title="${map.CHEST ? map.CHEST.name : ''}">
-    ${map.CHEST ? map.CHEST.name : 'CHEST'}
-    </td>
-    <td style="background-image: url('${placeholder}');" title="${map.RIGHT_HAND ? map.RIGHT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : '')}">
-    ${map.RIGHT_HAND ? map.RIGHT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : 'R_HAND')}
-    </td>
-  </tr>
-  <tr>
-    <td>
-    </td>
-    <td style="background-image: url('${placeholder}');" title="${map.LEGS ? map.LEGS.name : ''}">
-    ${map.LEGS ? map.LEGS.name : 'LEGS'}
-    </td>
-    <td>
-    </td>
-  </tr>
-  </table>
-  `;
-
-  return html;
-}
-function statPointIncreaser(stat: StatDisplay) {
-  return `<button class="increase-stat emit-event" data-event="spend-stat-point" data-args="${stat.id}">+</button>`;
-}
-function renderStatDetails() {
-  const player: Player = cache.get('player');
-  let html = '<table id="stat-breakdown">';
-
-  StatDef.forEach(stat => {
-    html += `<tr>
-      <th>${stat.display}</th>
-      <td class="${stat.id}">
-        ${player[stat.id]}
-        ${player.stat_points ? statPointIncreaser(stat) : ''}
-      </td>
-    </tr>`;
-  });
-
-  html += `<tr><th>Stat Points</th><td class="stat_points">${player.stat_points}</td></tr>`;
-
-  html += '</table>';
-
-  return html;
-}
-
-$('body').on('click', 'nav.filter', e => {
-  e.preventDefault();
-  e.stopPropagation();
-
-  const $target = $(e.target);
-  const filter = $target.data('filter');
-
-  $('.filter-result').removeClass('active').addClass('hidden');
-  $(`#filter_${filter}`).addClass('active').removeClass('hidden');
-
-  $target.closest('nav').find('a').removeClass('active');
-  $target.addClass('active');
-
-  const cacheKey = `active-${$(e.target).closest('nav').attr('id')}`;
-
-  cache.set(cacheKey, filter);
-});
-
-$('body').on('click', '.close-modal', e => {
-  const $el = $(e.target).closest('dialog').get(0) as HTMLDialogElement;
-  $el.close();
-  $el.remove();
-});
-
-$('body').on('click', '.trigger-modal', (e) => {
-  const $el = $(e.target).closest('.trigger-modal');
-  const modal = new Modal();
-
-  modal.on('ready', async (m: Modal) => {
-    const res: {description: string} = await http.get($el.data('endpoint'));
-
-    m.setBody(res.description);
-    
-    m.showModal();
-  });
-
-  modal.render();
-});
-
-
-function renderInventoryItems(items: PlayerItem[]): string {
-  return items.map(item => {
-    return `
-    <div class="player-item trigger-modal" data-endpoint="/modal/items/${item.item_id}">
-      <img src="/assets/img/icons/items/${item.icon_name}" title="${item.name}">
-      <span class="amount">${item.amount.toLocaleString()}</span>
-    </div>`;
-  }).join("<br>");
-
-}
-
-function renderInventorySection(inventory: EquippedItemDetails[]): string {
-  return inventory.map(item => {
-    return renderInventoryItem(item, item => {
-      if(item.is_equipped) {
-        return `<button type="button" class="unequip-item error" data-id="${item.item_id}">Unequip</button>`;
-      }
-      else {
-        if(item.equipment_slot === 'ANY_HAND') {
-          return `<button type="button" class="equip-item" data-id="${item.item_id}" data-slot="LEFT_HAND">Equip L</button>
-          <button type="button" class="equip-item" data-id="${item.item_id}" data-slot="RIGHT_HAND">Equip R</button>`;
-        }
-        else if(item.equipment_slot === 'LEFT_HAND') {
-          return `<button type="button" class="equip-item" data-id="${item.item_id}" data-slot="${item.equipment_slot}">Equip Left</button>`;
-        }
-        else if(item.equipment_slot === 'RIGHT_HAND') {
-          return `<button type="button" class="equip-item" data-id="${item.item_id}" data-slot="${item.equipment_slot}">Equip Right</button>`;
-        }
-        else if(item.equipment_slot === 'TWO_HANDED') {
-          return `<button type="button" class="equip-item" data-id="${item.item_id}" data-slot="${item.equipment_slot}">Equip</button>`;
-        }
-        else {
-          return `<button type="button" class="equip-item" data-id="${item.item_id}" data-slot="${item.equipment_slot}">Equip</button>`;
-        }
-      }
-    })
-  }).join("\n");
-}
-
-events.on('tab:profile', () => {
-  const html = `<div id="extra-inventory-info">
-    ${renderStatDetails()}
-  </div>`;
-
-  $('#profile').html(html);
-});
-
-socket.on('inventory', (data: {inventory: EquippedItemDetails[], items: PlayerItem[]}) => {
-  const player: Player = cache.get('player');
-  const activeSection = cache.get('active-inventory-section') || 'ARMOUR';
-  // split the inventory into sections!
-  const sectionedInventory: {ARMOUR: EquippedItemDetails[], WEAPON: EquippedItemDetails[], SPELL: EquippedItemDetails[], ITEMS: PlayerItem[]} = {
-    ARMOUR: [],
-    WEAPON: [],
-    SPELL: [],
-    ITEMS: []
-  };
-
-  data.inventory.forEach(item => {
-    sectionedInventory[item.type].push(item);
-  });
-  data.items.forEach(item => {
-    sectionedInventory.ITEMS.push(item);
-  });
-
-  const html = `
-  <div id="inventory-page">
-    <div id="character-summary">
-    ${renderEquipmentPlacementGrid(data.inventory)}
-    </div>
-    <div id="inventory-section" class="filter-container">
-      <nav class="filter" id="inventory-section">
-        ${Object.keys(sectionedInventory).map(type => {
-          return `<a href="#" data-filter="${type}" class="${activeSection === type ? 'active': ''}">${capitalize(type)}</a>`;
-        }).join("")}
-      </nav>
-      <div class="inventory-listing listing">
-        ${Object.keys(sectionedInventory).map(type => {
-          return `<div class="filter-result ${activeSection === type ? 'active' : 'hidden'} inventory-${type}" id="filter_${type}">
-            ${type === 'ITEMS' ? renderInventoryItems(sectionedInventory[type]) : renderInventorySection(sectionedInventory[type])}
-          </div>`;
-
-        }).join("")}
-      </div>
-    </div>
-  </div>
-  `;
-  $('#inventory').html(html);
-});
-
-$('body').on('click', '.equip-item', e => {
-  e.preventDefault();
-  e.stopPropagation();
-
-  const $target = $(e.target);
-  const id = $target.data('id');
-  const slot = $target.data('slot');
-
-  socket.emit('equip', {id, slot});
-});
-
-$('body').on('click', '.unequip-item', e => {
-  e.preventDefault();
-  e.stopPropagation();
-
-  socket.emit('unequip', { id: $(e.target).data('id') });
-});
-
-function setMapBackground(city_id: number) {
-  $('#explore').css({
-    'background-image': `linear-gradient(to left top, rgba(255,255,255,0) 0%,rgb(255,255,255) 100%), linear-gradient(to left, rgba(255, 255, 255, 0) 0%, rgb(255, 255, 255) 100%), url("/assets/img/map/${city_id}.jpeg")`
-  });
-}
-
-events.on('renderMap', async function renderMap(data: { city: City, locations: Location[], paths: Path[]}) {
-  if(!data && cache.has('currentMapHTML')) {
-    $('#map').html(cache.get('currentMapHTML'));
-    return;
-  }
-
-  if(!data) {
-    console.error('oh no.. this got triggered without any city data');
-  }
-
-  setMapBackground(data.city.id);
-
-  const servicesParsed: Record<LocationType, string[]> = {
-    'SERVICES': [],
-    'STORES': [],
-    'EXPLORE': []
-  };
-
-  data.locations.forEach(l => {
-    servicesParsed[l.type].push(`<a href="#" class="city-emit-event" data-event="${l.event_name}" data-args="${l.id}">${l.name}</a>`);
-  });
-
-  let html = `<h1>${data.city.name}</h1>
-  <div class="city-details">`;
-
-  if(servicesParsed.SERVICES.length) {
-    html += `<div><h3>Services</h3>${servicesParsed.SERVICES.join("<br>")}</div>`
-  }
-  if(servicesParsed.STORES.length) {
-    html += `<div><h3>Stores</h3>${servicesParsed.STORES.join("<br>")}</div>`
-  }
-  if(servicesParsed.EXPLORE.length) {
-    html += `<div><h3>Explore</h3>${servicesParsed.EXPLORE.join("<br>")}</div>`
-  }
-  html += `
-    <div>
-      <h3>Travel</h3>
-      ${data.paths.map(path => {
-        return `<a href="#" class="city-emit-event" data-event="city:travel" data-args="${path.ending_city}">${path.ending_city_name}</a>`
-      }).join("<br>")}
-    </div>
-  </div>
-  `;
-
-  cache.set('currentMapHTML', html);
-
-  $('#map').html(html);
-});
-
-function renderRequirement(name: string, val: number | string, currentVal?: number): string {
-  let colorIndicator = '';
-  if(currentVal) {
-    colorIndicator = currentVal >= val ? 'success' : 'error';
-  }
-  return `<span class="requirement-title">${name}</span>: <span class="requirement-value ${colorIndicator}">${val.toLocaleString()}</span>`;
-}
-
-function renderStatBoost(name: string, val: number | string): string {
-  let valSign: string = '';
-  if(typeof val === 'number') {
-    valSign = val > 0 ? '+' : '-';
-  }
-  return `<span class="requirement-title">${name}</span>: <span class="requirement-value ${typeof val === 'number' ? (val > 0 ? "success": "error") : ""}">${valSign}${val}</span>`;
-}
-
-function renderInventoryItem(item: EquippedItemDetails , action: (item: EquippedItemDetails) => string): string {
-    return `<div class="store-list">
-    <div>
-      <img src="https://via.placeholder.com/64x64">
-    </div>
-    <div class="details">
-      <div class="name">${item.name}</div>
-      <div class="requirements">
-      ${item.requirements.level ? renderRequirement('LVL', item.requirements.level): ''}
-      ${item.requirements.strength ? renderRequirement('STR', item.requirements.strength): ''}
-      ${item.requirements.constitution ? renderRequirement('CON', item.requirements.constitution): ''}
-      ${item.requirements.dexterity ? renderRequirement('DEX', item.requirements.dexterity): ''}
-      ${item.requirements.intelligence ? renderRequirement('INT', item.requirements.intelligence): ''}
-      ${renderRequirement('PRF', item.profession)}
-      </div>
-      <div class="stat-mods">
-      ${item.boosts.strength ? renderStatBoost('STR', item.boosts.strength) : ''}
-      ${item.boosts.constitution ? renderStatBoost('CON', item.boosts.constitution) : ''}
-      ${item.boosts.dexterity ? renderStatBoost('DEX', item.boosts.dexterity) : ''}
-      ${item.boosts.intelligence ? renderStatBoost('INT', item.boosts.intelligence) : ''}
-      ${item.boosts.damage ? renderStatBoost('DMG', item.boosts.damage) : ''}
-      ${item.boosts.damage_mitigation ? renderStatBoost('MIT', item.boosts.damage_mitigation.toString())+'%' : ''}
-      ${['WEAPON','SPELL'].includes(item.type) ? '': generateProgressBar(item.currentAp, item.maxAp, '#7be67b')}
-      </div>
-      ${item.hasOwnProperty('id') ? `<div>${item.cost.toLocaleString()}G</div>` : ''}
-    </div>
-    <div class="store-actions">
-      ${action(item)}
-    </div>
-    </div>`;
-}
-
-function renderShopEquipment(item: ShopEquipment, action: (item: ShopEquipment) => string): string {
-  const player: Player = cache.get('player');
-    return `<div class="store-list">
-    <div>
-      <img src="https://via.placeholder.com/64x64">
-    </div>
-    <div class="details">
-      <div class="name">${item.name}${item.equipment_slot === 'TWO_HANDED' ? ' (2H)': ''}</div>
-      <div class="requirements">
-      ${item.requirements.level ? renderRequirement('LVL', item.requirements.level, player.level): ''}
-      ${item.requirements.strength ? renderRequirement('STR', item.requirements.strength, player.strength): ''}
-      ${item.requirements.constitution ? renderRequirement('CON', item.requirements.constitution, player.constitution): ''}
-      ${item.requirements.dexterity ? renderRequirement('DEX', item.requirements.dexterity, player.dexterity): ''}
-      ${item.requirements.intelligence ? renderRequirement('INT', item.requirements.intelligence, player.intelligence): ''}
-      ${renderRequirement('PRF', item.profession)}
-      </div>
-      <div class="stat-mods">
-      ${item.boosts.strength ? renderStatBoost('STR', item.boosts.strength) : ''}
-      ${item.boosts.constitution ? renderStatBoost('CON', item.boosts.constitution) : ''}
-      ${item.boosts.dexterity ? renderStatBoost('DEX', item.boosts.dexterity) : ''}
-      ${item.boosts.intelligence ? renderStatBoost('INT', item.boosts.intelligence) : ''}
-      ${item.boosts.damage ? renderStatBoost(item.affectedSkills.includes('restoration_magic') ? 'HP' : 'DMG', item.boosts.damage) : ''}
-      ${item.boosts.damage_mitigation ? renderStatBoost('MIT', item.boosts.damage_mitigation.toString())+'%' : ''}
-      ${['WEAPON','SPELL'].includes(item.type) ? '' : renderStatBoost('AP', item.maxAp.toString())}
-      </div>
-      ${item.hasOwnProperty('id') ? `<div>${item.cost.toLocaleString()}G</div>` : ''}
-    </div>
-    <div class="store-actions">
-      ${action(item)}
-    </div>
-    </div>`;
-}
-
-function renderShopItem(item: (ShopItem & Item), action: (item: (ShopItem & Item)) => string): string {
-  const player: Player = cache.get('player');
-    return `<div class="store-list">
-    <div>
-      <img src="/assets/img/icons/items/${item.icon_name}" title="${item.name}">
-    </div>
-    <div class="details">
-      <div class="name">${item.name}</div>
-      <div class="requirements">
-        ${item.description}
-      </div>
-      ${item.hasOwnProperty('id') ? `<div>${item.price_per_unit.toLocaleString()}G</div>` : ''}
-    </div>
-    <div class="store-actions">
-      ${action(item)}
-    </div>
-    </div>`;
-}
-
-socket.on('city:stores', (data: {equipment: ShopEquipment[], items: (ShopItem & Item)[]}) => {
-  const listing: Record<string, string> = {};
-  const listingTypes = new Set<string>();
-  const { equipment, items } = data;
-  equipment.forEach(item => {
-    if(item.type === 'ARMOUR') {
-      listingTypes.add(item.equipment_slot);
-
-      if(!listing[item.equipment_slot]) {
-        listing[item.equipment_slot] = '';
-      }
-      
-      listing[item.equipment_slot] += renderShopEquipment(item, i => {
-        const id = `data-id="${i.id}"`;
-        return `<button type="button" class="purchase-item" ${id} data-type="${i.type}" data-equipment-slot="${i.equipment_slot}" data-cost="${i.cost}">Buy</button>`
-      });
-    }
-    else if(item.type) {
-      listingTypes.add(item.type);
-      if(!listing[item.type]) {
-        listing[item.type] = '';
-      }
-      
-      listing[item.type] += renderShopEquipment(item, i => {
-        const id = `data-id="${i.id}"`;
-        return `<button type="button" class="purchase-item" ${id} data-type="${i.type}" data-equipment-slot="${i.equipment_slot}" data-cost="${i.cost}">Buy</button>`
-      });
-    }
-    else {
-      console.log('no type', item);
-    }
-  });
-
-  if(items && items.length) {
-    listingTypes.add('ITEMS');
-    listing['ITEMS'] = '';
-    items.forEach(item => {
-      listing['ITEMS'] += renderShopItem(item, i => {
-        return `<button type="button" class="trigger-modal" data-endpoint="/modal/location/${i.location_id}/purchase/items/${item.item_id}">Buy</button>`;
-      });
-    });
-  }
-
-  const sections = Object.keys(listing);
-  let activeSection = cache.get('active-shop-inventory-listing');
-
-  if(!sections.includes(activeSection)) {
-    activeSection = sections[0];
-  }
-
-  const nav: string[] = [];
-  const finalListing: string[] = [];
-
-  listingTypes.forEach(type => {
-    nav.push(`<a href="#" data-filter="${type}" class="${activeSection === type ? 'active': ''}">${capitalize(type)}</a>`);
-    finalListing.push(`<div class="filter-result ${activeSection === type ? 'active': 'hidden'}" id="filter_${type}">${listing[type]}</div>`);
-  });
-
-  let html = `<div class="shop-inventory-listing filter-container">
-    <nav class="filter" id="shop-inventory-listing">${nav.join(" ")}</nav><div class="inventory-listing listing">
-      ${finalListing.join("\n")}
-    </div>
-  </div>`;
-
-  $('#map').html(html);
-
-});
-
-$('body').on('click', '.purchase-item', e => {
-  e.preventDefault();
-  e.stopPropagation();
-
-  const player = cache.get('player');
-  const cost = parseInt($(e.target).data('cost'));
-
-
-  const id = $(e.target).data('id');
-  if(player.gold < cost) {
-    events.emit('alert', [{
-      type: 'error',
-      text: 'You don\'t have enough gold!'
-    }]);
-    return;
-  }
-  else {
-    const type = $(e.target).data('type');
-    socket.emit('purchase', {
-      id
-    });
-  }
-});
-
-$('body').on('click', '.http-post', async e => {
-  const $el = $(e.target).closest('[data-endpoint]');
-  const endpoint = $el.data('endpoint');
-  const args = $el.data();
-
-  const res = await http.post(endpoint, args);
-});
-
-$('body').on('click', '.emit-event', e => {
-  const $el = $(e.target);
-
-  const eventName = $el.closest('[data-event]').data('event');
-  const args = $el.closest('[data-args]').data('args');
-
-  const rawBlock = $el.data('block');
-
-  if(rawBlock) {
-    const block = parseInt(rawBlock) || 0;
-
-    if(block > Date.now()) {
-      Alert('Sorry, clicked too quick');
-      return;
-    }
-  }
-
-  console.log(`Sending event ${eventName}`, { args });
-  socket.emit(eventName, { args });
-});
-
-$('body').on('click', '.city-emit-event', e => {
-  const $el = $(e.target);
-
-  const eventName = $el.data('event');
-  const args = $el.data('args');
-
-  console.log(`Sending event ${eventName}`, { args });
-  socket.emit(eventName, { args });
-});
-
-$('body').on('click', '.emit-event-internal', e => {
-  const $el = $(e.target);
-
-  const eventName = $el.data('event');
-  const args: string[] = $el.data('args')?.toString().split('|');
-
-  console.log(`Trigger internal event [${eventName}]`);
-  events.emit(eventName, args);
-});
-
-
-socket.on('explore:fights', (monsters: MonsterForList[]) => {
-  const lastSelectedMonster = cache.get('last-selected-monster');
-  if(monsters.length) {
-    let sel = `<form id="fight-selector"><select id="monster-selector">
-    ${monsters.map(monster => {
-      return `<option value="${monster.id}" ${lastSelectedMonster == monster.id ? 'selected': ''}>${monster.name}</option>`;
-    }).join("\n")}
-    </select> <button type="submit">Fight</button></option>`;
-
-    $('#map').html(sel);
-  }
-});
-
-events.on('tab:explore', async () => {
-  const state = cache.get('state');
-  if(cache.get('player').hp <= 0 || (!state.fight && !state.travel)) {
-    // get the details of the city
-    // render the map!
-    let data: {city: City, locations: Location[], paths: Path[]};
-    if(!cache.has(('currentMapHTML')) || cache.get('player').hp <= 0) {
-      data = await http.get(`/city/${cache.get('player').city_id}`);
-    }
-    events.emit('renderMap', [data, state.travel]);
-
-  }
-  else if(state.fight) {
-    setMapBackground(state.closestTown);
-    $('#map').html(renderFight(state.fight));
-  }
-  else if(state.travel) {
-    // render TRAVEL
-    events.emit('renderTravel', [state.travel]);
-  }
-});
-
-function updateStepButton() {
-  const raw = $('#keep-walking').data('block');
-  const time = parseInt(raw) || 0;
-
-  if(time > 0) {
-    const wait = Math.ceil((time - Date.now())/ 1000);
-    if(wait > 0) {
-      $('#keep-walking').prop('disabled', true).html(`Keep walking (${wait}s)`);
-      setTimeout(updateStepButton, 300);
-      return;
-    }
-  }
-
-  $('#keep-walking').prop('disabled', false).html(`Keep walking`);
-}
-
-function renderTravel(data: TravelDTO) {
-  setMapBackground(data.closestTown);
-
-  let promptText = data.walkingText;
-  const blockTime = data.nextAction || 0;
-  let html = `<div id="travelling">`;
-
-  html += '<div id="travelling-actions">';
-  html += `<button class="emit-event" id="keep-walking" data-event="travel:step" data-block="${blockTime}">Keep Walking</button>`;
-
-  if(data.things.length) {
-    // ok you found something, for now we only support 
-    // monsters, but eventually that will change
-    promptText = `You see a ${data.things[0].name}`;
-    html += `<button class="emit-event-internal" data-event="startFight" data-args="${data.things[0].id}|travel">Fight</button>`;
-  }
-
-  // end #travelling-actions
-  html += '</div>';
-  html += `<p>${promptText}</p>`;
-
-  // end #travelling div
-  html += '</div>';
-
-  $('#map').html(html);
-
-  if(blockTime) {
-    updateStepButton();
-  }
-}
-
-events.on('renderTravel', renderTravel);
-
-function renderFight(monster: MonsterForFight | Fight) {
-  const hpPercent = Math.floor((monster.hp / monster.maxHp) * 100);
-
-  let html = `<div id="fight-container">
-    <div id="defender-info">
-      <div class="avatar-container">
-        <img id="avatar" src="https://via.placeholder.com/64x64">
-      </div>
-      <div id="defender-stat-bars">
-        <div id="defender-name">${monster.name}</div>
-        <div class="progress-bar" id="defender-hp-bar" style="background: linear-gradient(to right, red, red ${hpPercent}%, transparent ${hpPercent}%, transparent)" title="${hpPercent}% - ${monster.hp}/${monster.maxHp}">${hpPercent}% - ${monster.hp} / ${monster.maxHp}</div>
-      </div>
-    </div>
-    <div id="fight-actions">
-      <select id="fight-target">
-        <option value="head">Head</option>
-        <option value="body">Body</option>
-        <option value="arms">Arms</option>
-        <option value="legs">Legs</option>
-      </select>
-      <button type="button" class="fight-action" data-action="attack">Attack</button>
-      <button type="button" class="fight-action" data-action="cast">Cast</button>
-      <button type="button" class="fight-action" data-action="flee">Flee</button>
-    </div>
-    <div id="fight-results"></div>
-  </div>`;
-
-  return html;
-}
-
-socket.on('updatePlayer', (player: Player) => {
-  cache.set('player', player);
-  updatePlayer();
-});
-
-socket.on('fight-over', (data: {roundData: FightRound, monsters: MonsterForFight[]}) => {
-  const { roundData, monsters } = data;
-  cache.set('player', roundData.player);
-  updatePlayer();
-
-  $('#map').html(renderFight(roundData.monster));
-
-  let html: string[] = roundData.roundDetails.map(d => `<div>${d}</div>`);
-
-  if(roundData.winner === 'player') {
-    html.push(`<div>You defeated the ${roundData.monster.name}!</div>`);
-    if(roundData.rewards.gold) {
-      html.push(`<div>You gained ${roundData.rewards.gold} gold`);
-    }
-    if(roundData.rewards.exp) {
-      html.push(`<div>You gained ${roundData.rewards.exp} exp`);
-    }
-    if(roundData.rewards.levelIncrease) {
-      html.push(`<div>You gained a level! ${roundData.player.level}`);
-    }
-  }
-
-  if(roundData.player.hp === 0) {
-    // prompt to return to town and don't let them do anything
-    html.push(`<p>You were killed...</p>`);
-    html.push('<p><button class="emit-event-internal" data-event="tab:explore" data-args="">Back to Town</button></p>');
-  }
-  else {
-    switch(roundData.fightTrigger) {
-      case 'explore':
-        if(monsters.length) {
-          const lastSelectedMonster = cache.get('last-selected-monster');
-          // put this above the fight details
-          html.unshift(`<h2>Fight Again</h2><form id="fight-selector"><select id="monster-selector">
-            ${monsters.map(monster => {
-              return `<option value="${monster.id}" ${lastSelectedMonster == monster.id ? 'selected': ''}>${monster.name}</option>`;
-            }).join("\n")}
-            </select> <button type="submit">Fight</button></option>
-          </select></form><hr>`);
-        }
-      break;
-      case 'travel':
-        html.push(`<p><button class="emit-event" data-event="travel:step">Keep Walking</button></p>`);
-      break;
-      default:
-        console.error(`Unknown fight trigger [${roundData.fightTrigger}]`, roundData);
-      break;
-    }
-  }
-
-
-
-  $('#fight-results').html(html.join("\n"));
-  $('#fight-actions').html('');
-
-});
-
-socket.on('fight-round', (data: FightRound) => {
-  $('.fight-action').prop('disabled', false);
-  cache.set('player', data.player);
-  updatePlayer();
-
-  $('#map').html(renderFight(data.monster));
-
-  $('#fight-results').html(data.roundDetails.map(d => `<div>${d}</div>`).join("\n"));
-});
-
-async function startFight(monsterId: string, fightTrigger: FightTrigger = 'explore') {
-  // check your HP first
-  if(cache.get('player').hp <= 0) {
-    events.emit('alert', [{
-      type: 'error',
-      text: 'You don\'t have enough HP to go looking for a fight'
-    }]);
-    return;
-  }
-
-  cache.set('last-selected-monster', monsterId);
-
-  try {
-    const monster: MonsterForFight = await http.post('/fight', {
-      monsterId,
-      fightTrigger
-    });
-
-    $('#map').html(renderFight(monster));
-  }
-  catch(e) {
-    events.emit('alert', [{
-      type: 'error',
-      text: 'Sorry, you can\'t start that fight'
-    }]);
-  }
-}
-
-events.on('startFight', startFight);
-
-$('body').on('submit', '#fight-selector', async e => {
-  e.preventDefault();
-  e.stopPropagation();
-
-  const monsterId = $('#monster-selector option:selected').val();
-
-  if(monsterId) {
-    startFight(monsterId.toString());
-  }
-  else {
-    console.error(`Invalid monster id [${monsterId}]`);
-  }
-
-});
-
-$('body').on('click', '.fight-action', e => {
-  e.preventDefault();
-  e.stopPropagation();
-
-  const action = $(e.target).data('action');
-  const target = $('#fight-target option:selected').val();
-  $('.fight-action').prop('disabled', true);
-
-  socket.emit('fight', { action, target });
-});
-
-$('body').on('submit', '#signup', async e => {
-  e.preventDefault();
-  e.stopPropagation();
-
-  const data: Record<string, string> = {}; 
-
-  $(e.target).serializeArray().forEach(v => data[v.name] = v.value);
-
-  const res = await http.post('/signup', data);
-
-  if(res.error) {
-    events.emit('alert', [{
-      type: 'error',
-      text: res.error
-    }]);
-  }
-  else {
-    cache.set('player', res.player);
-    updatePlayer();
-    $('#signup-prompt').remove();
-  }
-
-});
-
-$('body').on('click', '#login', async e => {
-  e.preventDefault();
-  e.stopPropagation();
-
-  const data: Record<string, string> = {}; 
-
-  $(e.target).closest('form').serializeArray().forEach(v => data[v.name] = v.value);
-
-  if(data.username && data.password) {
-    const res = await http.post('/login', data);
-    if(res.error) {
-      events.emit('alert', [{type: 'error', text: res.error}]);
-    }
-    else {
-      localStorage.setItem('authToken', res.player.id);
-      window.location.reload();
-    }
-  }
-});
-
-$('body').on('click', '#logout', async e => {
-  e.preventDefault();
-  e.stopPropagation();
-
-  let logout = false;
-
-  const player = cache.get('player');
-  if(/^Player[\d]+$/.test(player.username)) {
-    const clear = confirm('Are you sure? You will not be able to retrieve this character unless you set up an email/password');
-    if(clear) {
-      logout = true;
-    }
-    else {
-      logout = false;
-    }
-  }
-  else {
-    logout = true;
-  }
-
-  if(logout) {
-    socket.emit('logout');
-    localStorage.clear();
-    window.location.reload();
-  }
-
-});
-
-function bootstrap() {
-  console.log('Server connection verified');
-  //socket.emit('inventory');
-  $('nav a').first().click();
-
-}
-document.body.addEventListener('htmx:configRequest', function(evt) {
-  //@ts-ignore
-  evt.detail.headers['x-authtoken'] = authToken();
-});
diff --git a/src/client/modal.ts b/src/client/modal.ts
deleted file mode 100644 (file)
index 1eabdac..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-import { v4 as uuid } from 'uuid';
-import $ from 'jquery';
-import { CustomEventManager } from './events';
-
-export class Modal extends CustomEventManager {
-  id: string;
-  constructor() {
-    super();
-    this.id = `id-${uuid()}`;
-  }
-
-  setBody(text: string) {
-    this.$el().find('.modal-body').html(text);
-  }
-
-  render(visible: boolean = false) {
-    let html = `
-    <dialog id="${this.id}">
-      <div class="modal-header"><span class="close-modal">x</span></div>
-      <div class="modal-body">Modal Body!</div>
-    </dialog>
-    `;
-
-    if(this.$el().length) {
-      this.showModal();
-    }
-    else {
-      $('body').append(html);
-      this.emit('ready', [this]);
-    }
-  }
-
-  $el() {
-    return $(`#${this.id}`);
-  }
-
-  showModal() {
-    // @ts-ignore 
-    this.$el().get(0)?.showModal();
-  }
-}
diff --git a/src/client/socket-event.client.ts b/src/client/socket-event.client.ts
deleted file mode 100644 (file)
index e27ae94..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-import {Socket} from "socket.io-client";
-import {CustomEventManager} from "./events";
-
-export type API = {
-  socket: Socket;
-  cache: Map<string, any>,
-  events: CustomEventManager
-};
-
-type SocketEventHandler = (api: API, data: unknown) => void;
-
-export class SocketEvent {
-  constructor(public eventName: string, public handler: SocketEventHandler) {
-
-  }
-}
index bd86f977d9eaae3652e87312803ccc74aae6da0f..b99640132ac5a89d3482a33b14c75edf994a8953 100644 (file)
@@ -6,7 +6,7 @@ import express, {Request, Response} from 'express';
 import bodyParser from 'body-parser';
 
 import http from 'http';
 import bodyParser from 'body-parser';
 
 import http from 'http';
-import { Server, Socket } from 'socket.io';
+import { Server } from 'socket.io';
 import { logger } from './lib/logger';
 import { loadPlayer, createPlayer, updatePlayer, movePlayer } from './player';
 import { random, sample } from 'lodash';
 import { logger } from './lib/logger';
 import { loadPlayer, createPlayer, updatePlayer, movePlayer } from './player';
 import { random, sample } from 'lodash';
@@ -17,11 +17,11 @@ import {FightRound} from '../shared/fight';
 import {addInventoryItem, deleteInventoryItem, getEquippedItems, getInventory, getInventoryItem, updateAp} from './inventory';
 import { getItemFromPlayer, getItemFromShop, getPlayersItems, getShopItems, givePlayerItem, updateItemCount } from './items';
 import {FightTrigger, Monster, MonsterForFight, MonsterWithFaction} from '../shared/monsters';
 import {addInventoryItem, deleteInventoryItem, getEquippedItems, getInventory, getInventoryItem, updateAp} from './inventory';
 import { getItemFromPlayer, getItemFromShop, getPlayersItems, getShopItems, givePlayerItem, updateItemCount } from './items';
 import {FightTrigger, Monster, MonsterForFight, MonsterWithFaction} from '../shared/monsters';
-import {getShopEquipment, getShopItem, listShopItems } from './shopEquipment';
+import {getShopEquipment, listShopItems } from './shopEquipment';
 import {EquippedItemDetails} from '../shared/equipped';
 import {ArmourEquipmentSlot, EquipmentSlot} from '../shared/inventory';
 import { clearTravelPlan, completeTravel, getAllPaths, getAllServices, getCityDetails, getService, getTravelPlan, stepForward, travel } from './map';
 import {EquippedItemDetails} from '../shared/equipped';
 import {ArmourEquipmentSlot, EquipmentSlot} from '../shared/inventory';
 import { clearTravelPlan, completeTravel, getAllPaths, getAllServices, getCityDetails, getService, getTravelPlan, stepForward, travel } from './map';
-import { signup, login, authEndpoint } from './auth';
+import { signup, login, authEndpoint, AuthRequest } from './auth';
 import {db} from './lib/db';
 import { getPlayerSkills, getPlayerSkillsAsObject, updatePlayerSkills } from './skills';
 import {SkillID, Skills} from '../shared/skills';
 import {db} from './lib/db';
 import { getPlayerSkills, getPlayerSkillsAsObject, updatePlayerSkills } from './skills';
 import {SkillID, Skills} from '../shared/skills';
@@ -95,23 +95,12 @@ io.on('connection', async socket => {
 
   socket.emit('authToken', player.id);
 
 
   socket.emit('authToken', player.id);
 
-  socket.emit('chat', broadcastMessage('server', `${player.username} just logged in`));
+  socket.emit('chat', renderChatMessage(broadcastMessage('server', `${player.username} just logged in`)));
 
   socket.on('disconnect', () => {
     console.log(`Player ${player.username} left`);
   });
 
 
   socket.on('disconnect', () => {
     console.log(`Player ${player.username} left`);
   });
 
-  socket.on('logout', async () => {
-    // clear this player from the cache!
-    const player = cache.get(`token:${socket.handshake.headers['x-authtoken']}`);
-    if(player) {
-      logger.log(`Player ${player.username} logged out`);
-    }
-    else {
-      logger.log(`Invalid user logout`);
-    }
-  });
-
   // this is a special event to let the client know it can start 
   // requesting data
   socket.emit('ready');
   // this is a special event to let the client know it can start 
   // requesting data
   socket.emit('ready');
@@ -380,29 +369,13 @@ async function fightRound(player: Player, monster: MonsterWithFaction,  data: {a
 app.use(healerRouter);
 
 
 app.use(healerRouter);
 
 
-app.get('/chat/history', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
+app.get('/chat/history', authEndpoint, async (req: AuthRequest, res: Response) => {
   let html = chatHistory.map(renderChatMessage);
 
   res.send(html.join("\n"));
 });
 
   let html = chatHistory.map(renderChatMessage);
 
   res.send(html.join("\n"));
 });
 
-app.post('/chat', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
+app.post('/chat', authEndpoint, async (req: AuthRequest, res: Response) => {
   const msg = req.body.message.trim();
 
   if(!msg || !msg.length) {
   const msg = req.body.message.trim();
 
   if(!msg || !msg.length) {
@@ -430,80 +403,64 @@ app.post('/chat', authEndpoint, async (req: Request, res: Response) => {
         message = broadcastMessage('server', str);
       }
     }
         message = broadcastMessage('server', str);
       }
     }
-
-
   }
   else {
   }
   else {
-    message = broadcastMessage(player.username, msg);
+    message = broadcastMessage(req.player.username, msg);
     chatHistory.push(message);
     chatHistory.slice(-10);
     chatHistory.push(message);
     chatHistory.slice(-10);
-
-    io.emit('chat', message);
-    res.sendStatus(204);
   }
 
   if(message) {
   }
 
   if(message) {
-    io.emit('chat', message);
+    io.emit('chat', renderChatMessage(message));
+    res.sendStatus(204);
   }
   }
-
 });
 
 });
 
-app.get('/player', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
-  const inventory = await getEquippedItems(player.id);
+app.get('/player', authEndpoint, async (req: AuthRequest, res: Response) => {
+  const inventory = await getEquippedItems(req.player.id);
 
 
-  res.send(renderPlayerBar(player, inventory) + (await renderProfilePage(player)));
+  res.send(renderPlayerBar(req.player, inventory) + renderProfilePage(req.player));
 });
 
 });
 
-app.get('/player/skills', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
+app.post('/player/stat/:stat', authEndpoint, async (req: AuthRequest, res: Response) => {
+  const stat = req.params.stat;
+  if(!['strength', 'constitution', 'dexterity', 'intelligence'].includes(stat)) {
+    res.send(Alert.ErrorAlert(`Sorry, that's not a valid stat to increase`));
+    return;
+  }
 
 
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
+  if(req.player.stat_points <= 0) {
+    res.send(Alert.ErrorAlert(`Sorry, you don't have enough stat points`));
+    return;
   }
 
   }
 
-  const skills = await getPlayerSkills(player.id);
+  req.player.stat_points -= 1;
+  req.player[stat]++;
 
 
-  res.send(renderSkills(skills));
+  updatePlayer(req.player);
+
+  const equippedItems = await getEquippedItems(req.player.id);
+  res.send(renderPlayerBar(req.player, equippedItems) + renderProfilePage(req.player));
 });
 
 });
 
-app.get('/player/inventory', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
+app.get('/player/skills', authEndpoint, async (req: AuthRequest, res: Response) => {
+  const skills = await getPlayerSkills(req.player.id);
 
 
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
+  res.send(renderSkills(skills));
+});
 
 
+app.get('/player/inventory', authEndpoint, async (req: AuthRequest, res: Response) => {
   const [inventory, items] = await Promise.all([
   const [inventory, items] = await Promise.all([
-    getInventory(player.id),
-    getPlayersItems(player.id)
+    getInventory(req.player.id),
+    getPlayersItems(req.player.id)
   ]);
 
   res.send(renderInventoryPage(inventory, items));
 });
 
   ]);
 
   res.send(renderInventoryPage(inventory, items));
 });
 
-app.post('/player/equip/:item_id/:slot', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
-  const inventoryItem = await getInventoryItem(player.id, req.params.item_id);
-  const equippedItems = await getEquippedItems(player.id);
+app.post('/player/equip/:item_id/:slot', authEndpoint, async (req: AuthRequest, res: Response) => {
+  const inventoryItem = await getInventoryItem(req.player.id, req.params.item_id);
+  const equippedItems = await getEquippedItems(req.player.id);
   const requestedSlot = req.params.slot;
   let desiredSlot: EquipmentSlot = inventoryItem.equipment_slot;
 
   const requestedSlot = req.params.slot;
   let desiredSlot: EquipmentSlot = inventoryItem.equipment_slot;
 
@@ -533,9 +490,9 @@ app.post('/player/equip/:item_id/:slot', authEndpoint, async (req: Request, res:
     }
 
 
     }
 
 
-    await equip(player.id, inventoryItem, desiredSlot);
-    const socketId = cache.get(`socket:${player.id}`).toString();
-    io.to(socketId).emit('updatePlayer', player);
+    await equip(req.player.id, inventoryItem, desiredSlot);
+    const socketId = cache.get(`socket:${req.player.id}`).toString();
+    io.to(socketId).emit('updatePlayer', req.player);
     io.to(socketId).emit('alert', {
       type: 'success',
       text: `You equipped your ${inventoryItem.name}`
     io.to(socketId).emit('alert', {
       type: 'success',
       text: `You equipped your ${inventoryItem.name}`
@@ -546,47 +503,30 @@ app.post('/player/equip/:item_id/:slot', authEndpoint, async (req: Request, res:
   }
 
   const [inventory, items] = await Promise.all([
   }
 
   const [inventory, items] = await Promise.all([
-    getInventory(player.id),
-    getPlayersItems(player.id)
+    getInventory(req.player.id),
+    getPlayersItems(req.player.id)
   ]);
 
   ]);
 
-  res.send(renderInventoryPage(inventory, items, inventoryItem.type) + renderPlayerBar(player, inventory));
+  res.send(renderInventoryPage(inventory, items, inventoryItem.type) + renderPlayerBar(req.player, inventory));
 });
 
 });
 
-app.post('/player/unequip/:item_id', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
+app.post('/player/unequip/:item_id', authEndpoint, async (req: AuthRequest, res: Response) => {
   const [item, ] = await Promise.all([
   const [item, ] = await Promise.all([
-    getInventoryItem(player.id, req.params.item_id),
-    unequip(player.id, req.params.item_id)
+    getInventoryItem(req.player.id, req.params.item_id),
+    unequip(req.player.id, req.params.item_id)
   ]);
 
   const [inventory, items] = await Promise.all([
   ]);
 
   const [inventory, items] = await Promise.all([
-    getInventory(player.id),
-    getPlayersItems(player.id)
+    getInventory(req.player.id),
+    getPlayersItems(req.player.id)
   ]);
 
   ]);
 
-  res.send(renderInventoryPage(inventory, items, item.type) + renderPlayerBar(player, inventory));
+  res.send(renderInventoryPage(inventory, items, item.type) + renderPlayerBar(req.player, inventory));
 });
 
 });
 
-app.get('/player/explore', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
-
-  const fight = await loadMonsterFromFight(player.id);
-  let closestTown = player.city_id;
+app.get('/player/explore', authEndpoint, async (req: AuthRequest, res: Response) => {
+  const fight = await loadMonsterFromFight(req.player.id);
+  let closestTown = req.player.city_id;
 
   if(fight) {
     // ok lets display the fight screen!
 
   if(fight) {
     // ok lets display the fight screen!
@@ -602,10 +542,10 @@ app.get('/player/explore', authEndpoint, async (req: Request, res: Response) =>
     res.send(renderFight(data));
   }
   else {
     res.send(renderFight(data));
   }
   else {
-    const travelPlan = await getTravelPlan(player.id);
+    const travelPlan = await getTravelPlan(req.player.id);
     if(travelPlan) {
       // traveling!
     if(travelPlan) {
       // traveling!
-      const travelPlan = await getTravelPlan(player.id);
+      const travelPlan = await getTravelPlan(req.player.id);
 
       const closest: number = (travelPlan.current_position / travelPlan.total_distance) > 0.5 ? travelPlan.destination_id : travelPlan.source_id;
 
 
       const closest: number = (travelPlan.current_position / travelPlan.total_distance) > 0.5 ? travelPlan.destination_id : travelPlan.source_id;
 
@@ -617,7 +557,7 @@ app.get('/player/explore', authEndpoint, async (req: Request, res: Response) =>
       }
 
       // STEP_DELAY
       }
 
       // STEP_DELAY
-      const nextAction = cache[`step:${player.id}`] || 0;
+      const nextAction = cache[`step:${req.player.id}`] || 0;
 
       res.send(renderTravel({
         things,
 
       res.send(renderTravel({
         things,
@@ -629,9 +569,9 @@ app.get('/player/explore', authEndpoint, async (req: Request, res: Response) =>
     else {
       // display the city info!
       const [city, locations, paths] = await Promise.all([
     else {
       // display the city info!
       const [city, locations, paths] = await Promise.all([
-        getCityDetails(player.city_id),
-        getAllServices(player.city_id),
-        getAllPaths(player.city_id)
+        getCityDetails(req.player.city_id),
+        getAllServices(req.player.city_id),
+        getAllPaths(req.player.city_id)
       ]);
 
       res.send(await renderMap({city, locations, paths}, closestTown));
       ]);
 
       res.send(await renderMap({city, locations, paths}, closestTown));
@@ -641,14 +581,7 @@ app.get('/player/explore', authEndpoint, async (req: Request, res: Response) =>
 });
 
 // used to purchase equipment from a particular shop
 });
 
 // used to purchase equipment from a particular shop
-app.put('/location/:location_id/equipment/:item_id', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
+app.put('/location/:location_id/equipment/:item_id', authEndpoint, async (req: AuthRequest, res: Response) => {
   const item = await getShopEquipment(parseInt(req.params.item_id), parseInt(req.params.location_id));
 
   if(!item) {
   const item = await getShopEquipment(parseInt(req.params.item_id), parseInt(req.params.location_id));
 
   if(!item) {
@@ -656,30 +589,23 @@ app.put('/location/:location_id/equipment/:item_id', authEndpoint, async (req: R
     return res.sendStatus(400);
   }
 
     return res.sendStatus(400);
   }
 
-  if(player.gold < item.cost) {
+  if(req.player.gold < item.cost) {
     res.send(Alert.ErrorAlert(`Sorry, you need at least ${item.cost.toLocaleString()}G to purchase this.`));
     return;
   }
 
     res.send(Alert.ErrorAlert(`Sorry, you need at least ${item.cost.toLocaleString()}G to purchase this.`));
     return;
   }
 
-  player.gold -= item.cost;
+  req.player.gold -= item.cost;
 
 
-  await updatePlayer(player);
-  await addInventoryItem(player.id, item);
+  await updatePlayer(req.player);
+  await addInventoryItem(req.player.id, item);
 
 
-  const equippedItems = await getEquippedItems(player.id);
+  const equippedItems = await getEquippedItems(req.player.id);
 
 
-  res.send(renderPlayerBar(player, equippedItems) + Alert.SuccessAlert(`You purchased ${item.name}`));
+  res.send(renderPlayerBar(req.player, equippedItems) + Alert.SuccessAlert(`You purchased ${item.name}`));
 });
 
 // used to purchase items from a particular shop
 });
 
 // used to purchase items from a particular shop
-app.put('/location/:location_id/items/:item_id', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
+app.put('/location/:location_id/items/:item_id', authEndpoint, async (req: AuthRequest, res: Response) => {
   const item: (ShopItem & Item) = await getItemFromShop(parseInt(req.params.item_id), parseInt(req.params.location_id));
 
   if(!item) {
   const item: (ShopItem & Item) = await getItemFromShop(parseInt(req.params.item_id), parseInt(req.params.location_id));
 
   if(!item) {
@@ -687,32 +613,25 @@ app.put('/location/:location_id/items/:item_id', authEndpoint, async (req: Reque
     return res.sendStatus(400);
   }
 
     return res.sendStatus(400);
   }
 
-  if(player.gold < item.price_per_unit) {
+  if(req.player.gold < item.price_per_unit) {
     res.send(Alert.ErrorAlert(`Sorry, you need at least ${item.price_per_unit.toLocaleString()}G to purchase this.`));
     return;
   }
 
     res.send(Alert.ErrorAlert(`Sorry, you need at least ${item.price_per_unit.toLocaleString()}G to purchase this.`));
     return;
   }
 
-  player.gold -= item.price_per_unit;
+  req.player.gold -= item.price_per_unit;
 
 
-  await updatePlayer(player);
-  await givePlayerItem(player.id, item.id, 1);
+  await updatePlayer(req.player);
+  await givePlayerItem(req.player.id, item.id, 1);
 
 
-  const equippedItems = await getEquippedItems(player.id);
+  const equippedItems = await getEquippedItems(req.player.id);
 
 
-  res.send(renderPlayerBar(player, equippedItems) + Alert.SuccessAlert(`You purchased a ${item.name}`));
+  res.send(renderPlayerBar(req.player, equippedItems) + Alert.SuccessAlert(`You purchased a ${item.name}`));
 });
 
 // used to display equipment modals in a store, validates that 
 // the equipment is actually in this store before displaying 
 // the modal
 });
 
 // used to display equipment modals in a store, validates that 
 // the equipment is actually in this store before displaying 
 // the modal
-app.get('/location/:location_id/equipment/:item_id/overview', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
+app.get('/location/:location_id/equipment/:item_id/overview', authEndpoint, async (req: AuthRequest, res: Response) => {
   const equipment = await getShopEquipment(parseInt(req.params.item_id), parseInt(req.params.location_id));
 
   if(!equipment) {
   const equipment = await getShopEquipment(parseInt(req.params.item_id), parseInt(req.params.location_id));
 
   if(!equipment) {
@@ -724,10 +643,10 @@ app.get('/location/:location_id/equipment/:item_id/overview', authEndpoint, asyn
 <dialog>
   <div class="item-modal-overview">
     <div class="icon">
 <dialog>
   <div class="item-modal-overview">
     <div class="icon">
-      <img src="https://via.placeholder.com/64x64" title="${equipment.name}" alt="${equipment.name}"> 
+      <img src="${equipment.icon ? `/assets/img/icons/equipment/${equipment.icon}` : 'https://via.placeholder.com/64x64'}" title="${equipment.name}" alt="${equipment.name}"> 
     </div>
     <div>
     </div>
     <div>
-      ${renderEquipmentDetails(equipment, player)}
+      ${renderEquipmentDetails(equipment, req.player)}
     </div>
   </div>
   <div class="actions">
     </div>
   </div>
   <div class="actions">
@@ -743,14 +662,7 @@ app.get('/location/:location_id/equipment/:item_id/overview', authEndpoint, asyn
 // used to display item modals in a store, validates that 
 // the item is actually in this store before displaying 
 // the modal
 // used to display item modals in a store, validates that 
 // the item is actually in this store before displaying 
 // the modal
-app.get('/location/:location_id/items/:item_id/overview', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
+app.get('/location/:location_id/items/:item_id/overview', authEndpoint, async (req: AuthRequest, res: Response) => {
   const item: (ShopItem & Item) = await getItemFromShop(parseInt(req.params.item_id), parseInt(req.params.location_id));
 
   if(!item) {
   const item: (ShopItem & Item) = await getItemFromShop(parseInt(req.params.item_id), parseInt(req.params.location_id));
 
   if(!item) {
@@ -779,15 +691,8 @@ app.get('/location/:location_id/items/:item_id/overview', authEndpoint, async (r
   res.send(html);
 });
 
   res.send(html);
 });
 
-app.put('/item/:item_id', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
-  const item: PlayerItem = await getItemFromPlayer(player.id, parseInt(req.params.item_id));
+app.put('/item/:item_id', authEndpoint, async (req: AuthRequest, res: Response) => {
+  const item: PlayerItem = await getItemFromPlayer(req.player.id, parseInt(req.params.item_id));
 
   if(!item) {
     console.log(`Can't find item [${req.params.item_id}]`);
 
   if(!item) {
     console.log(`Can't find item [${req.params.item_id}]`);
@@ -803,26 +708,26 @@ app.put('/item/:item_id', authEndpoint, async (req: Request, res: Response) => {
 
   switch(item.effect_name) {
     case 'heal_small':
 
   switch(item.effect_name) {
     case 'heal_small':
-      const hpGain = HealthPotionSmall.effect(player);
+      const hpGain = HealthPotionSmall.effect(req.player);
 
 
-      player.hp += hpGain;
+      req.player.hp += hpGain;
 
 
-      if(player.hp > maxHp(player.constitution, player.level)) {
-        player.hp = maxHp(player.constitution, player.level);
+      if(req.player.hp > maxHp(req.player.constitution, req.player.level)) {
+        req.player.hp = maxHp(req.player.constitution, req.player.level);
       }
     break;
   }
 
       }
     break;
   }
 
-  await updateItemCount(player.id, item.item_id, -1);
-  await updatePlayer(player);
+  await updateItemCount(req.player.id, item.item_id, -1);
+  await updatePlayer(req.player);
 
 
-  const inventory = await getInventory(player.id);
+  const inventory = await getInventory(req.player.id);
   const equippedItems = inventory.filter(i => i.is_equipped);
   const equippedItems = inventory.filter(i => i.is_equipped);
-  const items = await getPlayersItems(player.id);
+  const items = await getPlayersItems(req.player.id);
 
   res.send(
     [
 
   res.send(
     [
-      renderPlayerBar(player, equippedItems),
+      renderPlayerBar(req.player, equippedItems),
       renderInventoryPage(inventory, items, 'ITEMS'),
       Alert.SuccessAlert(`You used the ${item.name}`)
     ].join("")
       renderInventoryPage(inventory, items, 'ITEMS'),
       Alert.SuccessAlert(`You used the ${item.name}`)
     ].join("")
@@ -830,15 +735,8 @@ app.put('/item/:item_id', authEndpoint, async (req: Request, res: Response) => {
 
 });
 
 
 });
 
-app.get('/modal/items/:item_id', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
-  const item: PlayerItem = await getItemFromPlayer(player.id, parseInt(req.params.item_id));
+app.get('/modal/items/:item_id', authEndpoint, async (req: AuthRequest, res: Response) => {
+  const item: PlayerItem = await getItemFromPlayer(req.player.id, parseInt(req.params.item_id));
 
   if(!item) {
     logger.log(`Invalid item [${req.params.item_id}]`);
 
   if(!item) {
     logger.log(`Invalid item [${req.params.item_id}]`);
@@ -866,17 +764,10 @@ app.get('/modal/items/:item_id', authEndpoint, async (req: Request, res: Respons
   res.send(html);
 });
 
   res.send(html);
 });
 
-app.get('/city/stores/city:stores/:location_id', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
+app.get('/city/stores/city:stores/:location_id', authEndpoint, async (req: AuthRequest, res: Response) => {
   const location = await getService(parseInt(req.params.location_id));
 
   const location = await getService(parseInt(req.params.location_id));
 
-  if(!location || location.city_id !== player.city_id) {
+  if(!location || location.city_id !== req.player.city_id) {
     logger.log(`Invalid location: [${req.params.location_id}]`);
     res.sendStatus(400);
   }
     logger.log(`Invalid location: [${req.params.location_id}]`);
     res.sendStatus(400);
   }
@@ -885,21 +776,14 @@ app.get('/city/stores/city:stores/:location_id', authEndpoint, async (req: Reque
     getShopItems(location.id)
   ]);
 
     getShopItems(location.id)
   ]);
 
-  const html = await renderStore(shopEquipment, shopItems, player);
+  const html = await renderStore(shopEquipment, shopItems, req.player);
 
   res.send(html);
 });
 
 
   res.send(html);
 });
 
-app.get('/city/explore/city:explore/:location_id', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
+app.get('/city/explore/city:explore/:location_id', authEndpoint, async (req: AuthRequest, res: Response) => {
   const location = await getService(parseInt(req.params.location_id));
   const location = await getService(parseInt(req.params.location_id));
-  if(!location || location.city_id !== player.city_id) {
+  if(!location || location.city_id !== req.player.city_id) {
 
     logger.log(`Invalid location: [${req.params.location_id}]`);
     res.sendStatus(400);
 
     logger.log(`Invalid location: [${req.params.location_id}]`);
     res.sendStatus(400);
@@ -909,43 +793,28 @@ app.get('/city/explore/city:explore/:location_id', authEndpoint, async (req: Req
   res.send(renderMonsterSelector(monsters));
 });
 
   res.send(renderMonsterSelector(monsters));
 });
 
-app.post('/travel', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
+app.post('/travel', authEndpoint, async (req: AuthRequest, res: Response) => {
   const destination_id = parseInt(req.body.destination_id);
 
   const destination_id = parseInt(req.body.destination_id);
 
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
   if(!destination_id || isNaN(destination_id)) {
     logger.log(`Invalid destination_id [${req.body.destination_id}]`);
     return res.sendStatus(400);
   }
 
   if(!destination_id || isNaN(destination_id)) {
     logger.log(`Invalid destination_id [${req.body.destination_id}]`);
     return res.sendStatus(400);
   }
 
-  const travelPlan = travel(player, req.body.destination_id);
+  const travelPlan = travel(req.player, req.body.destination_id);
 
   res.json(travelPlan);
 });
 
 
   res.json(travelPlan);
 });
 
-app.post('/fight/turn', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
-  const monster = await loadMonsterWithFaction(player.id);
+app.post('/fight/turn', authEndpoint, async (req: AuthRequest, res: Response) => {
+  const monster = await loadMonsterWithFaction(req.player.id);
 
   if(!monster) {
     res.send(Alert.ErrorAlert('Not in a fight'));
     return;
   }
 
 
   if(!monster) {
     res.send(Alert.ErrorAlert('Not in a fight'));
     return;
   }
 
-  const fightData  = await fightRound(player, monster, {
+  const fightData  = await fightRound(req.player, monster, {
     action: req.body.action,
     target: req.body.fightTarget
   });
     action: req.body.action,
     target: req.body.fightTarget
   });
@@ -963,27 +832,19 @@ app.post('/fight/turn', authEndpoint, async (req: Request, res: Response) => {
   let travelSection = '';
   if(monster.fight_trigger === 'travel' && fightData.roundData.winner === 'player') {
     // you're travellinga dn you won.. display the keep walking!
   let travelSection = '';
   if(monster.fight_trigger === 'travel' && fightData.roundData.winner === 'player') {
     // you're travellinga dn you won.. display the keep walking!
-    const travelPlan = await getTravelPlan(player.id);
+    const travelPlan = await getTravelPlan(req.player.id);
     const closest: number = (travelPlan.current_position / travelPlan.total_distance) > 0.5 ? travelPlan.destination_id : travelPlan.source_id;
     travelSection = travelButton(0);
   }
 
     const closest: number = (travelPlan.current_position / travelPlan.total_distance) > 0.5 ? travelPlan.destination_id : travelPlan.source_id;
     travelSection = travelButton(0);
   }
 
-  const equippedItems = await getEquippedItems(player.id);
+  const equippedItems = await getEquippedItems(req.player.id);
   const playerBar = renderPlayerBar(fightData.player, equippedItems);
 
   res.send(html + travelSection + playerBar);
 });
 
   const playerBar = renderPlayerBar(fightData.player, equippedItems);
 
   res.send(html + travelSection + playerBar);
 });
 
-app.post('/fight', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
-  if(player.hp <= 0) {
+app.post('/fight', authEndpoint, async (req: AuthRequest, res: Response) => {
+  if(req.player.hp <= 0) {
     logger.log(`Player didn\'t have enough hp`);
     return res.sendStatus(400);
   }
     logger.log(`Player didn\'t have enough hp`);
     return res.sendStatus(400);
   }
@@ -1008,7 +869,7 @@ app.post('/fight', authEndpoint, async (req: Request, res: Response) => {
     return res.sendStatus(400);
   }
 
     return res.sendStatus(400);
   }
 
-  const fight = await createFight(player.id, monster, fightTrigger);
+  const fight = await createFight(req.player.id, monster, fightTrigger);
 
 
   const data: MonsterForFight = {
 
 
   const data: MonsterForFight = {
@@ -1023,17 +884,10 @@ app.post('/fight', authEndpoint, async (req: Request, res: Response) => {
   res.send(renderFight(data));
 });
 
   res.send(renderFight(data));
 });
 
-app.post('/travel/step', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-  const stepTimerKey = `step:${player.id}`;
-
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
+app.post('/travel/step', authEndpoint, async (req: AuthRequest, res: Response) => {
+  const stepTimerKey = `step:${req.player.id}`;
 
 
-  const travelPlan = await getTravelPlan(player.id);
+  const travelPlan = await getTravelPlan(req.player.id);
   if(!travelPlan) {
     res.send(Alert.ErrorAlert('You don\'t have a travel plan'));
     return;
   if(!travelPlan) {
     res.send(Alert.ErrorAlert('You don\'t have a travel plan'));
     return;
@@ -1049,10 +903,10 @@ app.post('/travel/step', authEndpoint, async (req: Request, res: Response) => {
   travelPlan.current_position++;
 
   if(travelPlan.current_position >= travelPlan.total_distance) {
   travelPlan.current_position++;
 
   if(travelPlan.current_position >= travelPlan.total_distance) {
-    const travel = await completeTravel(player.id);
+    const travel = await completeTravel(req.player.id);
 
 
-    player.city_id = travel.destination_id;
-    await movePlayer(travel.destination_id, player.id);
+    req.player.city_id = travel.destination_id;
+    await movePlayer(travel.destination_id, req.player.id);
 
     const [city, locations, paths] = await Promise.all([
       getCityDetails(travel.destination_id),
 
     const [city, locations, paths] = await Promise.all([
       getCityDetails(travel.destination_id),
@@ -1061,7 +915,7 @@ app.post('/travel/step', authEndpoint, async (req: Request, res: Response) => {
     ]);
 
     delete cache[stepTimerKey];
     ]);
 
     delete cache[stepTimerKey];
-    res.send(await renderMap({city, locations, paths}, player.city_id));
+    res.send(await renderMap({city, locations, paths}, req.player.city_id));
   }
   else {
     const walkingText: string[] = [
   }
   else {
     const walkingText: string[] = [
@@ -1070,7 +924,7 @@ app.post('/travel/step', authEndpoint, async (req: Request, res: Response) => {
     ];
     // update existing plan..
     // decide if they will run into anything
     ];
     // update existing plan..
     // decide if they will run into anything
-    const travelPlan = await stepForward(player.id);
+    const travelPlan = await stepForward(req.player.id);
 
     const closest: number = (travelPlan.current_position / travelPlan.total_distance) > 0.5 ? travelPlan.destination_id : travelPlan.source_id;
 
 
     const closest: number = (travelPlan.current_position / travelPlan.total_distance) > 0.5 ? travelPlan.destination_id : travelPlan.source_id;
 
@@ -1096,16 +950,8 @@ app.post('/travel/step', authEndpoint, async (req: Request, res: Response) => {
   }
 });
 
   }
 });
 
-app.post('/travel/:destination_id', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken'].toString();
-  const player: Player = await loadPlayer(authToken)
-
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
-  if(player.hp <= 0) {
+app.post('/travel/:destination_id', authEndpoint, async (req: AuthRequest, res: Response) => {
+  if(req.player.hp <= 0) {
     logger.log(`Player didn\'t have enough hp`);
     res.send(Alert.ErrorAlert('Sorry, you need some HP to start travelling.'));
     return;
     logger.log(`Player didn\'t have enough hp`);
     res.send(Alert.ErrorAlert('Sorry, you need some HP to start travelling.'));
     return;
@@ -1118,16 +964,38 @@ app.post('/travel/:destination_id', authEndpoint, async (req: Request, res: Resp
     return;
   }
 
     return;
   }
 
-  await travel(player, destination.id);
+  await travel(req.player, destination.id);
 
   res.send(renderTravel({
     things: [],
     nextAction: 0,
     walkingText: '',
 
   res.send(renderTravel({
     things: [],
     nextAction: 0,
     walkingText: '',
-    closestTown: player.city_id
+    closestTown: req.player.city_id
   }));
 });
 
   }));
 });
 
+app.get('/settings', authEndpoint, async (req: AuthRequest, res: Response) => {
+  let warning = '';
+  let html = '';
+  if(req.player.account_type === 'session') {
+    warning += `<div class="alert error">If you log out without signing up first, this account is lost forever.</div>`;
+  }
+
+  html += '<a href="#" hx-post="/logout">Logout</a>';
+  res.send(warning + html);
+});
+
+app.post('/logout', authEndpoint, async (req: AuthRequest, res: Response) => {
+  // ref to get the socket id for a particular player
+  cache.delete(`socket:${req.player.id}`);
+  // ref to get the player object
+  cache.delete(`token:${req.player.id}`);
+
+  logger.log(`${req.player.username} logged out`);
+
+  res.send('logout');
+});
+
 
 app.post('/signup', async (req: Request, res: Response) => {
   const {username, password} = req.body;
 
 app.post('/signup', async (req: Request, res: Response) => {
   const {username, password} = req.body;
index d82d4b64c39f06a9460a338fa1f8e3361bf61234..3f4899bad9decb1521c5ee4b31168b00927ad17e 100644 (file)
@@ -5,6 +5,10 @@ import { Auth } from '../shared/auth';
 import { db } from './lib/db';
 import { Request, Response } from 'express';
 
 import { db } from './lib/db';
 import { Request, Response } from 'express';
 
+export interface AuthRequest extends Request {
+  player: Player
+}
+
 export async function signup(playerId: string, username: string, password: string): Promise<void> {
   const salt = await bcrypt.genSalt(10);
   const hash = await bcrypt.hash(password, salt);
 export async function signup(playerId: string, username: string, password: string): Promise<void> {
   const salt = await bcrypt.genSalt(10);
   const hash = await bcrypt.hash(password, salt);
@@ -58,13 +62,21 @@ export async function login(username: string, password: string): Promise<Player>
 
 }
 
 
 }
 
-export function authEndpoint(req: Request, res: Response, next: any) {
+export async function authEndpoint(req: AuthRequest, res: Response, next: any) {
   const authToken = req.headers['x-authtoken'];
   if(!authToken) {
     console.log(`Invalid auth token ${authToken}`);
   const authToken = req.headers['x-authtoken'];
   if(!authToken) {
     console.log(`Invalid auth token ${authToken}`);
-    res.sendStatus(400)
+    res.sendStatus(401)
   }
   else {
   }
   else {
-    next()
+    const player: Player = await loadPlayer(authToken.toString());
+    if(player) {
+      req.player = player;
+      next()
+    }
+    else {
+      console.log(`Invalid auth token ${authToken}`);
+      res.sendStatus(401);
+    }
   }
 }
   }
 }
index c5c2b6717e4cbec2471512b6ca3262979559e891..88bfc87da5a19d1b4da990f2f9c6a06abe33a1b0 100644 (file)
@@ -14,6 +14,7 @@ export async function addInventoryItem(playerId: string, item: ShopEquipment) {
     cost: item.cost,
     count: item.count,
     profession:  item.profession,
     cost: item.cost,
     count: item.count,
     profession:  item.profession,
+    icon: item.icon,
     requirements: {
       level: item.requirements.level,
       strength: item.requirements.strength,
     requirements: {
       level: item.requirements.level,
       strength: item.requirements.strength,
index bd3ba1c9a322e5cbadff9b1a613f66c40b45fea7..46877b24e621f8ff003887225b8a63844814dc0b 100644 (file)
@@ -1,6 +1,6 @@
 import { Request, Response, Router } from "express";
 import { maxHp, Player } from "../../../shared/player";
 import { Request, Response, Router } from "express";
 import { maxHp, Player } from "../../../shared/player";
-import { authEndpoint } from '../../auth';
+import { authEndpoint, AuthRequest } from '../../auth';
 import { logger } from "../../lib/logger";
 import { loadPlayer, updatePlayer } from "../../player";
 import { getCityDetails, getService } from '../../map';
 import { logger } from "../../lib/logger";
 import { loadPlayer, updatePlayer } from "../../player";
 import { getCityDetails, getService } from '../../map';
@@ -91,18 +91,11 @@ function getText(type: TextSegment, location: Location, city: City): string {
 
 }
 
 
 }
 
-router.get('/city/services/city:services:healer/:location_id', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken']!.toString();
-  const player: Player = await loadPlayer(authToken)
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
+router.get('/city/services/city:services:healer/:location_id', authEndpoint, async (req: AuthRequest, res: Response) => {
   const service = await getService(parseInt(req.params.location_id));
   const city = await getCityDetails(service.city_id);
 
   const service = await getService(parseInt(req.params.location_id));
   const city = await getCityDetails(service.city_id);
 
-  if(!service || service.city_id !== player.city_id) {
+  if(!service || service.city_id !== req.player.city_id) {
     logger.log(`Invalid location: [${req.params.location_id}]`);
     res.sendStatus(400);
   }
     logger.log(`Invalid location: [${req.params.location_id}]`);
     res.sendStatus(400);
   }
@@ -113,11 +106,11 @@ router.get('/city/services/city:services:healer/:location_id', authEndpoint, asy
   text.push(`<p>"${getText('intro', service, city)}"</p>`);
 
 
   text.push(`<p>"${getText('intro', service, city)}"</p>`);
 
 
-  if(player.hp === maxHp(player.constitution, player.level)) {
+  if(req.player.hp === maxHp(req.player.constitution, req.player.level)) {
     text.push(`<p>You're already at full health?</p>`);
   }
   else {
     text.push(`<p>You're already at full health?</p>`);
   }
   else {
-    if(player.gold <= (healCost * 2)) {
+    if(req.player.gold <= (healCost * 2)) {
       text.push(`<p>You don't seem to have too much money... I guess I can do it for free this time...</p>`);
       text.push(`<p><button type="button" hx-post="/city/services/city:services:healer:heal/${service.id}" hx-target="#explore">Heal for Free!</button></p>`);
     }
       text.push(`<p>You don't seem to have too much money... I guess I can do it for free this time...</p>`);
       text.push(`<p><button type="button" hx-post="/city/services/city:services:healer:heal/${service.id}" hx-target="#explore">Heal for Free!</button></p>`);
     }
@@ -132,18 +125,11 @@ router.get('/city/services/city:services:healer/:location_id', authEndpoint, asy
 
 
 
 
 
 
-router.post('/city/services/city:services:healer:heal/:location_id', authEndpoint, async (req: Request, res: Response) => {
-  const authToken = req.headers['x-authtoken']!.toString();
-  const player: Player = await loadPlayer(authToken)
-  if(!player) {
-    logger.log(`Couldnt find player with id ${authToken}`);
-    return res.sendStatus(400);
-  }
-
+router.post('/city/services/city:services:healer:heal/:location_id', authEndpoint, async (req: AuthRequest, res: Response) => {
   const service = await getService(parseInt(req.params.location_id));
   const city = await getCityDetails(service.city_id);
 
   const service = await getService(parseInt(req.params.location_id));
   const city = await getCityDetails(service.city_id);
 
-  if(!service || service.city_id !== player.city_id) {
+  if(!service || service.city_id !== req.player.city_id) {
     logger.log(`Invalid location: [${req.params.location_id}]`);
     res.sendStatus(400);
   }
     logger.log(`Invalid location: [${req.params.location_id}]`);
     res.sendStatus(400);
   }
@@ -151,21 +137,21 @@ router.post('/city/services/city:services:healer:heal/:location_id', authEndpoin
   const text: string[] = [];
   text.push(`<p><b>${service.name}</b></p>`);
 
   const text: string[] = [];
   text.push(`<p><b>${service.name}</b></p>`);
 
-  const cost = player.gold <= (healCost * 2) ? 0 : healCost;
+  const cost = req.player.gold <= (healCost * 2) ? 0 : healCost;
 
 
-  if(player.gold < cost) {
+  if(req.player.gold < cost) {
     text.push(`<p>${getText('insufficient_money', service, city)}</p>`)
     res.send(`<div>${text.join("\n")}</div>`);
   }
   else {
     text.push(`<p>${getText('insufficient_money', service, city)}</p>`)
     res.send(`<div>${text.join("\n")}</div>`);
   }
   else {
-    player.hp = maxHp(player.constitution, player.level);
-    player.gold -= cost;
+    req.player.hp = maxHp(req.player.constitution, req.player.level);
+    req.player.gold -= cost;
 
 
-    await updatePlayer(player);
-    const inventory = await getEquippedItems(player.id);
+    await updatePlayer(req.player);
+    const inventory = await getEquippedItems(req.player.id);
 
     text.push(`<p>${getText('heal_successful', service, city)}</p>`);
     text.push('<p><button hx-get="/player/explore" hx-target="#explore">Back to Town</button></p>');
 
     text.push(`<p>${getText('heal_successful', service, city)}</p>`);
     text.push('<p><button hx-get="/player/explore" hx-target="#explore">Back to Town</button></p>');
-    res.send(`<div>${text.join("\n")}</div>` + renderPlayerBar(player, inventory));
+    res.send(`<div>${text.join("\n")}</div>` + renderPlayerBar(req.player, inventory));
   }
 });
   }
 });
index fdd51b4c07b376230e7c7b8640c15cf8ecdf7117..b6ed6dcf276ca62095cf94a22da6a9e3927645ad 100644 (file)
@@ -23,8 +23,7 @@ export function renderRoundDetails(roundData: FightRound): string {
       html.push('<p><button hx-get="/player/explore" hx-target="#explore">Back to Town</button></p>');
     break;
     case 'in-progress':
       html.push('<p><button hx-get="/player/explore" hx-target="#explore">Back to Town</button></p>');
     break;
     case 'in-progress':
-      // still in progress? 
-      console.log('in progress still');
+      // fight still in progress, so we don't send any final actions back
     break;
   }
 
     break;
   }
 
index 08fce8e07027836a8d543d47efbe598b76b7df6a..3ad3e025eb8ae4ccd2a89ccf7525ba797548cc30 100644 (file)
@@ -3,6 +3,12 @@ import { EquippedItemDetails } from "../../shared/equipped";
 import { PlayerItem } from "../../shared/items";
 import { capitalize } from "lodash";
 
 import { PlayerItem } from "../../shared/items";
 import { capitalize } from "lodash";
 
+function icon(icon_name?: string): string {
+  const icon = icon_name ? `/assets/img/icons/equipment/${icon_name}` : 'https://via.placeholder.com/64x64';
+
+  return icon;
+}
+
 function renderEquipmentPlacementGrid(items: EquippedItemDetails[]) {
   const placeholder = 'https://via.placeholder.com/64x64';
   // @ts-ignore
 function renderEquipmentPlacementGrid(items: EquippedItemDetails[]) {
   const placeholder = 'https://via.placeholder.com/64x64';
   // @ts-ignore
@@ -16,29 +22,29 @@ function renderEquipmentPlacementGrid(items: EquippedItemDetails[]) {
 <tr>
 <td>
 </td>
 <tr>
 <td>
 </td>
-<td style="background-image: url('${placeholder}');" title="${map.HEAD ? map.HEAD.name : 'Empty'}">
-${map.HEAD ? map.HEAD.name : 'HEAD'}
+<td style="background-image: url('${icon(map.HEAD?.icon)}');" title="${map.HEAD ? map.HEAD.name : 'Empty'}">
+${map.HEAD ? (map.HEAD.icon ? '' : map.HEAD.name) : 'HEAD'}
 </td>
 </td>
-<td style="background-image: url('${placeholder}');" title="${map.ARMS ? map.ARMS.name : 'Empty'}">
-${map.ARMS ? map.ARMS.name : 'ARMS'}
+<td style="background-image: url('${icon(map.ARMS?.icon)}');" title="${map.ARMS ? map.ARMS.name : 'Empty'}">
+${map.ARMS ? (map.ARMS.icon ? '' : map.ARMS.name) : 'ARMS'}
 </td>
 </tr>
 <tr>
 </td>
 </tr>
 <tr>
-<td style="background-image: url('${placeholder}');" title="${map.LEFT_HAND ? map.LEFT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : '')}">
-${map.LEFT_HAND ? map.LEFT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : 'L_HAND')}
+<td style="background-image: url('${icon(map.LEFT_HAND ? map.LEFT_HAND.icon : map.TWO_HANDED?.icon)}');" title="${map.LEFT_HAND ? map.LEFT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : '')}">
+${map.LEFT_HAND ? (map.LEFT_HAND.icon ? '' : map.LEFT_HAND.name) : (map.TWO_HANDED ? (map.TWO_HANDED.icon ? '' : map.TWO_HANDED.name) : 'L_HAND')}
 </td>
 </td>
-<td style="background-image: url('${placeholder}');" title="${map.CHEST ? map.CHEST.name : ''}">
-${map.CHEST ? map.CHEST.name : 'CHEST'}
+<td style="background-image: url('${icon(map.CHEST?.icon)}');" title="${map.CHEST ? map.CHEST.name : ''}">
+${map.CHEST ? (map.CHEST.icon ? '' : map.CHEST.name) : 'CHEST'}
 </td>
 </td>
-<td style="background-image: url('${placeholder}');" title="${map.RIGHT_HAND ? map.RIGHT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : '')}">
-${map.RIGHT_HAND ? map.RIGHT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : 'R_HAND')}
+<td style="background-image: url('${icon(map.RIGHT_HAND ? map.RIGHT_HAND.icon : map.TWO_HANDED?.icon)}');" title="${map.RIGHT_HAND ? map.RIGHT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : '')}">
+${map.RIGHT_HAND ? (map.RIGHT_HAND.icon ? '' : map.RIGHT_HAND.name) : (map.TWO_HANDED ? (map.TWO_HANDED.icon ? '' : map.TWO_HANDED.name) : 'R_HAND')}
 </td>
 </tr>
 <tr>
 <td>
 </td>
 </td>
 </tr>
 <tr>
 <td>
 </td>
-<td style="background-image: url('${placeholder}');" title="${map.LEGS ? map.LEGS.name : ''}">
-${map.LEGS ? map.LEGS.name : 'LEGS'}
+<td style="background-image: url('${icon(map.LEGS?.icon)}');" title="${map.LEGS ? map.LEGS.name : ''}">
+${map.LEGS ? (map.LEGS.icon ? '' : map.LEGS.name) : 'LEGS'}
 </td>
 <td>
 </td>
 </td>
 <td>
 </td>
@@ -88,7 +94,7 @@ function generateProgressBar(current: number, max: number, color: string, displa
 function renderInventoryItem(item: EquippedItemDetails , action: (item: EquippedItemDetails) => string): string {
   return `<div class="store-list">
     <div>
 function renderInventoryItem(item: EquippedItemDetails , action: (item: EquippedItemDetails) => string): string {
   return `<div class="store-list">
     <div>
-      <img src="https://via.placeholder.com/64x64">
+      <img src="${item.icon ? `/assets/img/icons/equipment/${item.icon}` : 'https://via.placeholder.com/64x64'}">
     </div>
     <div class="details">
       <div class="name">${item.name}</div>
     </div>
     <div class="details">
       <div class="name">${item.name}</div>
index 0d8468b0bd3e5c6864fa9c0b2163fea7632e7769..93a9bf739801b94abed608803d12184ba9290730 100644 (file)
@@ -1,9 +1,9 @@
 import { Player, StatDef, StatDisplay } from "../../shared/player";
 
 function statPointIncreaser(stat: StatDisplay) {
 import { Player, StatDef, StatDisplay } from "../../shared/player";
 
 function statPointIncreaser(stat: StatDisplay) {
-  return `<button class="increase-stat emit-event" data-event="spend-stat-point" data-args="${stat.id}">+</button>`;
+  return `<button class="increase-stat" hx-post="/player/stat/${stat.id}" hx-target="#profile">+</button>`;
 }
 }
-export async function renderProfilePage(player: Player): Promise<string> {
+export function renderProfilePage(player: Player): string {
   let statBreakdown = '';
 
   StatDef.forEach(stat => {
   let statBreakdown = '';
 
   StatDef.forEach(stat => {
index 6c237d1bd38bdcc9a1d45ca8597810449a5fa909..6a24e89b1138c2602b7e12690dd852d8f5fe3b7c 100644 (file)
@@ -67,7 +67,7 @@ export function renderEquipmentDetails(item: ShopEquipment, player: Player): str
 function renderShopEquipment(item: ShopEquipment, action: (item: ShopEquipment) => string, player: Player): string {
     return `<div class="store-list">
     <div>
 function renderShopEquipment(item: ShopEquipment, action: (item: ShopEquipment) => string, player: Player): string {
     return `<div class="store-list">
     <div>
-      <img src="https://via.placeholder.com/64x64">
+      <img src="${item.icon ? `/assets/img/icons/equipment/${item.icon}` : 'https://via.placeholder.com/64x64'}">
     </div>
     ${renderEquipmentDetails(item, player)}
     <div class="store-actions">
     </div>
     ${renderEquipmentDetails(item, player)}
     <div class="store-actions">
index 6c18807635b2bc26100d18b548d5358caa7bf2f9..cb4220061ae4cbcac68988c025271476a842e113 100644 (file)
@@ -18,6 +18,7 @@ export type InventoryItem = {
   equipment_slot: EquipmentSlot;
   cost: number;
   count: number;
   equipment_slot: EquipmentSlot;
   cost: number;
   count: number;
+  icon: string;
   requirements: {
     level: number,
     strength: number,
   requirements: {
     level: number,
     strength: number,