chore(release): 0.2.5 v0.2.5
authorxangelo <me@xangelo.ca>
Sat, 5 Aug 2023 12:59:04 +0000 (08:59 -0400)
committerxangelo <me@xangelo.ca>
Sat, 5 Aug 2023 12:59:04 +0000 (08:59 -0400)
50 files changed:
CHANGELOG.md
migrations/20230729184427_items.ts [new file with mode: 0644]
migrations/20230802173517_shop_equipment.ts [new file with mode: 0644]
migrations/20230802174902_items-in-shop.ts [new file with mode: 0644]
package-lock.json
package.json
public/assets/bundle.js
public/assets/css/game.css
public/assets/img/icons/items/Minor_Potion_health.png [new file with mode: 0755]
public/index.html
seeds/shop_items.ts
src/client/chat.ts
src/client/htmx.ts [new file with mode: 0644]
src/client/http.ts
src/client/index.ts
src/client/modal.ts [new file with mode: 0644]
src/events/client.ts
src/events/equipping-items/server.ts
src/events/healer/client.ts [deleted file]
src/events/healer/server.ts [deleted file]
src/events/items/server.ts [new file with mode: 0644]
src/events/server.ts
src/events/stores/server.ts
src/server/api.ts
src/server/auth.ts
src/server/inventory.ts
src/server/items.ts [new file with mode: 0644]
src/server/locations/healer/index.ts [new file with mode: 0644]
src/server/map.ts
src/server/monster.ts
src/server/shopEquipment.ts [new file with mode: 0644]
src/server/shopItem.ts [deleted file]
src/server/views/alert.ts [new file with mode: 0644]
src/server/views/chat.ts [new file with mode: 0644]
src/server/views/fight.ts [new file with mode: 0644]
src/server/views/inventory.ts [new file with mode: 0644]
src/server/views/map.ts [new file with mode: 0644]
src/server/views/monster-selector.ts [new file with mode: 0644]
src/server/views/player-bar.ts [new file with mode: 0644]
src/server/views/profile.ts [new file with mode: 0644]
src/server/views/skills.ts [new file with mode: 0644]
src/server/views/stores.ts [new file with mode: 0644]
src/server/views/travel.ts [new file with mode: 0644]
src/shared/inventory.ts
src/shared/items/base.ts [new file with mode: 0644]
src/shared/items/health_potion.ts [new file with mode: 0644]
src/shared/items/index.ts [new file with mode: 0644]
src/shared/map.ts
src/shared/time.ts
webpack.config.js

index 062f5641ba4b9e6eff4a90f18780ba1a1f7ba23d..2be61f50b3fb18631a435f3ad63e93936733e540 100644 (file)
@@ -2,6 +2,30 @@
 
 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.5](https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff;h=v0.2.5;hp=v0.2.4;ds=sidebyside) (2023-08-05)
+
+
+### Features
+
+* add health-potion functionality 2f13844
+* purchasable items from the store 4d8b8b1
+
+
+### Bug Fixes
+
+* migrate chat to htmx 34c9eae
+* migrate explore fight to htmx d955aa8
+* migrate exploring to htmx 1580d3a
+* migrate healer to htmx 18e87bf
+* migrate inventory to htmx 0a45adb
+* migrate item usage to htmx 6fb15e2
+* migrate shops to htmx 09b3c0d
+* migrate skills page to htmx c0de5fa
+* profile page to html (wip) eeead89
+* remove unnecessary console.log e547728
+* rename shop_items to shop_equipment 68d481a
+* support time display e110480
+
 ### [0.2.4](https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff;h=v0.2.4;hp=v0.2.3;ds=sidebyside) (2023-07-29)
 
 
 ### [0.2.4](https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff;h=v0.2.4;hp=v0.2.3;ds=sidebyside) (2023-07-29)
 
 
diff --git a/migrations/20230729184427_items.ts b/migrations/20230729184427_items.ts
new file mode 100644 (file)
index 0000000..4f7d09a
--- /dev/null
@@ -0,0 +1,24 @@
+import { Knex } from "knex";
+
+
+export async function up(knex: Knex): Promise<void> {
+  return knex.schema.createTable('items', function(table) {
+    table.increments('id').primary();
+    table.string('name');
+    table.string('description');
+    table.string('effect_name');
+    table.string('icon_name');
+  }).createTable('player_items', function(table) {
+      table.integer('item_id');
+      table.string('player_id');
+      table.integer('amount').defaultTo(1);
+
+      table.primary(['item_id', 'player_id']);
+    });
+}
+
+
+export async function down(knex: Knex): Promise<void> {
+  return knex.schema.dropTable('items').dropTable('player_items');
+}
+
diff --git a/migrations/20230802173517_shop_equipment.ts b/migrations/20230802173517_shop_equipment.ts
new file mode 100644 (file)
index 0000000..c0077dc
--- /dev/null
@@ -0,0 +1,15 @@
+import { Knex } from "knex";
+
+
+export async function up(knex: Knex): Promise<void> {
+  return knex.schema.alterTable('shop_items', function(table) {
+    table.dropPrimary();
+    table.primary(['id'], 'shop_equipment_pkey');
+  }).renameTable('shop_items', 'shop_equipment');
+}
+
+
+export async function down(knex: Knex): Promise<void> {
+  return knex.schema.renameTable('shop_equipment', 'shop_items');
+}
+
diff --git a/migrations/20230802174902_items-in-shop.ts b/migrations/20230802174902_items-in-shop.ts
new file mode 100644 (file)
index 0000000..2579162
--- /dev/null
@@ -0,0 +1,18 @@
+import { Knex } from "knex";
+
+
+export async function up(knex: Knex): Promise<void> {
+  return knex.schema.createTable('shop_items', function(table) {
+    table.integer('item_id');
+    table.integer('location_id');
+    table.integer('amount');
+    table.integer('price_per_unit');
+    table.primary(['item_id', 'location_id']);
+  });
+}
+
+
+export async function down(knex: Knex): Promise<void> {
+  return knex.schema.dropTable('shop_items');
+}
+
index b468207608e3cadb15a1ca8d1827ac81d4b3b44d..3d3fe4720bd3f2ae384dbef35209f46916973d08 100644 (file)
@@ -1,12 +1,12 @@
 {
   "name": "rising-legends",
 {
   "name": "rising-legends",
-  "version": "0.2.4",
+  "version": "0.2.5",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "rising-legends",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "rising-legends",
-      "version": "0.2.4",
+      "version": "0.2.5",
       "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 7b5f04e5fd49e754d5eae9b697a330923929cc41..7e36845b0dc2a820b285aba76bd4d9ffc70c6bdb 100644 (file)
@@ -1,7 +1,7 @@
 {
   "name": "rising-legends",
   "private": true,
 {
   "name": "rising-legends",
   "private": true,
-  "version": "0.2.4",
+  "version": "0.2.5",
   "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 14865b9aee6bc908b11185e2222e2b8315b8d7de..239b458de5390913d98e61adf20e4645916541ff 100644 (file)
@@ -1,2 +1 @@
-/*! For license information please see bundle.js.LICENSE.txt */
-(()=>{var t={4802:(t,e,n)=>{e.formatArgs=function(e){if(e[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+e[0]+(this.useColors?"%c ":" ")+"+"+t.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;e.splice(1,0,n,"color: inherit");let r=0,i=0;e[0].replace(/%[a-zA-Z%]/g,(t=>{"%%"!==t&&(r++,"%c"===t&&(i=r))})),e.splice(i,0,n)},e.save=function(t){try{t?e.storage.setItem("debug",t):e.storage.removeItem("debug")}catch(t){}},e.load=function(){let t;try{t=e.storage.getItem("debug")}catch(t){}return!t&&"undefined"!=typeof process&&"env"in process&&(t=process.env.DEBUG),t},e.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+)/))},e.storage=function(){try{return localStorage}catch(t){}}(),e.destroy=(()=>{let t=!1;return()=>{t||(t=!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`."))}})(),e.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"],e.log=console.debug||console.log||(()=>{}),t.exports=n(804)(e);const{formatters:r}=t.exports;r.j=function(t){try{return JSON.stringify(t)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}}},804:(t,e,n)=>{t.exports=function(t){function e(t){let n,i,o,s=null;function a(...t){if(!a.enabled)return;const r=a,i=Number(new Date),o=i-(n||i);r.diff=o,r.prev=n,r.curr=i,n=i,t[0]=e.coerce(t[0]),"string"!=typeof t[0]&&t.unshift("%O");let s=0;t[0]=t[0].replace(/%([a-zA-Z%])/g,((n,i)=>{if("%%"===n)return"%";s++;const o=e.formatters[i];if("function"==typeof o){const e=t[s];n=o.call(r,e),t.splice(s,1),s--}return n})),e.formatArgs.call(r,t),(r.log||e.log).apply(r,t)}return a.namespace=t,a.useColors=e.useColors(),a.color=e.selectColor(t),a.extend=r,a.destroy=e.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==s?s:(i!==e.namespaces&&(i=e.namespaces,o=e.enabled(t)),o),set:t=>{s=t}}),"function"==typeof e.init&&e.init(a),a}function r(t,n){const r=e(this.namespace+(void 0===n?":":n)+t);return r.log=this.log,r}function i(t){return t.toString().substring(2,t.toString().length-2).replace(/\.\*\?$/,"*")}return e.debug=e,e.default=e,e.coerce=function(t){return t instanceof Error?t.stack||t.message:t},e.disable=function(){const t=[...e.names.map(i),...e.skips.map(i).map((t=>"-"+t))].join(",");return e.enable(""),t},e.enable=function(t){let n;e.save(t),e.namespaces=t,e.names=[],e.skips=[];const r=("string"==typeof t?t:"").split(/[\s,]+/),i=r.length;for(n=0;n<i;n++)r[n]&&("-"===(t=r[n].replace(/\*/g,".*?"))[0]?e.skips.push(new RegExp("^"+t.slice(1)+"$")):e.names.push(new RegExp("^"+t+"$")))},e.enabled=function(t){if("*"===t[t.length-1])return!0;let n,r;for(n=0,r=e.skips.length;n<r;n++)if(e.skips[n].test(t))return!1;for(n=0,r=e.names.length;n<r;n++)if(e.names[n].test(t))return!0;return!1},e.humanize=n(810),e.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(t).forEach((n=>{e[n]=t[n]})),e.names=[],e.skips=[],e.formatters={},e.selectColor=function(t){let n=0;for(let e=0;e<t.length;e++)n=(n<<5)-n+t.charCodeAt(e),n|=0;return e.colors[Math.abs(n)%e.colors.length]},e.enable(e.load()),e}},810:t=>{var e=1e3,n=60*e,r=60*n,i=24*r;function o(t,e,n,r){var i=e>=1.5*n;return Math.round(t/n)+" "+r+(i?"s":"")}t.exports=function(t,s){s=s||{};var a,u,c=typeof t;if("string"===c&&t.length>0)return function(t){if(!((t=String(t)).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(t);if(o){var s=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*s;case"weeks":case"week":case"w":return 6048e5*s;case"days":case"day":case"d":return s*i;case"hours":case"hour":case"hrs":case"hr":case"h":return s*r;case"minutes":case"minute":case"mins":case"min":case"m":return s*n;case"seconds":case"second":case"secs":case"sec":case"s":return s*e;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return s;default:return}}}}(t);if("number"===c&&isFinite(t))return s.long?(a=t,(u=Math.abs(a))>=i?o(a,u,i,"day"):u>=r?o(a,u,r,"hour"):u>=n?o(a,u,n,"minute"):u>=e?o(a,u,e,"second"):a+" ms"):function(t){var o=Math.abs(t);return o>=i?Math.round(t/i)+"d":o>=r?Math.round(t/r)+"h":o>=n?Math.round(t/n)+"m":o>=e?Math.round(t/e)+"s":t+"ms"}(t);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(t))}},6486:function(t,e,n){var r;t=n.nmd(t),function(){var i,o="Expected a function",s="__lodash_hash_undefined__",a="__lodash_placeholder__",u=32,c=128,l=1/0,f=9007199254740991,d=NaN,h=4294967295,p=[["ary",c],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",u],["partialRight",64],["rearg",256]],g="[object Arguments]",v="[object Array]",y="[object Boolean]",m="[object Date]",_="[object Error]",b="[object Function]",C="[object GeneratorFunction]",w="[object Map]",k="[object Number]",E="[object Object]",S="[object Promise]",A="[object RegExp]",x="[object Set]",O="[object String]",T="[object Symbol]",F="[object WeakMap]",j="[object ArrayBuffer]",$="[object DataView]",P="[object Float32Array]",R="[object Float64Array]",M="[object Int8Array]",L="[object Int16Array]",N="[object Int32Array]",D="[object Uint8Array]",I="[object Uint8ClampedArray]",B="[object Uint16Array]",q="[object Uint32Array]",H=/\b__p \+= '';/g,U=/\b(__p \+=) '' \+/g,W=/(__e\(.*?\)|\b__t\)) \+\n'';/g,z=/&(?:amp|lt|gt|quot|#39);/g,V=/[&<>"']/g,K=RegExp(z.source),Y=RegExp(V.source),G=/<%-([\s\S]+?)%>/g,J=/<%([\s\S]+?)%>/g,X=/<%=([\s\S]+?)%>/g,Z=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Q=/^\w*$/,tt=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,et=/[\\^$.*+?()[\]{}|]/g,nt=RegExp(et.source),rt=/^\s+/,it=/\s/,ot=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,st=/\{\n\/\* \[wrapped with (.+)\] \*/,at=/,? & /,ut=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,ct=/[()=,{}\[\]\/\s]/,lt=/\\(\\)?/g,ft=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,dt=/\w*$/,ht=/^[-+]0x[0-9a-f]+$/i,pt=/^0b[01]+$/i,gt=/^\[object .+?Constructor\]$/,vt=/^0o[0-7]+$/i,yt=/^(?:0|[1-9]\d*)$/,mt=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,_t=/($^)/,bt=/['\n\r\u2028\u2029\\]/g,Ct="\\ud800-\\udfff",wt="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",kt="\\u2700-\\u27bf",Et="a-z\\xdf-\\xf6\\xf8-\\xff",St="A-Z\\xc0-\\xd6\\xd8-\\xde",At="\\ufe0e\\ufe0f",xt="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",Ot="["+Ct+"]",Tt="["+xt+"]",Ft="["+wt+"]",jt="\\d+",$t="["+kt+"]",Pt="["+Et+"]",Rt="[^"+Ct+xt+jt+kt+Et+St+"]",Mt="\\ud83c[\\udffb-\\udfff]",Lt="[^"+Ct+"]",Nt="(?:\\ud83c[\\udde6-\\uddff]){2}",Dt="[\\ud800-\\udbff][\\udc00-\\udfff]",It="["+St+"]",Bt="\\u200d",qt="(?:"+Pt+"|"+Rt+")",Ht="(?:"+It+"|"+Rt+")",Ut="(?:['’](?:d|ll|m|re|s|t|ve))?",Wt="(?:['’](?:D|LL|M|RE|S|T|VE))?",zt="(?:"+Ft+"|"+Mt+")?",Vt="["+At+"]?",Kt=Vt+zt+"(?:"+Bt+"(?:"+[Lt,Nt,Dt].join("|")+")"+Vt+zt+")*",Yt="(?:"+[$t,Nt,Dt].join("|")+")"+Kt,Gt="(?:"+[Lt+Ft+"?",Ft,Nt,Dt,Ot].join("|")+")",Jt=RegExp("['’]","g"),Xt=RegExp(Ft,"g"),Zt=RegExp(Mt+"(?="+Mt+")|"+Gt+Kt,"g"),Qt=RegExp([It+"?"+Pt+"+"+Ut+"(?="+[Tt,It,"$"].join("|")+")",Ht+"+"+Wt+"(?="+[Tt,It+qt,"$"].join("|")+")",It+"?"+qt+"+"+Ut,It+"+"+Wt,"\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",jt,Yt].join("|"),"g"),te=RegExp("["+Bt+Ct+wt+At+"]"),ee=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,ne=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],re=-1,ie={};ie[P]=ie[R]=ie[M]=ie[L]=ie[N]=ie[D]=ie[I]=ie[B]=ie[q]=!0,ie[g]=ie[v]=ie[j]=ie[y]=ie[$]=ie[m]=ie[_]=ie[b]=ie[w]=ie[k]=ie[E]=ie[A]=ie[x]=ie[O]=ie[F]=!1;var oe={};oe[g]=oe[v]=oe[j]=oe[$]=oe[y]=oe[m]=oe[P]=oe[R]=oe[M]=oe[L]=oe[N]=oe[w]=oe[k]=oe[E]=oe[A]=oe[x]=oe[O]=oe[T]=oe[D]=oe[I]=oe[B]=oe[q]=!0,oe[_]=oe[b]=oe[F]=!1;var se={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},ae=parseFloat,ue=parseInt,ce="object"==typeof n.g&&n.g&&n.g.Object===Object&&n.g,le="object"==typeof self&&self&&self.Object===Object&&self,fe=ce||le||Function("return this")(),de=e&&!e.nodeType&&e,he=de&&t&&!t.nodeType&&t,pe=he&&he.exports===de,ge=pe&&ce.process,ve=function(){try{return he&&he.require&&he.require("util").types||ge&&ge.binding&&ge.binding("util")}catch(t){}}(),ye=ve&&ve.isArrayBuffer,me=ve&&ve.isDate,_e=ve&&ve.isMap,be=ve&&ve.isRegExp,Ce=ve&&ve.isSet,we=ve&&ve.isTypedArray;function ke(t,e,n){switch(n.length){case 0:return t.call(e);case 1:return t.call(e,n[0]);case 2:return t.call(e,n[0],n[1]);case 3:return t.call(e,n[0],n[1],n[2])}return t.apply(e,n)}function Ee(t,e,n,r){for(var i=-1,o=null==t?0:t.length;++i<o;){var s=t[i];e(r,s,n(s),t)}return r}function Se(t,e){for(var n=-1,r=null==t?0:t.length;++n<r&&!1!==e(t[n],n,t););return t}function Ae(t,e){for(var n=null==t?0:t.length;n--&&!1!==e(t[n],n,t););return t}function xe(t,e){for(var n=-1,r=null==t?0:t.length;++n<r;)if(!e(t[n],n,t))return!1;return!0}function Oe(t,e){for(var n=-1,r=null==t?0:t.length,i=0,o=[];++n<r;){var s=t[n];e(s,n,t)&&(o[i++]=s)}return o}function Te(t,e){return!(null==t||!t.length)&&Ie(t,e,0)>-1}function Fe(t,e,n){for(var r=-1,i=null==t?0:t.length;++r<i;)if(n(e,t[r]))return!0;return!1}function je(t,e){for(var n=-1,r=null==t?0:t.length,i=Array(r);++n<r;)i[n]=e(t[n],n,t);return i}function $e(t,e){for(var n=-1,r=e.length,i=t.length;++n<r;)t[i+n]=e[n];return t}function Pe(t,e,n,r){var i=-1,o=null==t?0:t.length;for(r&&o&&(n=t[++i]);++i<o;)n=e(n,t[i],i,t);return n}function Re(t,e,n,r){var i=null==t?0:t.length;for(r&&i&&(n=t[--i]);i--;)n=e(n,t[i],i,t);return n}function Me(t,e){for(var n=-1,r=null==t?0:t.length;++n<r;)if(e(t[n],n,t))return!0;return!1}var Le=Ue("length");function Ne(t,e,n){var r;return n(t,(function(t,n,i){if(e(t,n,i))return r=n,!1})),r}function De(t,e,n,r){for(var i=t.length,o=n+(r?1:-1);r?o--:++o<i;)if(e(t[o],o,t))return o;return-1}function Ie(t,e,n){return e==e?function(t,e,n){for(var r=n-1,i=t.length;++r<i;)if(t[r]===e)return r;return-1}(t,e,n):De(t,qe,n)}function Be(t,e,n,r){for(var i=n-1,o=t.length;++i<o;)if(r(t[i],e))return i;return-1}function qe(t){return t!=t}function He(t,e){var n=null==t?0:t.length;return n?Ve(t,e)/n:d}function Ue(t){return function(e){return null==e?i:e[t]}}function We(t){return function(e){return null==t?i:t[e]}}function ze(t,e,n,r,i){return i(t,(function(t,i,o){n=r?(r=!1,t):e(n,t,i,o)})),n}function Ve(t,e){for(var n,r=-1,o=t.length;++r<o;){var s=e(t[r]);s!==i&&(n=n===i?s:n+s)}return n}function Ke(t,e){for(var n=-1,r=Array(t);++n<t;)r[n]=e(n);return r}function Ye(t){return t?t.slice(0,dn(t)+1).replace(rt,""):t}function Ge(t){return function(e){return t(e)}}function Je(t,e){return je(e,(function(e){return t[e]}))}function Xe(t,e){return t.has(e)}function Ze(t,e){for(var n=-1,r=t.length;++n<r&&Ie(e,t[n],0)>-1;);return n}function Qe(t,e){for(var n=t.length;n--&&Ie(e,t[n],0)>-1;);return n}var tn=We({À:"A",Á:"A",Â:"A",Ã:"A",Ä:"A",Å:"A",à:"a",á:"a",â:"a",ã:"a",ä:"a",å:"a",Ç:"C",ç:"c",Ð:"D",ð:"d",È:"E",É:"E",Ê:"E",Ë:"E",è:"e",é:"e",ê:"e",ë:"e",Ì:"I",Í:"I",Î:"I",Ï:"I",ì:"i",í:"i",î:"i",ï:"i",Ñ:"N",ñ:"n",Ò:"O",Ó:"O",Ô:"O",Õ:"O",Ö:"O",Ø:"O",ò:"o",ó:"o",ô:"o",õ:"o",ö:"o",ø:"o",Ù:"U",Ú:"U",Û:"U",Ü:"U",ù:"u",ú:"u",û:"u",ü:"u",Ý:"Y",ý:"y",ÿ:"y",Æ:"Ae",æ:"ae",Þ:"Th",þ:"th",ß:"ss",Ā:"A",Ă:"A",Ą:"A",ā:"a",ă:"a",ą:"a",Ć:"C",Ĉ:"C",Ċ:"C",Č:"C",ć:"c",ĉ:"c",ċ:"c",č:"c",Ď:"D",Đ:"D",ď:"d",đ:"d",Ē:"E",Ĕ:"E",Ė:"E",Ę:"E",Ě:"E",ē:"e",ĕ:"e",ė:"e",ę:"e",ě:"e",Ĝ:"G",Ğ:"G",Ġ:"G",Ģ:"G",ĝ:"g",ğ:"g",ġ:"g",ģ:"g",Ĥ:"H",Ħ:"H",ĥ:"h",ħ:"h",Ĩ:"I",Ī:"I",Ĭ:"I",Į:"I",İ:"I",ĩ:"i",ī:"i",ĭ:"i",į:"i",ı:"i",Ĵ:"J",ĵ:"j",Ķ:"K",ķ:"k",ĸ:"k",Ĺ:"L",Ļ:"L",Ľ:"L",Ŀ:"L",Ł:"L",ĺ:"l",ļ:"l",ľ:"l",ŀ:"l",ł:"l",Ń:"N",Ņ:"N",Ň:"N",Ŋ:"N",ń:"n",ņ:"n",ň:"n",ŋ:"n",Ō:"O",Ŏ:"O",Ő:"O",ō:"o",ŏ:"o",ő:"o",Ŕ:"R",Ŗ:"R",Ř:"R",ŕ:"r",ŗ:"r",ř:"r",Ś:"S",Ŝ:"S",Ş:"S",Š:"S",ś:"s",ŝ:"s",ş:"s",š:"s",Ţ:"T",Ť:"T",Ŧ:"T",ţ:"t",ť:"t",ŧ:"t",Ũ:"U",Ū:"U",Ŭ:"U",Ů:"U",Ű:"U",Ų:"U",ũ:"u",ū:"u",ŭ:"u",ů:"u",ű:"u",ų:"u",Ŵ:"W",ŵ:"w",Ŷ:"Y",ŷ:"y",Ÿ:"Y",Ź:"Z",Ż:"Z",Ž:"Z",ź:"z",ż:"z",ž:"z",IJ:"IJ",ij:"ij",Œ:"Oe",œ:"oe",ʼn:"'n",ſ:"s"}),en=We({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"});function nn(t){return"\\"+se[t]}function rn(t){return te.test(t)}function on(t){var e=-1,n=Array(t.size);return t.forEach((function(t,r){n[++e]=[r,t]})),n}function sn(t,e){return function(n){return t(e(n))}}function an(t,e){for(var n=-1,r=t.length,i=0,o=[];++n<r;){var s=t[n];s!==e&&s!==a||(t[n]=a,o[i++]=n)}return o}function un(t){var e=-1,n=Array(t.size);return t.forEach((function(t){n[++e]=t})),n}function cn(t){var e=-1,n=Array(t.size);return t.forEach((function(t){n[++e]=[t,t]})),n}function ln(t){return rn(t)?function(t){for(var e=Zt.lastIndex=0;Zt.test(t);)++e;return e}(t):Le(t)}function fn(t){return rn(t)?function(t){return t.match(Zt)||[]}(t):function(t){return t.split("")}(t)}function dn(t){for(var e=t.length;e--&&it.test(t.charAt(e)););return e}var hn=We({"&amp;":"&","&lt;":"<","&gt;":">","&quot;":'"',"&#39;":"'"}),pn=function t(e){var n,r=(e=null==e?fe:pn.defaults(fe.Object(),e,pn.pick(fe,ne))).Array,it=e.Date,Ct=e.Error,wt=e.Function,kt=e.Math,Et=e.Object,St=e.RegExp,At=e.String,xt=e.TypeError,Ot=r.prototype,Tt=wt.prototype,Ft=Et.prototype,jt=e["__core-js_shared__"],$t=Tt.toString,Pt=Ft.hasOwnProperty,Rt=0,Mt=(n=/[^.]+$/.exec(jt&&jt.keys&&jt.keys.IE_PROTO||""))?"Symbol(src)_1."+n:"",Lt=Ft.toString,Nt=$t.call(Et),Dt=fe._,It=St("^"+$t.call(Pt).replace(et,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Bt=pe?e.Buffer:i,qt=e.Symbol,Ht=e.Uint8Array,Ut=Bt?Bt.allocUnsafe:i,Wt=sn(Et.getPrototypeOf,Et),zt=Et.create,Vt=Ft.propertyIsEnumerable,Kt=Ot.splice,Yt=qt?qt.isConcatSpreadable:i,Gt=qt?qt.iterator:i,Zt=qt?qt.toStringTag:i,te=function(){try{var t=uo(Et,"defineProperty");return t({},"",{}),t}catch(t){}}(),se=e.clearTimeout!==fe.clearTimeout&&e.clearTimeout,ce=it&&it.now!==fe.Date.now&&it.now,le=e.setTimeout!==fe.setTimeout&&e.setTimeout,de=kt.ceil,he=kt.floor,ge=Et.getOwnPropertySymbols,ve=Bt?Bt.isBuffer:i,Le=e.isFinite,We=Ot.join,gn=sn(Et.keys,Et),vn=kt.max,yn=kt.min,mn=it.now,_n=e.parseInt,bn=kt.random,Cn=Ot.reverse,wn=uo(e,"DataView"),kn=uo(e,"Map"),En=uo(e,"Promise"),Sn=uo(e,"Set"),An=uo(e,"WeakMap"),xn=uo(Et,"create"),On=An&&new An,Tn={},Fn=No(wn),jn=No(kn),$n=No(En),Pn=No(Sn),Rn=No(An),Mn=qt?qt.prototype:i,Ln=Mn?Mn.valueOf:i,Nn=Mn?Mn.toString:i;function Dn(t){if(ta(t)&&!Us(t)&&!(t instanceof Hn)){if(t instanceof qn)return t;if(Pt.call(t,"__wrapped__"))return Do(t)}return new qn(t)}var In=function(){function t(){}return function(e){if(!Qs(e))return{};if(zt)return zt(e);t.prototype=e;var n=new t;return t.prototype=i,n}}();function Bn(){}function qn(t,e){this.__wrapped__=t,this.__actions__=[],this.__chain__=!!e,this.__index__=0,this.__values__=i}function Hn(t){this.__wrapped__=t,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=h,this.__views__=[]}function Un(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e<n;){var r=t[e];this.set(r[0],r[1])}}function Wn(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e<n;){var r=t[e];this.set(r[0],r[1])}}function zn(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e<n;){var r=t[e];this.set(r[0],r[1])}}function Vn(t){var e=-1,n=null==t?0:t.length;for(this.__data__=new zn;++e<n;)this.add(t[e])}function Kn(t){var e=this.__data__=new Wn(t);this.size=e.size}function Yn(t,e){var n=Us(t),r=!n&&Hs(t),i=!n&&!r&&Ks(t),o=!n&&!r&&!i&&ua(t),s=n||r||i||o,a=s?Ke(t.length,At):[],u=a.length;for(var c in t)!e&&!Pt.call(t,c)||s&&("length"==c||i&&("offset"==c||"parent"==c)||o&&("buffer"==c||"byteLength"==c||"byteOffset"==c)||vo(c,u))||a.push(c);return a}function Gn(t){var e=t.length;return e?t[zr(0,e-1)]:i}function Jn(t,e){return $o(Ai(t),or(e,0,t.length))}function Xn(t){return $o(Ai(t))}function Zn(t,e,n){(n!==i&&!Is(t[e],n)||n===i&&!(e in t))&&rr(t,e,n)}function Qn(t,e,n){var r=t[e];Pt.call(t,e)&&Is(r,n)&&(n!==i||e in t)||rr(t,e,n)}function tr(t,e){for(var n=t.length;n--;)if(Is(t[n][0],e))return n;return-1}function er(t,e,n,r){return lr(t,(function(t,i,o){e(r,t,n(t),o)})),r}function nr(t,e){return t&&xi(e,Fa(e),t)}function rr(t,e,n){"__proto__"==e&&te?te(t,e,{configurable:!0,enumerable:!0,value:n,writable:!0}):t[e]=n}function ir(t,e){for(var n=-1,o=e.length,s=r(o),a=null==t;++n<o;)s[n]=a?i:Sa(t,e[n]);return s}function or(t,e,n){return t==t&&(n!==i&&(t=t<=n?t:n),e!==i&&(t=t>=e?t:e)),t}function sr(t,e,n,r,o,s){var a,u=1&e,c=2&e,l=4&e;if(n&&(a=o?n(t,r,o,s):n(t)),a!==i)return a;if(!Qs(t))return t;var f=Us(t);if(f){if(a=function(t){var e=t.length,n=new t.constructor(e);return e&&"string"==typeof t[0]&&Pt.call(t,"index")&&(n.index=t.index,n.input=t.input),n}(t),!u)return Ai(t,a)}else{var d=fo(t),h=d==b||d==C;if(Ks(t))return bi(t,u);if(d==E||d==g||h&&!o){if(a=c||h?{}:po(t),!u)return c?function(t,e){return xi(t,lo(t),e)}(t,function(t,e){return t&&xi(e,ja(e),t)}(a,t)):function(t,e){return xi(t,co(t),e)}(t,nr(a,t))}else{if(!oe[d])return o?t:{};a=function(t,e,n){var r,i=t.constructor;switch(e){case j:return Ci(t);case y:case m:return new i(+t);case $:return function(t,e){var n=e?Ci(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.byteLength)}(t,n);case P:case R:case M:case L:case N:case D:case I:case B:case q:return wi(t,n);case w:return new i;case k:case O:return new i(t);case A:return function(t){var e=new t.constructor(t.source,dt.exec(t));return e.lastIndex=t.lastIndex,e}(t);case x:return new i;case T:return r=t,Ln?Et(Ln.call(r)):{}}}(t,d,u)}}s||(s=new Kn);var p=s.get(t);if(p)return p;s.set(t,a),oa(t)?t.forEach((function(r){a.add(sr(r,e,n,r,t,s))})):ea(t)&&t.forEach((function(r,i){a.set(i,sr(r,e,n,i,t,s))}));var v=f?i:(l?c?eo:to:c?ja:Fa)(t);return Se(v||t,(function(r,i){v&&(r=t[i=r]),Qn(a,i,sr(r,e,n,i,t,s))})),a}function ar(t,e,n){var r=n.length;if(null==t)return!r;for(t=Et(t);r--;){var o=n[r],s=e[o],a=t[o];if(a===i&&!(o in t)||!s(a))return!1}return!0}function ur(t,e,n){if("function"!=typeof t)throw new xt(o);return Oo((function(){t.apply(i,n)}),e)}function cr(t,e,n,r){var i=-1,o=Te,s=!0,a=t.length,u=[],c=e.length;if(!a)return u;n&&(e=je(e,Ge(n))),r?(o=Fe,s=!1):e.length>=200&&(o=Xe,s=!1,e=new Vn(e));t:for(;++i<a;){var l=t[i],f=null==n?l:n(l);if(l=r||0!==l?l:0,s&&f==f){for(var d=c;d--;)if(e[d]===f)continue t;u.push(l)}else o(e,f,r)||u.push(l)}return u}Dn.templateSettings={escape:G,evaluate:J,interpolate:X,variable:"",imports:{_:Dn}},Dn.prototype=Bn.prototype,Dn.prototype.constructor=Dn,qn.prototype=In(Bn.prototype),qn.prototype.constructor=qn,Hn.prototype=In(Bn.prototype),Hn.prototype.constructor=Hn,Un.prototype.clear=function(){this.__data__=xn?xn(null):{},this.size=0},Un.prototype.delete=function(t){var e=this.has(t)&&delete this.__data__[t];return this.size-=e?1:0,e},Un.prototype.get=function(t){var e=this.__data__;if(xn){var n=e[t];return n===s?i:n}return Pt.call(e,t)?e[t]:i},Un.prototype.has=function(t){var e=this.__data__;return xn?e[t]!==i:Pt.call(e,t)},Un.prototype.set=function(t,e){var n=this.__data__;return this.size+=this.has(t)?0:1,n[t]=xn&&e===i?s:e,this},Wn.prototype.clear=function(){this.__data__=[],this.size=0},Wn.prototype.delete=function(t){var e=this.__data__,n=tr(e,t);return!(n<0||(n==e.length-1?e.pop():Kt.call(e,n,1),--this.size,0))},Wn.prototype.get=function(t){var e=this.__data__,n=tr(e,t);return n<0?i:e[n][1]},Wn.prototype.has=function(t){return tr(this.__data__,t)>-1},Wn.prototype.set=function(t,e){var n=this.__data__,r=tr(n,t);return r<0?(++this.size,n.push([t,e])):n[r][1]=e,this},zn.prototype.clear=function(){this.size=0,this.__data__={hash:new Un,map:new(kn||Wn),string:new Un}},zn.prototype.delete=function(t){var e=so(this,t).delete(t);return this.size-=e?1:0,e},zn.prototype.get=function(t){return so(this,t).get(t)},zn.prototype.has=function(t){return so(this,t).has(t)},zn.prototype.set=function(t,e){var n=so(this,t),r=n.size;return n.set(t,e),this.size+=n.size==r?0:1,this},Vn.prototype.add=Vn.prototype.push=function(t){return this.__data__.set(t,s),this},Vn.prototype.has=function(t){return this.__data__.has(t)},Kn.prototype.clear=function(){this.__data__=new Wn,this.size=0},Kn.prototype.delete=function(t){var e=this.__data__,n=e.delete(t);return this.size=e.size,n},Kn.prototype.get=function(t){return this.__data__.get(t)},Kn.prototype.has=function(t){return this.__data__.has(t)},Kn.prototype.set=function(t,e){var n=this.__data__;if(n instanceof Wn){var r=n.__data__;if(!kn||r.length<199)return r.push([t,e]),this.size=++n.size,this;n=this.__data__=new zn(r)}return n.set(t,e),this.size=n.size,this};var lr=Fi(mr),fr=Fi(_r,!0);function dr(t,e){var n=!0;return lr(t,(function(t,r,i){return n=!!e(t,r,i)})),n}function hr(t,e,n){for(var r=-1,o=t.length;++r<o;){var s=t[r],a=e(s);if(null!=a&&(u===i?a==a&&!aa(a):n(a,u)))var u=a,c=s}return c}function pr(t,e){var n=[];return lr(t,(function(t,r,i){e(t,r,i)&&n.push(t)})),n}function gr(t,e,n,r,i){var o=-1,s=t.length;for(n||(n=go),i||(i=[]);++o<s;){var a=t[o];e>0&&n(a)?e>1?gr(a,e-1,n,r,i):$e(i,a):r||(i[i.length]=a)}return i}var vr=ji(),yr=ji(!0);function mr(t,e){return t&&vr(t,e,Fa)}function _r(t,e){return t&&yr(t,e,Fa)}function br(t,e){return Oe(e,(function(e){return Js(t[e])}))}function Cr(t,e){for(var n=0,r=(e=vi(e,t)).length;null!=t&&n<r;)t=t[Lo(e[n++])];return n&&n==r?t:i}function wr(t,e,n){var r=e(t);return Us(t)?r:$e(r,n(t))}function kr(t){return null==t?t===i?"[object Undefined]":"[object Null]":Zt&&Zt in Et(t)?function(t){var e=Pt.call(t,Zt),n=t[Zt];try{t[Zt]=i;var r=!0}catch(t){}var o=Lt.call(t);return r&&(e?t[Zt]=n:delete t[Zt]),o}(t):function(t){return Lt.call(t)}(t)}function Er(t,e){return t>e}function Sr(t,e){return null!=t&&Pt.call(t,e)}function Ar(t,e){return null!=t&&e in Et(t)}function xr(t,e,n){for(var o=n?Fe:Te,s=t[0].length,a=t.length,u=a,c=r(a),l=1/0,f=[];u--;){var d=t[u];u&&e&&(d=je(d,Ge(e))),l=yn(d.length,l),c[u]=!n&&(e||s>=120&&d.length>=120)?new Vn(u&&d):i}d=t[0];var h=-1,p=c[0];t:for(;++h<s&&f.length<l;){var g=d[h],v=e?e(g):g;if(g=n||0!==g?g:0,!(p?Xe(p,v):o(f,v,n))){for(u=a;--u;){var y=c[u];if(!(y?Xe(y,v):o(t[u],v,n)))continue t}p&&p.push(v),f.push(g)}}return f}function Or(t,e,n){var r=null==(t=So(t,e=vi(e,t)))?t:t[Lo(Go(e))];return null==r?i:ke(r,t,n)}function Tr(t){return ta(t)&&kr(t)==g}function Fr(t,e,n,r,o){return t===e||(null==t||null==e||!ta(t)&&!ta(e)?t!=t&&e!=e:function(t,e,n,r,o,s){var a=Us(t),u=Us(e),c=a?v:fo(t),l=u?v:fo(e),f=(c=c==g?E:c)==E,d=(l=l==g?E:l)==E,h=c==l;if(h&&Ks(t)){if(!Ks(e))return!1;a=!0,f=!1}if(h&&!f)return s||(s=new Kn),a||ua(t)?Zi(t,e,n,r,o,s):function(t,e,n,r,i,o,s){switch(n){case $:if(t.byteLength!=e.byteLength||t.byteOffset!=e.byteOffset)return!1;t=t.buffer,e=e.buffer;case j:return!(t.byteLength!=e.byteLength||!o(new Ht(t),new Ht(e)));case y:case m:case k:return Is(+t,+e);case _:return t.name==e.name&&t.message==e.message;case A:case O:return t==e+"";case w:var a=on;case x:var u=1&r;if(a||(a=un),t.size!=e.size&&!u)return!1;var c=s.get(t);if(c)return c==e;r|=2,s.set(t,e);var l=Zi(a(t),a(e),r,i,o,s);return s.delete(t),l;case T:if(Ln)return Ln.call(t)==Ln.call(e)}return!1}(t,e,c,n,r,o,s);if(!(1&n)){var p=f&&Pt.call(t,"__wrapped__"),b=d&&Pt.call(e,"__wrapped__");if(p||b){var C=p?t.value():t,S=b?e.value():e;return s||(s=new Kn),o(C,S,n,r,s)}}return!!h&&(s||(s=new Kn),function(t,e,n,r,o,s){var a=1&n,u=to(t),c=u.length;if(c!=to(e).length&&!a)return!1;for(var l=c;l--;){var f=u[l];if(!(a?f in e:Pt.call(e,f)))return!1}var d=s.get(t),h=s.get(e);if(d&&h)return d==e&&h==t;var p=!0;s.set(t,e),s.set(e,t);for(var g=a;++l<c;){var v=t[f=u[l]],y=e[f];if(r)var m=a?r(y,v,f,e,t,s):r(v,y,f,t,e,s);if(!(m===i?v===y||o(v,y,n,r,s):m)){p=!1;break}g||(g="constructor"==f)}if(p&&!g){var _=t.constructor,b=e.constructor;_==b||!("constructor"in t)||!("constructor"in e)||"function"==typeof _&&_ instanceof _&&"function"==typeof b&&b instanceof b||(p=!1)}return s.delete(t),s.delete(e),p}(t,e,n,r,o,s))}(t,e,n,r,Fr,o))}function jr(t,e,n,r){var o=n.length,s=o,a=!r;if(null==t)return!s;for(t=Et(t);o--;){var u=n[o];if(a&&u[2]?u[1]!==t[u[0]]:!(u[0]in t))return!1}for(;++o<s;){var c=(u=n[o])[0],l=t[c],f=u[1];if(a&&u[2]){if(l===i&&!(c in t))return!1}else{var d=new Kn;if(r)var h=r(l,f,c,t,e,d);if(!(h===i?Fr(f,l,3,r,d):h))return!1}}return!0}function $r(t){return!(!Qs(t)||(e=t,Mt&&Mt in e))&&(Js(t)?It:gt).test(No(t));var e}function Pr(t){return"function"==typeof t?t:null==t?nu:"object"==typeof t?Us(t)?Dr(t[0],t[1]):Nr(t):fu(t)}function Rr(t){if(!Co(t))return gn(t);var e=[];for(var n in Et(t))Pt.call(t,n)&&"constructor"!=n&&e.push(n);return e}function Mr(t,e){return t<e}function Lr(t,e){var n=-1,i=zs(t)?r(t.length):[];return lr(t,(function(t,r,o){i[++n]=e(t,r,o)})),i}function Nr(t){var e=ao(t);return 1==e.length&&e[0][2]?ko(e[0][0],e[0][1]):function(n){return n===t||jr(n,t,e)}}function Dr(t,e){return mo(t)&&wo(e)?ko(Lo(t),e):function(n){var r=Sa(n,t);return r===i&&r===e?Aa(n,t):Fr(e,r,3)}}function Ir(t,e,n,r,o){t!==e&&vr(e,(function(s,a){if(o||(o=new Kn),Qs(s))!function(t,e,n,r,o,s,a){var u=Ao(t,n),c=Ao(e,n),l=a.get(c);if(l)Zn(t,n,l);else{var f=s?s(u,c,n+"",t,e,a):i,d=f===i;if(d){var h=Us(c),p=!h&&Ks(c),g=!h&&!p&&ua(c);f=c,h||p||g?Us(u)?f=u:Vs(u)?f=Ai(u):p?(d=!1,f=bi(c,!0)):g?(d=!1,f=wi(c,!0)):f=[]:ra(c)||Hs(c)?(f=u,Hs(u)?f=va(u):Qs(u)&&!Js(u)||(f=po(c))):d=!1}d&&(a.set(c,f),o(f,c,r,s,a),a.delete(c)),Zn(t,n,f)}}(t,e,a,n,Ir,r,o);else{var u=r?r(Ao(t,a),s,a+"",t,e,o):i;u===i&&(u=s),Zn(t,a,u)}}),ja)}function Br(t,e){var n=t.length;if(n)return vo(e+=e<0?n:0,n)?t[e]:i}function qr(t,e,n){e=e.length?je(e,(function(t){return Us(t)?function(e){return Cr(e,1===t.length?t[0]:t)}:t})):[nu];var r=-1;e=je(e,Ge(oo()));var i=Lr(t,(function(t,n,i){var o=je(e,(function(e){return e(t)}));return{criteria:o,index:++r,value:t}}));return function(t,e){var r=t.length;for(t.sort((function(t,e){return function(t,e,n){for(var r=-1,i=t.criteria,o=e.criteria,s=i.length,a=n.length;++r<s;){var u=ki(i[r],o[r]);if(u)return r>=a?u:u*("desc"==n[r]?-1:1)}return t.index-e.index}(t,e,n)}));r--;)t[r]=t[r].value;return t}(i)}function Hr(t,e,n){for(var r=-1,i=e.length,o={};++r<i;){var s=e[r],a=Cr(t,s);n(a,s)&&Jr(o,vi(s,t),a)}return o}function Ur(t,e,n,r){var i=r?Be:Ie,o=-1,s=e.length,a=t;for(t===e&&(e=Ai(e)),n&&(a=je(t,Ge(n)));++o<s;)for(var u=0,c=e[o],l=n?n(c):c;(u=i(a,l,u,r))>-1;)a!==t&&Kt.call(a,u,1),Kt.call(t,u,1);return t}function Wr(t,e){for(var n=t?e.length:0,r=n-1;n--;){var i=e[n];if(n==r||i!==o){var o=i;vo(i)?Kt.call(t,i,1):ui(t,i)}}return t}function zr(t,e){return t+he(bn()*(e-t+1))}function Vr(t,e){var n="";if(!t||e<1||e>f)return n;do{e%2&&(n+=t),(e=he(e/2))&&(t+=t)}while(e);return n}function Kr(t,e){return To(Eo(t,e,nu),t+"")}function Yr(t){return Gn(Ia(t))}function Gr(t,e){var n=Ia(t);return $o(n,or(e,0,n.length))}function Jr(t,e,n,r){if(!Qs(t))return t;for(var o=-1,s=(e=vi(e,t)).length,a=s-1,u=t;null!=u&&++o<s;){var c=Lo(e[o]),l=n;if("__proto__"===c||"constructor"===c||"prototype"===c)return t;if(o!=a){var f=u[c];(l=r?r(f,c,u):i)===i&&(l=Qs(f)?f:vo(e[o+1])?[]:{})}Qn(u,c,l),u=u[c]}return t}var Xr=On?function(t,e){return On.set(t,e),t}:nu,Zr=te?function(t,e){return te(t,"toString",{configurable:!0,enumerable:!1,value:Qa(e),writable:!0})}:nu;function Qr(t){return $o(Ia(t))}function ti(t,e,n){var i=-1,o=t.length;e<0&&(e=-e>o?0:o+e),(n=n>o?o:n)<0&&(n+=o),o=e>n?0:n-e>>>0,e>>>=0;for(var s=r(o);++i<o;)s[i]=t[i+e];return s}function ei(t,e){var n;return lr(t,(function(t,r,i){return!(n=e(t,r,i))})),!!n}function ni(t,e,n){var r=0,i=null==t?r:t.length;if("number"==typeof e&&e==e&&i<=2147483647){for(;r<i;){var o=r+i>>>1,s=t[o];null!==s&&!aa(s)&&(n?s<=e:s<e)?r=o+1:i=o}return i}return ri(t,e,nu,n)}function ri(t,e,n,r){var o=0,s=null==t?0:t.length;if(0===s)return 0;for(var a=(e=n(e))!=e,u=null===e,c=aa(e),l=e===i;o<s;){var f=he((o+s)/2),d=n(t[f]),h=d!==i,p=null===d,g=d==d,v=aa(d);if(a)var y=r||g;else y=l?g&&(r||h):u?g&&h&&(r||!p):c?g&&h&&!p&&(r||!v):!p&&!v&&(r?d<=e:d<e);y?o=f+1:s=f}return yn(s,4294967294)}function ii(t,e){for(var n=-1,r=t.length,i=0,o=[];++n<r;){var s=t[n],a=e?e(s):s;if(!n||!Is(a,u)){var u=a;o[i++]=0===s?0:s}}return o}function oi(t){return"number"==typeof t?t:aa(t)?d:+t}function si(t){if("string"==typeof t)return t;if(Us(t))return je(t,si)+"";if(aa(t))return Nn?Nn.call(t):"";var e=t+"";return"0"==e&&1/t==-1/0?"-0":e}function ai(t,e,n){var r=-1,i=Te,o=t.length,s=!0,a=[],u=a;if(n)s=!1,i=Fe;else if(o>=200){var c=e?null:Vi(t);if(c)return un(c);s=!1,i=Xe,u=new Vn}else u=e?[]:a;t:for(;++r<o;){var l=t[r],f=e?e(l):l;if(l=n||0!==l?l:0,s&&f==f){for(var d=u.length;d--;)if(u[d]===f)continue t;e&&u.push(f),a.push(l)}else i(u,f,n)||(u!==a&&u.push(f),a.push(l))}return a}function ui(t,e){return null==(t=So(t,e=vi(e,t)))||delete t[Lo(Go(e))]}function ci(t,e,n,r){return Jr(t,e,n(Cr(t,e)),r)}function li(t,e,n,r){for(var i=t.length,o=r?i:-1;(r?o--:++o<i)&&e(t[o],o,t););return n?ti(t,r?0:o,r?o+1:i):ti(t,r?o+1:0,r?i:o)}function fi(t,e){var n=t;return n instanceof Hn&&(n=n.value()),Pe(e,(function(t,e){return e.func.apply(e.thisArg,$e([t],e.args))}),n)}function di(t,e,n){var i=t.length;if(i<2)return i?ai(t[0]):[];for(var o=-1,s=r(i);++o<i;)for(var a=t[o],u=-1;++u<i;)u!=o&&(s[o]=cr(s[o]||a,t[u],e,n));return ai(gr(s,1),e,n)}function hi(t,e,n){for(var r=-1,o=t.length,s=e.length,a={};++r<o;){var u=r<s?e[r]:i;n(a,t[r],u)}return a}function pi(t){return Vs(t)?t:[]}function gi(t){return"function"==typeof t?t:nu}function vi(t,e){return Us(t)?t:mo(t,e)?[t]:Mo(ya(t))}var yi=Kr;function mi(t,e,n){var r=t.length;return n=n===i?r:n,!e&&n>=r?t:ti(t,e,n)}var _i=se||function(t){return fe.clearTimeout(t)};function bi(t,e){if(e)return t.slice();var n=t.length,r=Ut?Ut(n):new t.constructor(n);return t.copy(r),r}function Ci(t){var e=new t.constructor(t.byteLength);return new Ht(e).set(new Ht(t)),e}function wi(t,e){var n=e?Ci(t.buffer):t.buffer;return new t.constructor(n,t.byteOffset,t.length)}function ki(t,e){if(t!==e){var n=t!==i,r=null===t,o=t==t,s=aa(t),a=e!==i,u=null===e,c=e==e,l=aa(e);if(!u&&!l&&!s&&t>e||s&&a&&c&&!u&&!l||r&&a&&c||!n&&c||!o)return 1;if(!r&&!s&&!l&&t<e||l&&n&&o&&!r&&!s||u&&n&&o||!a&&o||!c)return-1}return 0}function Ei(t,e,n,i){for(var o=-1,s=t.length,a=n.length,u=-1,c=e.length,l=vn(s-a,0),f=r(c+l),d=!i;++u<c;)f[u]=e[u];for(;++o<a;)(d||o<s)&&(f[n[o]]=t[o]);for(;l--;)f[u++]=t[o++];return f}function Si(t,e,n,i){for(var o=-1,s=t.length,a=-1,u=n.length,c=-1,l=e.length,f=vn(s-u,0),d=r(f+l),h=!i;++o<f;)d[o]=t[o];for(var p=o;++c<l;)d[p+c]=e[c];for(;++a<u;)(h||o<s)&&(d[p+n[a]]=t[o++]);return d}function Ai(t,e){var n=-1,i=t.length;for(e||(e=r(i));++n<i;)e[n]=t[n];return e}function xi(t,e,n,r){var o=!n;n||(n={});for(var s=-1,a=e.length;++s<a;){var u=e[s],c=r?r(n[u],t[u],u,n,t):i;c===i&&(c=t[u]),o?rr(n,u,c):Qn(n,u,c)}return n}function Oi(t,e){return function(n,r){var i=Us(n)?Ee:er,o=e?e():{};return i(n,t,oo(r,2),o)}}function Ti(t){return Kr((function(e,n){var r=-1,o=n.length,s=o>1?n[o-1]:i,a=o>2?n[2]:i;for(s=t.length>3&&"function"==typeof s?(o--,s):i,a&&yo(n[0],n[1],a)&&(s=o<3?i:s,o=1),e=Et(e);++r<o;){var u=n[r];u&&t(e,u,r,s)}return e}))}function Fi(t,e){return function(n,r){if(null==n)return n;if(!zs(n))return t(n,r);for(var i=n.length,o=e?i:-1,s=Et(n);(e?o--:++o<i)&&!1!==r(s[o],o,s););return n}}function ji(t){return function(e,n,r){for(var i=-1,o=Et(e),s=r(e),a=s.length;a--;){var u=s[t?a:++i];if(!1===n(o[u],u,o))break}return e}}function $i(t){return function(e){var n=rn(e=ya(e))?fn(e):i,r=n?n[0]:e.charAt(0),o=n?mi(n,1).join(""):e.slice(1);return r[t]()+o}}function Pi(t){return function(e){return Pe(Ja(Ha(e).replace(Jt,"")),t,"")}}function Ri(t){return function(){var e=arguments;switch(e.length){case 0:return new t;case 1:return new t(e[0]);case 2:return new t(e[0],e[1]);case 3:return new t(e[0],e[1],e[2]);case 4:return new t(e[0],e[1],e[2],e[3]);case 5:return new t(e[0],e[1],e[2],e[3],e[4]);case 6:return new t(e[0],e[1],e[2],e[3],e[4],e[5]);case 7:return new t(e[0],e[1],e[2],e[3],e[4],e[5],e[6])}var n=In(t.prototype),r=t.apply(n,e);return Qs(r)?r:n}}function Mi(t){return function(e,n,r){var o=Et(e);if(!zs(e)){var s=oo(n,3);e=Fa(e),n=function(t){return s(o[t],t,o)}}var a=t(e,n,r);return a>-1?o[s?e[a]:a]:i}}function Li(t){return Qi((function(e){var n=e.length,r=n,s=qn.prototype.thru;for(t&&e.reverse();r--;){var a=e[r];if("function"!=typeof a)throw new xt(o);if(s&&!u&&"wrapper"==ro(a))var u=new qn([],!0)}for(r=u?r:n;++r<n;){var c=ro(a=e[r]),l="wrapper"==c?no(a):i;u=l&&_o(l[0])&&424==l[1]&&!l[4].length&&1==l[9]?u[ro(l[0])].apply(u,l[3]):1==a.length&&_o(a)?u[c]():u.thru(a)}return function(){var t=arguments,r=t[0];if(u&&1==t.length&&Us(r))return u.plant(r).value();for(var i=0,o=n?e[i].apply(this,t):r;++i<n;)o=e[i].call(this,o);return o}}))}function Ni(t,e,n,o,s,a,u,l,f,d){var h=e&c,p=1&e,g=2&e,v=24&e,y=512&e,m=g?i:Ri(t);return function c(){for(var _=arguments.length,b=r(_),C=_;C--;)b[C]=arguments[C];if(v)var w=io(c),k=function(t,e){for(var n=t.length,r=0;n--;)t[n]===e&&++r;return r}(b,w);if(o&&(b=Ei(b,o,s,v)),a&&(b=Si(b,a,u,v)),_-=k,v&&_<d){var E=an(b,w);return Wi(t,e,Ni,c.placeholder,n,b,E,l,f,d-_)}var S=p?n:this,A=g?S[t]:t;return _=b.length,l?b=function(t,e){for(var n=t.length,r=yn(e.length,n),o=Ai(t);r--;){var s=e[r];t[r]=vo(s,n)?o[s]:i}return t}(b,l):y&&_>1&&b.reverse(),h&&f<_&&(b.length=f),this&&this!==fe&&this instanceof c&&(A=m||Ri(A)),A.apply(S,b)}}function Di(t,e){return function(n,r){return function(t,e,n,r){return mr(t,(function(t,i,o){e(r,n(t),i,o)})),r}(n,t,e(r),{})}}function Ii(t,e){return function(n,r){var o;if(n===i&&r===i)return e;if(n!==i&&(o=n),r!==i){if(o===i)return r;"string"==typeof n||"string"==typeof r?(n=si(n),r=si(r)):(n=oi(n),r=oi(r)),o=t(n,r)}return o}}function Bi(t){return Qi((function(e){return e=je(e,Ge(oo())),Kr((function(n){var r=this;return t(e,(function(t){return ke(t,r,n)}))}))}))}function qi(t,e){var n=(e=e===i?" ":si(e)).length;if(n<2)return n?Vr(e,t):e;var r=Vr(e,de(t/ln(e)));return rn(e)?mi(fn(r),0,t).join(""):r.slice(0,t)}function Hi(t){return function(e,n,o){return o&&"number"!=typeof o&&yo(e,n,o)&&(n=o=i),e=da(e),n===i?(n=e,e=0):n=da(n),function(t,e,n,i){for(var o=-1,s=vn(de((e-t)/(n||1)),0),a=r(s);s--;)a[i?s:++o]=t,t+=n;return a}(e,n,o=o===i?e<n?1:-1:da(o),t)}}function Ui(t){return function(e,n){return"string"==typeof e&&"string"==typeof n||(e=ga(e),n=ga(n)),t(e,n)}}function Wi(t,e,n,r,o,s,a,c,l,f){var d=8&e;e|=d?u:64,4&(e&=~(d?64:u))||(e&=-4);var h=[t,e,o,d?s:i,d?a:i,d?i:s,d?i:a,c,l,f],p=n.apply(i,h);return _o(t)&&xo(p,h),p.placeholder=r,Fo(p,t,e)}function zi(t){var e=kt[t];return function(t,n){if(t=ga(t),(n=null==n?0:yn(ha(n),292))&&Le(t)){var r=(ya(t)+"e").split("e");return+((r=(ya(e(r[0]+"e"+(+r[1]+n)))+"e").split("e"))[0]+"e"+(+r[1]-n))}return e(t)}}var Vi=Sn&&1/un(new Sn([,-0]))[1]==l?function(t){return new Sn(t)}:au;function Ki(t){return function(e){var n=fo(e);return n==w?on(e):n==x?cn(e):function(t,e){return je(e,(function(e){return[e,t[e]]}))}(e,t(e))}}function Yi(t,e,n,s,l,f,d,h){var p=2&e;if(!p&&"function"!=typeof t)throw new xt(o);var g=s?s.length:0;if(g||(e&=-97,s=l=i),d=d===i?d:vn(ha(d),0),h=h===i?h:ha(h),g-=l?l.length:0,64&e){var v=s,y=l;s=l=i}var m=p?i:no(t),_=[t,e,n,s,l,v,y,f,d,h];if(m&&function(t,e){var n=t[1],r=e[1],i=n|r,o=i<131,s=r==c&&8==n||r==c&&256==n&&t[7].length<=e[8]||384==r&&e[7].length<=e[8]&&8==n;if(!o&&!s)return t;1&r&&(t[2]=e[2],i|=1&n?0:4);var u=e[3];if(u){var l=t[3];t[3]=l?Ei(l,u,e[4]):u,t[4]=l?an(t[3],a):e[4]}(u=e[5])&&(l=t[5],t[5]=l?Si(l,u,e[6]):u,t[6]=l?an(t[5],a):e[6]),(u=e[7])&&(t[7]=u),r&c&&(t[8]=null==t[8]?e[8]:yn(t[8],e[8])),null==t[9]&&(t[9]=e[9]),t[0]=e[0],t[1]=i}(_,m),t=_[0],e=_[1],n=_[2],s=_[3],l=_[4],!(h=_[9]=_[9]===i?p?0:t.length:vn(_[9]-g,0))&&24&e&&(e&=-25),e&&1!=e)b=8==e||16==e?function(t,e,n){var o=Ri(t);return function s(){for(var a=arguments.length,u=r(a),c=a,l=io(s);c--;)u[c]=arguments[c];var f=a<3&&u[0]!==l&&u[a-1]!==l?[]:an(u,l);return(a-=f.length)<n?Wi(t,e,Ni,s.placeholder,i,u,f,i,i,n-a):ke(this&&this!==fe&&this instanceof s?o:t,this,u)}}(t,e,h):e!=u&&33!=e||l.length?Ni.apply(i,_):function(t,e,n,i){var o=1&e,s=Ri(t);return function e(){for(var a=-1,u=arguments.length,c=-1,l=i.length,f=r(l+u),d=this&&this!==fe&&this instanceof e?s:t;++c<l;)f[c]=i[c];for(;u--;)f[c++]=arguments[++a];return ke(d,o?n:this,f)}}(t,e,n,s);else var b=function(t,e,n){var r=1&e,i=Ri(t);return function e(){return(this&&this!==fe&&this instanceof e?i:t).apply(r?n:this,arguments)}}(t,e,n);return Fo((m?Xr:xo)(b,_),t,e)}function Gi(t,e,n,r){return t===i||Is(t,Ft[n])&&!Pt.call(r,n)?e:t}function Ji(t,e,n,r,o,s){return Qs(t)&&Qs(e)&&(s.set(e,t),Ir(t,e,i,Ji,s),s.delete(e)),t}function Xi(t){return ra(t)?i:t}function Zi(t,e,n,r,o,s){var a=1&n,u=t.length,c=e.length;if(u!=c&&!(a&&c>u))return!1;var l=s.get(t),f=s.get(e);if(l&&f)return l==e&&f==t;var d=-1,h=!0,p=2&n?new Vn:i;for(s.set(t,e),s.set(e,t);++d<u;){var g=t[d],v=e[d];if(r)var y=a?r(v,g,d,e,t,s):r(g,v,d,t,e,s);if(y!==i){if(y)continue;h=!1;break}if(p){if(!Me(e,(function(t,e){if(!Xe(p,e)&&(g===t||o(g,t,n,r,s)))return p.push(e)}))){h=!1;break}}else if(g!==v&&!o(g,v,n,r,s)){h=!1;break}}return s.delete(t),s.delete(e),h}function Qi(t){return To(Eo(t,i,Wo),t+"")}function to(t){return wr(t,Fa,co)}function eo(t){return wr(t,ja,lo)}var no=On?function(t){return On.get(t)}:au;function ro(t){for(var e=t.name+"",n=Tn[e],r=Pt.call(Tn,e)?n.length:0;r--;){var i=n[r],o=i.func;if(null==o||o==t)return i.name}return e}function io(t){return(Pt.call(Dn,"placeholder")?Dn:t).placeholder}function oo(){var t=Dn.iteratee||ru;return t=t===ru?Pr:t,arguments.length?t(arguments[0],arguments[1]):t}function so(t,e){var n,r,i=t.__data__;return("string"==(r=typeof(n=e))||"number"==r||"symbol"==r||"boolean"==r?"__proto__"!==n:null===n)?i["string"==typeof e?"string":"hash"]:i.map}function ao(t){for(var e=Fa(t),n=e.length;n--;){var r=e[n],i=t[r];e[n]=[r,i,wo(i)]}return e}function uo(t,e){var n=function(t,e){return null==t?i:t[e]}(t,e);return $r(n)?n:i}var co=ge?function(t){return null==t?[]:(t=Et(t),Oe(ge(t),(function(e){return Vt.call(t,e)})))}:pu,lo=ge?function(t){for(var e=[];t;)$e(e,co(t)),t=Wt(t);return e}:pu,fo=kr;function ho(t,e,n){for(var r=-1,i=(e=vi(e,t)).length,o=!1;++r<i;){var s=Lo(e[r]);if(!(o=null!=t&&n(t,s)))break;t=t[s]}return o||++r!=i?o:!!(i=null==t?0:t.length)&&Zs(i)&&vo(s,i)&&(Us(t)||Hs(t))}function po(t){return"function"!=typeof t.constructor||Co(t)?{}:In(Wt(t))}function go(t){return Us(t)||Hs(t)||!!(Yt&&t&&t[Yt])}function vo(t,e){var n=typeof t;return!!(e=null==e?f:e)&&("number"==n||"symbol"!=n&&yt.test(t))&&t>-1&&t%1==0&&t<e}function yo(t,e,n){if(!Qs(n))return!1;var r=typeof e;return!!("number"==r?zs(n)&&vo(e,n.length):"string"==r&&e in n)&&Is(n[e],t)}function mo(t,e){if(Us(t))return!1;var n=typeof t;return!("number"!=n&&"symbol"!=n&&"boolean"!=n&&null!=t&&!aa(t))||Q.test(t)||!Z.test(t)||null!=e&&t in Et(e)}function _o(t){var e=ro(t),n=Dn[e];if("function"!=typeof n||!(e in Hn.prototype))return!1;if(t===n)return!0;var r=no(n);return!!r&&t===r[0]}(wn&&fo(new wn(new ArrayBuffer(1)))!=$||kn&&fo(new kn)!=w||En&&fo(En.resolve())!=S||Sn&&fo(new Sn)!=x||An&&fo(new An)!=F)&&(fo=function(t){var e=kr(t),n=e==E?t.constructor:i,r=n?No(n):"";if(r)switch(r){case Fn:return $;case jn:return w;case $n:return S;case Pn:return x;case Rn:return F}return e});var bo=jt?Js:gu;function Co(t){var e=t&&t.constructor;return t===("function"==typeof e&&e.prototype||Ft)}function wo(t){return t==t&&!Qs(t)}function ko(t,e){return function(n){return null!=n&&n[t]===e&&(e!==i||t in Et(n))}}function Eo(t,e,n){return e=vn(e===i?t.length-1:e,0),function(){for(var i=arguments,o=-1,s=vn(i.length-e,0),a=r(s);++o<s;)a[o]=i[e+o];o=-1;for(var u=r(e+1);++o<e;)u[o]=i[o];return u[e]=n(a),ke(t,this,u)}}function So(t,e){return e.length<2?t:Cr(t,ti(e,0,-1))}function Ao(t,e){if(("constructor"!==e||"function"!=typeof t[e])&&"__proto__"!=e)return t[e]}var xo=jo(Xr),Oo=le||function(t,e){return fe.setTimeout(t,e)},To=jo(Zr);function Fo(t,e,n){var r=e+"";return To(t,function(t,e){var n=e.length;if(!n)return t;var r=n-1;return e[r]=(n>1?"& ":"")+e[r],e=e.join(n>2?", ":" "),t.replace(ot,"{\n/* [wrapped with "+e+"] */\n")}(r,function(t,e){return Se(p,(function(n){var r="_."+n[0];e&n[1]&&!Te(t,r)&&t.push(r)})),t.sort()}(function(t){var e=t.match(st);return e?e[1].split(at):[]}(r),n)))}function jo(t){var e=0,n=0;return function(){var r=mn(),o=16-(r-n);if(n=r,o>0){if(++e>=800)return arguments[0]}else e=0;return t.apply(i,arguments)}}function $o(t,e){var n=-1,r=t.length,o=r-1;for(e=e===i?r:e;++n<e;){var s=zr(n,o),a=t[s];t[s]=t[n],t[n]=a}return t.length=e,t}var Po,Ro,Mo=(Po=Ps((function(t){var e=[];return 46===t.charCodeAt(0)&&e.push(""),t.replace(tt,(function(t,n,r,i){e.push(r?i.replace(lt,"$1"):n||t)})),e}),(function(t){return 500===Ro.size&&Ro.clear(),t})),Ro=Po.cache,Po);function Lo(t){if("string"==typeof t||aa(t))return t;var e=t+"";return"0"==e&&1/t==-1/0?"-0":e}function No(t){if(null!=t){try{return $t.call(t)}catch(t){}try{return t+""}catch(t){}}return""}function Do(t){if(t instanceof Hn)return t.clone();var e=new qn(t.__wrapped__,t.__chain__);return e.__actions__=Ai(t.__actions__),e.__index__=t.__index__,e.__values__=t.__values__,e}var Io=Kr((function(t,e){return Vs(t)?cr(t,gr(e,1,Vs,!0)):[]})),Bo=Kr((function(t,e){var n=Go(e);return Vs(n)&&(n=i),Vs(t)?cr(t,gr(e,1,Vs,!0),oo(n,2)):[]})),qo=Kr((function(t,e){var n=Go(e);return Vs(n)&&(n=i),Vs(t)?cr(t,gr(e,1,Vs,!0),i,n):[]}));function Ho(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var i=null==n?0:ha(n);return i<0&&(i=vn(r+i,0)),De(t,oo(e,3),i)}function Uo(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var o=r-1;return n!==i&&(o=ha(n),o=n<0?vn(r+o,0):yn(o,r-1)),De(t,oo(e,3),o,!0)}function Wo(t){return null!=t&&t.length?gr(t,1):[]}function zo(t){return t&&t.length?t[0]:i}var Vo=Kr((function(t){var e=je(t,pi);return e.length&&e[0]===t[0]?xr(e):[]})),Ko=Kr((function(t){var e=Go(t),n=je(t,pi);return e===Go(n)?e=i:n.pop(),n.length&&n[0]===t[0]?xr(n,oo(e,2)):[]})),Yo=Kr((function(t){var e=Go(t),n=je(t,pi);return(e="function"==typeof e?e:i)&&n.pop(),n.length&&n[0]===t[0]?xr(n,i,e):[]}));function Go(t){var e=null==t?0:t.length;return e?t[e-1]:i}var Jo=Kr(Xo);function Xo(t,e){return t&&t.length&&e&&e.length?Ur(t,e):t}var Zo=Qi((function(t,e){var n=null==t?0:t.length,r=ir(t,e);return Wr(t,je(e,(function(t){return vo(t,n)?+t:t})).sort(ki)),r}));function Qo(t){return null==t?t:Cn.call(t)}var ts=Kr((function(t){return ai(gr(t,1,Vs,!0))})),es=Kr((function(t){var e=Go(t);return Vs(e)&&(e=i),ai(gr(t,1,Vs,!0),oo(e,2))})),ns=Kr((function(t){var e=Go(t);return e="function"==typeof e?e:i,ai(gr(t,1,Vs,!0),i,e)}));function rs(t){if(!t||!t.length)return[];var e=0;return t=Oe(t,(function(t){if(Vs(t))return e=vn(t.length,e),!0})),Ke(e,(function(e){return je(t,Ue(e))}))}function is(t,e){if(!t||!t.length)return[];var n=rs(t);return null==e?n:je(n,(function(t){return ke(e,i,t)}))}var os=Kr((function(t,e){return Vs(t)?cr(t,e):[]})),ss=Kr((function(t){return di(Oe(t,Vs))})),as=Kr((function(t){var e=Go(t);return Vs(e)&&(e=i),di(Oe(t,Vs),oo(e,2))})),us=Kr((function(t){var e=Go(t);return e="function"==typeof e?e:i,di(Oe(t,Vs),i,e)})),cs=Kr(rs),ls=Kr((function(t){var e=t.length,n=e>1?t[e-1]:i;return n="function"==typeof n?(t.pop(),n):i,is(t,n)}));function fs(t){var e=Dn(t);return e.__chain__=!0,e}function ds(t,e){return e(t)}var hs=Qi((function(t){var e=t.length,n=e?t[0]:0,r=this.__wrapped__,o=function(e){return ir(e,t)};return!(e>1||this.__actions__.length)&&r instanceof Hn&&vo(n)?((r=r.slice(n,+n+(e?1:0))).__actions__.push({func:ds,args:[o],thisArg:i}),new qn(r,this.__chain__).thru((function(t){return e&&!t.length&&t.push(i),t}))):this.thru(o)})),ps=Oi((function(t,e,n){Pt.call(t,n)?++t[n]:rr(t,n,1)})),gs=Mi(Ho),vs=Mi(Uo);function ys(t,e){return(Us(t)?Se:lr)(t,oo(e,3))}function ms(t,e){return(Us(t)?Ae:fr)(t,oo(e,3))}var _s=Oi((function(t,e,n){Pt.call(t,n)?t[n].push(e):rr(t,n,[e])})),bs=Kr((function(t,e,n){var i=-1,o="function"==typeof e,s=zs(t)?r(t.length):[];return lr(t,(function(t){s[++i]=o?ke(e,t,n):Or(t,e,n)})),s})),Cs=Oi((function(t,e,n){rr(t,n,e)}));function ws(t,e){return(Us(t)?je:Lr)(t,oo(e,3))}var ks=Oi((function(t,e,n){t[n?0:1].push(e)}),(function(){return[[],[]]})),Es=Kr((function(t,e){if(null==t)return[];var n=e.length;return n>1&&yo(t,e[0],e[1])?e=[]:n>2&&yo(e[0],e[1],e[2])&&(e=[e[0]]),qr(t,gr(e,1),[])})),Ss=ce||function(){return fe.Date.now()};function As(t,e,n){return e=n?i:e,e=t&&null==e?t.length:e,Yi(t,c,i,i,i,i,e)}function xs(t,e){var n;if("function"!=typeof e)throw new xt(o);return t=ha(t),function(){return--t>0&&(n=e.apply(this,arguments)),t<=1&&(e=i),n}}var Os=Kr((function(t,e,n){var r=1;if(n.length){var i=an(n,io(Os));r|=u}return Yi(t,r,e,n,i)})),Ts=Kr((function(t,e,n){var r=3;if(n.length){var i=an(n,io(Ts));r|=u}return Yi(e,r,t,n,i)}));function Fs(t,e,n){var r,s,a,u,c,l,f=0,d=!1,h=!1,p=!0;if("function"!=typeof t)throw new xt(o);function g(e){var n=r,o=s;return r=s=i,f=e,u=t.apply(o,n)}function v(t){var n=t-l;return l===i||n>=e||n<0||h&&t-f>=a}function y(){var t=Ss();if(v(t))return m(t);c=Oo(y,function(t){var n=e-(t-l);return h?yn(n,a-(t-f)):n}(t))}function m(t){return c=i,p&&r?g(t):(r=s=i,u)}function _(){var t=Ss(),n=v(t);if(r=arguments,s=this,l=t,n){if(c===i)return function(t){return f=t,c=Oo(y,e),d?g(t):u}(l);if(h)return _i(c),c=Oo(y,e),g(l)}return c===i&&(c=Oo(y,e)),u}return e=ga(e)||0,Qs(n)&&(d=!!n.leading,a=(h="maxWait"in n)?vn(ga(n.maxWait)||0,e):a,p="trailing"in n?!!n.trailing:p),_.cancel=function(){c!==i&&_i(c),f=0,r=l=s=c=i},_.flush=function(){return c===i?u:m(Ss())},_}var js=Kr((function(t,e){return ur(t,1,e)})),$s=Kr((function(t,e,n){return ur(t,ga(e)||0,n)}));function Ps(t,e){if("function"!=typeof t||null!=e&&"function"!=typeof e)throw new xt(o);var n=function(){var r=arguments,i=e?e.apply(this,r):r[0],o=n.cache;if(o.has(i))return o.get(i);var s=t.apply(this,r);return n.cache=o.set(i,s)||o,s};return n.cache=new(Ps.Cache||zn),n}function Rs(t){if("function"!=typeof t)throw new xt(o);return function(){var e=arguments;switch(e.length){case 0:return!t.call(this);case 1:return!t.call(this,e[0]);case 2:return!t.call(this,e[0],e[1]);case 3:return!t.call(this,e[0],e[1],e[2])}return!t.apply(this,e)}}Ps.Cache=zn;var Ms=yi((function(t,e){var n=(e=1==e.length&&Us(e[0])?je(e[0],Ge(oo())):je(gr(e,1),Ge(oo()))).length;return Kr((function(r){for(var i=-1,o=yn(r.length,n);++i<o;)r[i]=e[i].call(this,r[i]);return ke(t,this,r)}))})),Ls=Kr((function(t,e){var n=an(e,io(Ls));return Yi(t,u,i,e,n)})),Ns=Kr((function(t,e){var n=an(e,io(Ns));return Yi(t,64,i,e,n)})),Ds=Qi((function(t,e){return Yi(t,256,i,i,i,e)}));function Is(t,e){return t===e||t!=t&&e!=e}var Bs=Ui(Er),qs=Ui((function(t,e){return t>=e})),Hs=Tr(function(){return arguments}())?Tr:function(t){return ta(t)&&Pt.call(t,"callee")&&!Vt.call(t,"callee")},Us=r.isArray,Ws=ye?Ge(ye):function(t){return ta(t)&&kr(t)==j};function zs(t){return null!=t&&Zs(t.length)&&!Js(t)}function Vs(t){return ta(t)&&zs(t)}var Ks=ve||gu,Ys=me?Ge(me):function(t){return ta(t)&&kr(t)==m};function Gs(t){if(!ta(t))return!1;var e=kr(t);return e==_||"[object DOMException]"==e||"string"==typeof t.message&&"string"==typeof t.name&&!ra(t)}function Js(t){if(!Qs(t))return!1;var e=kr(t);return e==b||e==C||"[object AsyncFunction]"==e||"[object Proxy]"==e}function Xs(t){return"number"==typeof t&&t==ha(t)}function Zs(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=f}function Qs(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}function ta(t){return null!=t&&"object"==typeof t}var ea=_e?Ge(_e):function(t){return ta(t)&&fo(t)==w};function na(t){return"number"==typeof t||ta(t)&&kr(t)==k}function ra(t){if(!ta(t)||kr(t)!=E)return!1;var e=Wt(t);if(null===e)return!0;var n=Pt.call(e,"constructor")&&e.constructor;return"function"==typeof n&&n instanceof n&&$t.call(n)==Nt}var ia=be?Ge(be):function(t){return ta(t)&&kr(t)==A},oa=Ce?Ge(Ce):function(t){return ta(t)&&fo(t)==x};function sa(t){return"string"==typeof t||!Us(t)&&ta(t)&&kr(t)==O}function aa(t){return"symbol"==typeof t||ta(t)&&kr(t)==T}var ua=we?Ge(we):function(t){return ta(t)&&Zs(t.length)&&!!ie[kr(t)]},ca=Ui(Mr),la=Ui((function(t,e){return t<=e}));function fa(t){if(!t)return[];if(zs(t))return sa(t)?fn(t):Ai(t);if(Gt&&t[Gt])return function(t){for(var e,n=[];!(e=t.next()).done;)n.push(e.value);return n}(t[Gt]());var e=fo(t);return(e==w?on:e==x?un:Ia)(t)}function da(t){return t?(t=ga(t))===l||t===-1/0?17976931348623157e292*(t<0?-1:1):t==t?t:0:0===t?t:0}function ha(t){var e=da(t),n=e%1;return e==e?n?e-n:e:0}function pa(t){return t?or(ha(t),0,h):0}function ga(t){if("number"==typeof t)return t;if(aa(t))return d;if(Qs(t)){var e="function"==typeof t.valueOf?t.valueOf():t;t=Qs(e)?e+"":e}if("string"!=typeof t)return 0===t?t:+t;t=Ye(t);var n=pt.test(t);return n||vt.test(t)?ue(t.slice(2),n?2:8):ht.test(t)?d:+t}function va(t){return xi(t,ja(t))}function ya(t){return null==t?"":si(t)}var ma=Ti((function(t,e){if(Co(e)||zs(e))xi(e,Fa(e),t);else for(var n in e)Pt.call(e,n)&&Qn(t,n,e[n])})),_a=Ti((function(t,e){xi(e,ja(e),t)})),ba=Ti((function(t,e,n,r){xi(e,ja(e),t,r)})),Ca=Ti((function(t,e,n,r){xi(e,Fa(e),t,r)})),wa=Qi(ir),ka=Kr((function(t,e){t=Et(t);var n=-1,r=e.length,o=r>2?e[2]:i;for(o&&yo(e[0],e[1],o)&&(r=1);++n<r;)for(var s=e[n],a=ja(s),u=-1,c=a.length;++u<c;){var l=a[u],f=t[l];(f===i||Is(f,Ft[l])&&!Pt.call(t,l))&&(t[l]=s[l])}return t})),Ea=Kr((function(t){return t.push(i,Ji),ke(Pa,i,t)}));function Sa(t,e,n){var r=null==t?i:Cr(t,e);return r===i?n:r}function Aa(t,e){return null!=t&&ho(t,e,Ar)}var xa=Di((function(t,e,n){null!=e&&"function"!=typeof e.toString&&(e=Lt.call(e)),t[e]=n}),Qa(nu)),Oa=Di((function(t,e,n){null!=e&&"function"!=typeof e.toString&&(e=Lt.call(e)),Pt.call(t,e)?t[e].push(n):t[e]=[n]}),oo),Ta=Kr(Or);function Fa(t){return zs(t)?Yn(t):Rr(t)}function ja(t){return zs(t)?Yn(t,!0):function(t){if(!Qs(t))return function(t){var e=[];if(null!=t)for(var n in Et(t))e.push(n);return e}(t);var e=Co(t),n=[];for(var r in t)("constructor"!=r||!e&&Pt.call(t,r))&&n.push(r);return n}(t)}var $a=Ti((function(t,e,n){Ir(t,e,n)})),Pa=Ti((function(t,e,n,r){Ir(t,e,n,r)})),Ra=Qi((function(t,e){var n={};if(null==t)return n;var r=!1;e=je(e,(function(e){return e=vi(e,t),r||(r=e.length>1),e})),xi(t,eo(t),n),r&&(n=sr(n,7,Xi));for(var i=e.length;i--;)ui(n,e[i]);return n})),Ma=Qi((function(t,e){return null==t?{}:function(t,e){return Hr(t,e,(function(e,n){return Aa(t,n)}))}(t,e)}));function La(t,e){if(null==t)return{};var n=je(eo(t),(function(t){return[t]}));return e=oo(e),Hr(t,n,(function(t,n){return e(t,n[0])}))}var Na=Ki(Fa),Da=Ki(ja);function Ia(t){return null==t?[]:Je(t,Fa(t))}var Ba=Pi((function(t,e,n){return e=e.toLowerCase(),t+(n?qa(e):e)}));function qa(t){return Ga(ya(t).toLowerCase())}function Ha(t){return(t=ya(t))&&t.replace(mt,tn).replace(Xt,"")}var Ua=Pi((function(t,e,n){return t+(n?"-":"")+e.toLowerCase()})),Wa=Pi((function(t,e,n){return t+(n?" ":"")+e.toLowerCase()})),za=$i("toLowerCase"),Va=Pi((function(t,e,n){return t+(n?"_":"")+e.toLowerCase()})),Ka=Pi((function(t,e,n){return t+(n?" ":"")+Ga(e)})),Ya=Pi((function(t,e,n){return t+(n?" ":"")+e.toUpperCase()})),Ga=$i("toUpperCase");function Ja(t,e,n){return t=ya(t),(e=n?i:e)===i?function(t){return ee.test(t)}(t)?function(t){return t.match(Qt)||[]}(t):function(t){return t.match(ut)||[]}(t):t.match(e)||[]}var Xa=Kr((function(t,e){try{return ke(t,i,e)}catch(t){return Gs(t)?t:new Ct(t)}})),Za=Qi((function(t,e){return Se(e,(function(e){e=Lo(e),rr(t,e,Os(t[e],t))})),t}));function Qa(t){return function(){return t}}var tu=Li(),eu=Li(!0);function nu(t){return t}function ru(t){return Pr("function"==typeof t?t:sr(t,1))}var iu=Kr((function(t,e){return function(n){return Or(n,t,e)}})),ou=Kr((function(t,e){return function(n){return Or(t,n,e)}}));function su(t,e,n){var r=Fa(e),i=br(e,r);null!=n||Qs(e)&&(i.length||!r.length)||(n=e,e=t,t=this,i=br(e,Fa(e)));var o=!(Qs(n)&&"chain"in n&&!n.chain),s=Js(t);return Se(i,(function(n){var r=e[n];t[n]=r,s&&(t.prototype[n]=function(){var e=this.__chain__;if(o||e){var n=t(this.__wrapped__);return(n.__actions__=Ai(this.__actions__)).push({func:r,args:arguments,thisArg:t}),n.__chain__=e,n}return r.apply(t,$e([this.value()],arguments))})})),t}function au(){}var uu=Bi(je),cu=Bi(xe),lu=Bi(Me);function fu(t){return mo(t)?Ue(Lo(t)):function(t){return function(e){return Cr(e,t)}}(t)}var du=Hi(),hu=Hi(!0);function pu(){return[]}function gu(){return!1}var vu,yu=Ii((function(t,e){return t+e}),0),mu=zi("ceil"),_u=Ii((function(t,e){return t/e}),1),bu=zi("floor"),Cu=Ii((function(t,e){return t*e}),1),wu=zi("round"),ku=Ii((function(t,e){return t-e}),0);return Dn.after=function(t,e){if("function"!=typeof e)throw new xt(o);return t=ha(t),function(){if(--t<1)return e.apply(this,arguments)}},Dn.ary=As,Dn.assign=ma,Dn.assignIn=_a,Dn.assignInWith=ba,Dn.assignWith=Ca,Dn.at=wa,Dn.before=xs,Dn.bind=Os,Dn.bindAll=Za,Dn.bindKey=Ts,Dn.castArray=function(){if(!arguments.length)return[];var t=arguments[0];return Us(t)?t:[t]},Dn.chain=fs,Dn.chunk=function(t,e,n){e=(n?yo(t,e,n):e===i)?1:vn(ha(e),0);var o=null==t?0:t.length;if(!o||e<1)return[];for(var s=0,a=0,u=r(de(o/e));s<o;)u[a++]=ti(t,s,s+=e);return u},Dn.compact=function(t){for(var e=-1,n=null==t?0:t.length,r=0,i=[];++e<n;){var o=t[e];o&&(i[r++]=o)}return i},Dn.concat=function(){var t=arguments.length;if(!t)return[];for(var e=r(t-1),n=arguments[0],i=t;i--;)e[i-1]=arguments[i];return $e(Us(n)?Ai(n):[n],gr(e,1))},Dn.cond=function(t){var e=null==t?0:t.length,n=oo();return t=e?je(t,(function(t){if("function"!=typeof t[1])throw new xt(o);return[n(t[0]),t[1]]})):[],Kr((function(n){for(var r=-1;++r<e;){var i=t[r];if(ke(i[0],this,n))return ke(i[1],this,n)}}))},Dn.conforms=function(t){return function(t){var e=Fa(t);return function(n){return ar(n,t,e)}}(sr(t,1))},Dn.constant=Qa,Dn.countBy=ps,Dn.create=function(t,e){var n=In(t);return null==e?n:nr(n,e)},Dn.curry=function t(e,n,r){var o=Yi(e,8,i,i,i,i,i,n=r?i:n);return o.placeholder=t.placeholder,o},Dn.curryRight=function t(e,n,r){var o=Yi(e,16,i,i,i,i,i,n=r?i:n);return o.placeholder=t.placeholder,o},Dn.debounce=Fs,Dn.defaults=ka,Dn.defaultsDeep=Ea,Dn.defer=js,Dn.delay=$s,Dn.difference=Io,Dn.differenceBy=Bo,Dn.differenceWith=qo,Dn.drop=function(t,e,n){var r=null==t?0:t.length;return r?ti(t,(e=n||e===i?1:ha(e))<0?0:e,r):[]},Dn.dropRight=function(t,e,n){var r=null==t?0:t.length;return r?ti(t,0,(e=r-(e=n||e===i?1:ha(e)))<0?0:e):[]},Dn.dropRightWhile=function(t,e){return t&&t.length?li(t,oo(e,3),!0,!0):[]},Dn.dropWhile=function(t,e){return t&&t.length?li(t,oo(e,3),!0):[]},Dn.fill=function(t,e,n,r){var o=null==t?0:t.length;return o?(n&&"number"!=typeof n&&yo(t,e,n)&&(n=0,r=o),function(t,e,n,r){var o=t.length;for((n=ha(n))<0&&(n=-n>o?0:o+n),(r=r===i||r>o?o:ha(r))<0&&(r+=o),r=n>r?0:pa(r);n<r;)t[n++]=e;return t}(t,e,n,r)):[]},Dn.filter=function(t,e){return(Us(t)?Oe:pr)(t,oo(e,3))},Dn.flatMap=function(t,e){return gr(ws(t,e),1)},Dn.flatMapDeep=function(t,e){return gr(ws(t,e),l)},Dn.flatMapDepth=function(t,e,n){return n=n===i?1:ha(n),gr(ws(t,e),n)},Dn.flatten=Wo,Dn.flattenDeep=function(t){return null!=t&&t.length?gr(t,l):[]},Dn.flattenDepth=function(t,e){return null!=t&&t.length?gr(t,e=e===i?1:ha(e)):[]},Dn.flip=function(t){return Yi(t,512)},Dn.flow=tu,Dn.flowRight=eu,Dn.fromPairs=function(t){for(var e=-1,n=null==t?0:t.length,r={};++e<n;){var i=t[e];r[i[0]]=i[1]}return r},Dn.functions=function(t){return null==t?[]:br(t,Fa(t))},Dn.functionsIn=function(t){return null==t?[]:br(t,ja(t))},Dn.groupBy=_s,Dn.initial=function(t){return null!=t&&t.length?ti(t,0,-1):[]},Dn.intersection=Vo,Dn.intersectionBy=Ko,Dn.intersectionWith=Yo,Dn.invert=xa,Dn.invertBy=Oa,Dn.invokeMap=bs,Dn.iteratee=ru,Dn.keyBy=Cs,Dn.keys=Fa,Dn.keysIn=ja,Dn.map=ws,Dn.mapKeys=function(t,e){var n={};return e=oo(e,3),mr(t,(function(t,r,i){rr(n,e(t,r,i),t)})),n},Dn.mapValues=function(t,e){var n={};return e=oo(e,3),mr(t,(function(t,r,i){rr(n,r,e(t,r,i))})),n},Dn.matches=function(t){return Nr(sr(t,1))},Dn.matchesProperty=function(t,e){return Dr(t,sr(e,1))},Dn.memoize=Ps,Dn.merge=$a,Dn.mergeWith=Pa,Dn.method=iu,Dn.methodOf=ou,Dn.mixin=su,Dn.negate=Rs,Dn.nthArg=function(t){return t=ha(t),Kr((function(e){return Br(e,t)}))},Dn.omit=Ra,Dn.omitBy=function(t,e){return La(t,Rs(oo(e)))},Dn.once=function(t){return xs(2,t)},Dn.orderBy=function(t,e,n,r){return null==t?[]:(Us(e)||(e=null==e?[]:[e]),Us(n=r?i:n)||(n=null==n?[]:[n]),qr(t,e,n))},Dn.over=uu,Dn.overArgs=Ms,Dn.overEvery=cu,Dn.overSome=lu,Dn.partial=Ls,Dn.partialRight=Ns,Dn.partition=ks,Dn.pick=Ma,Dn.pickBy=La,Dn.property=fu,Dn.propertyOf=function(t){return function(e){return null==t?i:Cr(t,e)}},Dn.pull=Jo,Dn.pullAll=Xo,Dn.pullAllBy=function(t,e,n){return t&&t.length&&e&&e.length?Ur(t,e,oo(n,2)):t},Dn.pullAllWith=function(t,e,n){return t&&t.length&&e&&e.length?Ur(t,e,i,n):t},Dn.pullAt=Zo,Dn.range=du,Dn.rangeRight=hu,Dn.rearg=Ds,Dn.reject=function(t,e){return(Us(t)?Oe:pr)(t,Rs(oo(e,3)))},Dn.remove=function(t,e){var n=[];if(!t||!t.length)return n;var r=-1,i=[],o=t.length;for(e=oo(e,3);++r<o;){var s=t[r];e(s,r,t)&&(n.push(s),i.push(r))}return Wr(t,i),n},Dn.rest=function(t,e){if("function"!=typeof t)throw new xt(o);return Kr(t,e=e===i?e:ha(e))},Dn.reverse=Qo,Dn.sampleSize=function(t,e,n){return e=(n?yo(t,e,n):e===i)?1:ha(e),(Us(t)?Jn:Gr)(t,e)},Dn.set=function(t,e,n){return null==t?t:Jr(t,e,n)},Dn.setWith=function(t,e,n,r){return r="function"==typeof r?r:i,null==t?t:Jr(t,e,n,r)},Dn.shuffle=function(t){return(Us(t)?Xn:Qr)(t)},Dn.slice=function(t,e,n){var r=null==t?0:t.length;return r?(n&&"number"!=typeof n&&yo(t,e,n)?(e=0,n=r):(e=null==e?0:ha(e),n=n===i?r:ha(n)),ti(t,e,n)):[]},Dn.sortBy=Es,Dn.sortedUniq=function(t){return t&&t.length?ii(t):[]},Dn.sortedUniqBy=function(t,e){return t&&t.length?ii(t,oo(e,2)):[]},Dn.split=function(t,e,n){return n&&"number"!=typeof n&&yo(t,e,n)&&(e=n=i),(n=n===i?h:n>>>0)?(t=ya(t))&&("string"==typeof e||null!=e&&!ia(e))&&!(e=si(e))&&rn(t)?mi(fn(t),0,n):t.split(e,n):[]},Dn.spread=function(t,e){if("function"!=typeof t)throw new xt(o);return e=null==e?0:vn(ha(e),0),Kr((function(n){var r=n[e],i=mi(n,0,e);return r&&$e(i,r),ke(t,this,i)}))},Dn.tail=function(t){var e=null==t?0:t.length;return e?ti(t,1,e):[]},Dn.take=function(t,e,n){return t&&t.length?ti(t,0,(e=n||e===i?1:ha(e))<0?0:e):[]},Dn.takeRight=function(t,e,n){var r=null==t?0:t.length;return r?ti(t,(e=r-(e=n||e===i?1:ha(e)))<0?0:e,r):[]},Dn.takeRightWhile=function(t,e){return t&&t.length?li(t,oo(e,3),!1,!0):[]},Dn.takeWhile=function(t,e){return t&&t.length?li(t,oo(e,3)):[]},Dn.tap=function(t,e){return e(t),t},Dn.throttle=function(t,e,n){var r=!0,i=!0;if("function"!=typeof t)throw new xt(o);return Qs(n)&&(r="leading"in n?!!n.leading:r,i="trailing"in n?!!n.trailing:i),Fs(t,e,{leading:r,maxWait:e,trailing:i})},Dn.thru=ds,Dn.toArray=fa,Dn.toPairs=Na,Dn.toPairsIn=Da,Dn.toPath=function(t){return Us(t)?je(t,Lo):aa(t)?[t]:Ai(Mo(ya(t)))},Dn.toPlainObject=va,Dn.transform=function(t,e,n){var r=Us(t),i=r||Ks(t)||ua(t);if(e=oo(e,4),null==n){var o=t&&t.constructor;n=i?r?new o:[]:Qs(t)&&Js(o)?In(Wt(t)):{}}return(i?Se:mr)(t,(function(t,r,i){return e(n,t,r,i)})),n},Dn.unary=function(t){return As(t,1)},Dn.union=ts,Dn.unionBy=es,Dn.unionWith=ns,Dn.uniq=function(t){return t&&t.length?ai(t):[]},Dn.uniqBy=function(t,e){return t&&t.length?ai(t,oo(e,2)):[]},Dn.uniqWith=function(t,e){return e="function"==typeof e?e:i,t&&t.length?ai(t,i,e):[]},Dn.unset=function(t,e){return null==t||ui(t,e)},Dn.unzip=rs,Dn.unzipWith=is,Dn.update=function(t,e,n){return null==t?t:ci(t,e,gi(n))},Dn.updateWith=function(t,e,n,r){return r="function"==typeof r?r:i,null==t?t:ci(t,e,gi(n),r)},Dn.values=Ia,Dn.valuesIn=function(t){return null==t?[]:Je(t,ja(t))},Dn.without=os,Dn.words=Ja,Dn.wrap=function(t,e){return Ls(gi(e),t)},Dn.xor=ss,Dn.xorBy=as,Dn.xorWith=us,Dn.zip=cs,Dn.zipObject=function(t,e){return hi(t||[],e||[],Qn)},Dn.zipObjectDeep=function(t,e){return hi(t||[],e||[],Jr)},Dn.zipWith=ls,Dn.entries=Na,Dn.entriesIn=Da,Dn.extend=_a,Dn.extendWith=ba,su(Dn,Dn),Dn.add=yu,Dn.attempt=Xa,Dn.camelCase=Ba,Dn.capitalize=qa,Dn.ceil=mu,Dn.clamp=function(t,e,n){return n===i&&(n=e,e=i),n!==i&&(n=(n=ga(n))==n?n:0),e!==i&&(e=(e=ga(e))==e?e:0),or(ga(t),e,n)},Dn.clone=function(t){return sr(t,4)},Dn.cloneDeep=function(t){return sr(t,5)},Dn.cloneDeepWith=function(t,e){return sr(t,5,e="function"==typeof e?e:i)},Dn.cloneWith=function(t,e){return sr(t,4,e="function"==typeof e?e:i)},Dn.conformsTo=function(t,e){return null==e||ar(t,e,Fa(e))},Dn.deburr=Ha,Dn.defaultTo=function(t,e){return null==t||t!=t?e:t},Dn.divide=_u,Dn.endsWith=function(t,e,n){t=ya(t),e=si(e);var r=t.length,o=n=n===i?r:or(ha(n),0,r);return(n-=e.length)>=0&&t.slice(n,o)==e},Dn.eq=Is,Dn.escape=function(t){return(t=ya(t))&&Y.test(t)?t.replace(V,en):t},Dn.escapeRegExp=function(t){return(t=ya(t))&&nt.test(t)?t.replace(et,"\\$&"):t},Dn.every=function(t,e,n){var r=Us(t)?xe:dr;return n&&yo(t,e,n)&&(e=i),r(t,oo(e,3))},Dn.find=gs,Dn.findIndex=Ho,Dn.findKey=function(t,e){return Ne(t,oo(e,3),mr)},Dn.findLast=vs,Dn.findLastIndex=Uo,Dn.findLastKey=function(t,e){return Ne(t,oo(e,3),_r)},Dn.floor=bu,Dn.forEach=ys,Dn.forEachRight=ms,Dn.forIn=function(t,e){return null==t?t:vr(t,oo(e,3),ja)},Dn.forInRight=function(t,e){return null==t?t:yr(t,oo(e,3),ja)},Dn.forOwn=function(t,e){return t&&mr(t,oo(e,3))},Dn.forOwnRight=function(t,e){return t&&_r(t,oo(e,3))},Dn.get=Sa,Dn.gt=Bs,Dn.gte=qs,Dn.has=function(t,e){return null!=t&&ho(t,e,Sr)},Dn.hasIn=Aa,Dn.head=zo,Dn.identity=nu,Dn.includes=function(t,e,n,r){t=zs(t)?t:Ia(t),n=n&&!r?ha(n):0;var i=t.length;return n<0&&(n=vn(i+n,0)),sa(t)?n<=i&&t.indexOf(e,n)>-1:!!i&&Ie(t,e,n)>-1},Dn.indexOf=function(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var i=null==n?0:ha(n);return i<0&&(i=vn(r+i,0)),Ie(t,e,i)},Dn.inRange=function(t,e,n){return e=da(e),n===i?(n=e,e=0):n=da(n),function(t,e,n){return t>=yn(e,n)&&t<vn(e,n)}(t=ga(t),e,n)},Dn.invoke=Ta,Dn.isArguments=Hs,Dn.isArray=Us,Dn.isArrayBuffer=Ws,Dn.isArrayLike=zs,Dn.isArrayLikeObject=Vs,Dn.isBoolean=function(t){return!0===t||!1===t||ta(t)&&kr(t)==y},Dn.isBuffer=Ks,Dn.isDate=Ys,Dn.isElement=function(t){return ta(t)&&1===t.nodeType&&!ra(t)},Dn.isEmpty=function(t){if(null==t)return!0;if(zs(t)&&(Us(t)||"string"==typeof t||"function"==typeof t.splice||Ks(t)||ua(t)||Hs(t)))return!t.length;var e=fo(t);if(e==w||e==x)return!t.size;if(Co(t))return!Rr(t).length;for(var n in t)if(Pt.call(t,n))return!1;return!0},Dn.isEqual=function(t,e){return Fr(t,e)},Dn.isEqualWith=function(t,e,n){var r=(n="function"==typeof n?n:i)?n(t,e):i;return r===i?Fr(t,e,i,n):!!r},Dn.isError=Gs,Dn.isFinite=function(t){return"number"==typeof t&&Le(t)},Dn.isFunction=Js,Dn.isInteger=Xs,Dn.isLength=Zs,Dn.isMap=ea,Dn.isMatch=function(t,e){return t===e||jr(t,e,ao(e))},Dn.isMatchWith=function(t,e,n){return n="function"==typeof n?n:i,jr(t,e,ao(e),n)},Dn.isNaN=function(t){return na(t)&&t!=+t},Dn.isNative=function(t){if(bo(t))throw new Ct("Unsupported core-js use. Try https://npms.io/search?q=ponyfill.");return $r(t)},Dn.isNil=function(t){return null==t},Dn.isNull=function(t){return null===t},Dn.isNumber=na,Dn.isObject=Qs,Dn.isObjectLike=ta,Dn.isPlainObject=ra,Dn.isRegExp=ia,Dn.isSafeInteger=function(t){return Xs(t)&&t>=-9007199254740991&&t<=f},Dn.isSet=oa,Dn.isString=sa,Dn.isSymbol=aa,Dn.isTypedArray=ua,Dn.isUndefined=function(t){return t===i},Dn.isWeakMap=function(t){return ta(t)&&fo(t)==F},Dn.isWeakSet=function(t){return ta(t)&&"[object WeakSet]"==kr(t)},Dn.join=function(t,e){return null==t?"":We.call(t,e)},Dn.kebabCase=Ua,Dn.last=Go,Dn.lastIndexOf=function(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var o=r;return n!==i&&(o=(o=ha(n))<0?vn(r+o,0):yn(o,r-1)),e==e?function(t,e,n){for(var r=n+1;r--;)if(t[r]===e)return r;return r}(t,e,o):De(t,qe,o,!0)},Dn.lowerCase=Wa,Dn.lowerFirst=za,Dn.lt=ca,Dn.lte=la,Dn.max=function(t){return t&&t.length?hr(t,nu,Er):i},Dn.maxBy=function(t,e){return t&&t.length?hr(t,oo(e,2),Er):i},Dn.mean=function(t){return He(t,nu)},Dn.meanBy=function(t,e){return He(t,oo(e,2))},Dn.min=function(t){return t&&t.length?hr(t,nu,Mr):i},Dn.minBy=function(t,e){return t&&t.length?hr(t,oo(e,2),Mr):i},Dn.stubArray=pu,Dn.stubFalse=gu,Dn.stubObject=function(){return{}},Dn.stubString=function(){return""},Dn.stubTrue=function(){return!0},Dn.multiply=Cu,Dn.nth=function(t,e){return t&&t.length?Br(t,ha(e)):i},Dn.noConflict=function(){return fe._===this&&(fe._=Dt),this},Dn.noop=au,Dn.now=Ss,Dn.pad=function(t,e,n){t=ya(t);var r=(e=ha(e))?ln(t):0;if(!e||r>=e)return t;var i=(e-r)/2;return qi(he(i),n)+t+qi(de(i),n)},Dn.padEnd=function(t,e,n){t=ya(t);var r=(e=ha(e))?ln(t):0;return e&&r<e?t+qi(e-r,n):t},Dn.padStart=function(t,e,n){t=ya(t);var r=(e=ha(e))?ln(t):0;return e&&r<e?qi(e-r,n)+t:t},Dn.parseInt=function(t,e,n){return n||null==e?e=0:e&&(e=+e),_n(ya(t).replace(rt,""),e||0)},Dn.random=function(t,e,n){if(n&&"boolean"!=typeof n&&yo(t,e,n)&&(e=n=i),n===i&&("boolean"==typeof e?(n=e,e=i):"boolean"==typeof t&&(n=t,t=i)),t===i&&e===i?(t=0,e=1):(t=da(t),e===i?(e=t,t=0):e=da(e)),t>e){var r=t;t=e,e=r}if(n||t%1||e%1){var o=bn();return yn(t+o*(e-t+ae("1e-"+((o+"").length-1))),e)}return zr(t,e)},Dn.reduce=function(t,e,n){var r=Us(t)?Pe:ze,i=arguments.length<3;return r(t,oo(e,4),n,i,lr)},Dn.reduceRight=function(t,e,n){var r=Us(t)?Re:ze,i=arguments.length<3;return r(t,oo(e,4),n,i,fr)},Dn.repeat=function(t,e,n){return e=(n?yo(t,e,n):e===i)?1:ha(e),Vr(ya(t),e)},Dn.replace=function(){var t=arguments,e=ya(t[0]);return t.length<3?e:e.replace(t[1],t[2])},Dn.result=function(t,e,n){var r=-1,o=(e=vi(e,t)).length;for(o||(o=1,t=i);++r<o;){var s=null==t?i:t[Lo(e[r])];s===i&&(r=o,s=n),t=Js(s)?s.call(t):s}return t},Dn.round=wu,Dn.runInContext=t,Dn.sample=function(t){return(Us(t)?Gn:Yr)(t)},Dn.size=function(t){if(null==t)return 0;if(zs(t))return sa(t)?ln(t):t.length;var e=fo(t);return e==w||e==x?t.size:Rr(t).length},Dn.snakeCase=Va,Dn.some=function(t,e,n){var r=Us(t)?Me:ei;return n&&yo(t,e,n)&&(e=i),r(t,oo(e,3))},Dn.sortedIndex=function(t,e){return ni(t,e)},Dn.sortedIndexBy=function(t,e,n){return ri(t,e,oo(n,2))},Dn.sortedIndexOf=function(t,e){var n=null==t?0:t.length;if(n){var r=ni(t,e);if(r<n&&Is(t[r],e))return r}return-1},Dn.sortedLastIndex=function(t,e){return ni(t,e,!0)},Dn.sortedLastIndexBy=function(t,e,n){return ri(t,e,oo(n,2),!0)},Dn.sortedLastIndexOf=function(t,e){if(null!=t&&t.length){var n=ni(t,e,!0)-1;if(Is(t[n],e))return n}return-1},Dn.startCase=Ka,Dn.startsWith=function(t,e,n){return t=ya(t),n=null==n?0:or(ha(n),0,t.length),e=si(e),t.slice(n,n+e.length)==e},Dn.subtract=ku,Dn.sum=function(t){return t&&t.length?Ve(t,nu):0},Dn.sumBy=function(t,e){return t&&t.length?Ve(t,oo(e,2)):0},Dn.template=function(t,e,n){var r=Dn.templateSettings;n&&yo(t,e,n)&&(e=i),t=ya(t),e=ba({},e,r,Gi);var o,s,a=ba({},e.imports,r.imports,Gi),u=Fa(a),c=Je(a,u),l=0,f=e.interpolate||_t,d="__p += '",h=St((e.escape||_t).source+"|"+f.source+"|"+(f===X?ft:_t).source+"|"+(e.evaluate||_t).source+"|$","g"),p="//# sourceURL="+(Pt.call(e,"sourceURL")?(e.sourceURL+"").replace(/\s/g," "):"lodash.templateSources["+ ++re+"]")+"\n";t.replace(h,(function(e,n,r,i,a,u){return r||(r=i),d+=t.slice(l,u).replace(bt,nn),n&&(o=!0,d+="' +\n__e("+n+") +\n'"),a&&(s=!0,d+="';\n"+a+";\n__p += '"),r&&(d+="' +\n((__t = ("+r+")) == null ? '' : __t) +\n'"),l=u+e.length,e})),d+="';\n";var g=Pt.call(e,"variable")&&e.variable;if(g){if(ct.test(g))throw new Ct("Invalid `variable` option passed into `_.template`")}else d="with (obj) {\n"+d+"\n}\n";d=(s?d.replace(H,""):d).replace(U,"$1").replace(W,"$1;"),d="function("+(g||"obj")+") {\n"+(g?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(o?", __e = _.escape":"")+(s?", __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\n":";\n")+d+"return __p\n}";var v=Xa((function(){return wt(u,p+"return "+d).apply(i,c)}));if(v.source=d,Gs(v))throw v;return v},Dn.times=function(t,e){if((t=ha(t))<1||t>f)return[];var n=h,r=yn(t,h);e=oo(e),t-=h;for(var i=Ke(r,e);++n<t;)e(n);return i},Dn.toFinite=da,Dn.toInteger=ha,Dn.toLength=pa,Dn.toLower=function(t){return ya(t).toLowerCase()},Dn.toNumber=ga,Dn.toSafeInteger=function(t){return t?or(ha(t),-9007199254740991,f):0===t?t:0},Dn.toString=ya,Dn.toUpper=function(t){return ya(t).toUpperCase()},Dn.trim=function(t,e,n){if((t=ya(t))&&(n||e===i))return Ye(t);if(!t||!(e=si(e)))return t;var r=fn(t),o=fn(e);return mi(r,Ze(r,o),Qe(r,o)+1).join("")},Dn.trimEnd=function(t,e,n){if((t=ya(t))&&(n||e===i))return t.slice(0,dn(t)+1);if(!t||!(e=si(e)))return t;var r=fn(t);return mi(r,0,Qe(r,fn(e))+1).join("")},Dn.trimStart=function(t,e,n){if((t=ya(t))&&(n||e===i))return t.replace(rt,"");if(!t||!(e=si(e)))return t;var r=fn(t);return mi(r,Ze(r,fn(e))).join("")},Dn.truncate=function(t,e){var n=30,r="...";if(Qs(e)){var o="separator"in e?e.separator:o;n="length"in e?ha(e.length):n,r="omission"in e?si(e.omission):r}var s=(t=ya(t)).length;if(rn(t)){var a=fn(t);s=a.length}if(n>=s)return t;var u=n-ln(r);if(u<1)return r;var c=a?mi(a,0,u).join(""):t.slice(0,u);if(o===i)return c+r;if(a&&(u+=c.length-u),ia(o)){if(t.slice(u).search(o)){var l,f=c;for(o.global||(o=St(o.source,ya(dt.exec(o))+"g")),o.lastIndex=0;l=o.exec(f);)var d=l.index;c=c.slice(0,d===i?u:d)}}else if(t.indexOf(si(o),u)!=u){var h=c.lastIndexOf(o);h>-1&&(c=c.slice(0,h))}return c+r},Dn.unescape=function(t){return(t=ya(t))&&K.test(t)?t.replace(z,hn):t},Dn.uniqueId=function(t){var e=++Rt;return ya(t)+e},Dn.upperCase=Ya,Dn.upperFirst=Ga,Dn.each=ys,Dn.eachRight=ms,Dn.first=zo,su(Dn,(vu={},mr(Dn,(function(t,e){Pt.call(Dn.prototype,e)||(vu[e]=t)})),vu),{chain:!1}),Dn.VERSION="4.17.21",Se(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(t){Dn[t].placeholder=Dn})),Se(["drop","take"],(function(t,e){Hn.prototype[t]=function(n){n=n===i?1:vn(ha(n),0);var r=this.__filtered__&&!e?new Hn(this):this.clone();return r.__filtered__?r.__takeCount__=yn(n,r.__takeCount__):r.__views__.push({size:yn(n,h),type:t+(r.__dir__<0?"Right":"")}),r},Hn.prototype[t+"Right"]=function(e){return this.reverse()[t](e).reverse()}})),Se(["filter","map","takeWhile"],(function(t,e){var n=e+1,r=1==n||3==n;Hn.prototype[t]=function(t){var e=this.clone();return e.__iteratees__.push({iteratee:oo(t,3),type:n}),e.__filtered__=e.__filtered__||r,e}})),Se(["head","last"],(function(t,e){var n="take"+(e?"Right":"");Hn.prototype[t]=function(){return this[n](1).value()[0]}})),Se(["initial","tail"],(function(t,e){var n="drop"+(e?"":"Right");Hn.prototype[t]=function(){return this.__filtered__?new Hn(this):this[n](1)}})),Hn.prototype.compact=function(){return this.filter(nu)},Hn.prototype.find=function(t){return this.filter(t).head()},Hn.prototype.findLast=function(t){return this.reverse().find(t)},Hn.prototype.invokeMap=Kr((function(t,e){return"function"==typeof t?new Hn(this):this.map((function(n){return Or(n,t,e)}))})),Hn.prototype.reject=function(t){return this.filter(Rs(oo(t)))},Hn.prototype.slice=function(t,e){t=ha(t);var n=this;return n.__filtered__&&(t>0||e<0)?new Hn(n):(t<0?n=n.takeRight(-t):t&&(n=n.drop(t)),e!==i&&(n=(e=ha(e))<0?n.dropRight(-e):n.take(e-t)),n)},Hn.prototype.takeRightWhile=function(t){return this.reverse().takeWhile(t).reverse()},Hn.prototype.toArray=function(){return this.take(h)},mr(Hn.prototype,(function(t,e){var n=/^(?:filter|find|map|reject)|While$/.test(e),r=/^(?:head|last)$/.test(e),o=Dn[r?"take"+("last"==e?"Right":""):e],s=r||/^find/.test(e);o&&(Dn.prototype[e]=function(){var e=this.__wrapped__,a=r?[1]:arguments,u=e instanceof Hn,c=a[0],l=u||Us(e),f=function(t){var e=o.apply(Dn,$e([t],a));return r&&d?e[0]:e};l&&n&&"function"==typeof c&&1!=c.length&&(u=l=!1);var d=this.__chain__,h=!!this.__actions__.length,p=s&&!d,g=u&&!h;if(!s&&l){e=g?e:new Hn(this);var v=t.apply(e,a);return v.__actions__.push({func:ds,args:[f],thisArg:i}),new qn(v,d)}return p&&g?t.apply(this,a):(v=this.thru(f),p?r?v.value()[0]:v.value():v)})})),Se(["pop","push","shift","sort","splice","unshift"],(function(t){var e=Ot[t],n=/^(?:push|sort|unshift)$/.test(t)?"tap":"thru",r=/^(?:pop|shift)$/.test(t);Dn.prototype[t]=function(){var t=arguments;if(r&&!this.__chain__){var i=this.value();return e.apply(Us(i)?i:[],t)}return this[n]((function(n){return e.apply(Us(n)?n:[],t)}))}})),mr(Hn.prototype,(function(t,e){var n=Dn[e];if(n){var r=n.name+"";Pt.call(Tn,r)||(Tn[r]=[]),Tn[r].push({name:e,func:n})}})),Tn[Ni(i,2).name]=[{name:"wrapper",func:i}],Hn.prototype.clone=function(){var t=new Hn(this.__wrapped__);return t.__actions__=Ai(this.__actions__),t.__dir__=this.__dir__,t.__filtered__=this.__filtered__,t.__iteratees__=Ai(this.__iteratees__),t.__takeCount__=this.__takeCount__,t.__views__=Ai(this.__views__),t},Hn.prototype.reverse=function(){if(this.__filtered__){var t=new Hn(this);t.__dir__=-1,t.__filtered__=!0}else(t=this.clone()).__dir__*=-1;return t},Hn.prototype.value=function(){var t=this.__wrapped__.value(),e=this.__dir__,n=Us(t),r=e<0,i=n?t.length:0,o=function(t,e,n){for(var r=-1,i=n.length;++r<i;){var o=n[r],s=o.size;switch(o.type){case"drop":t+=s;break;case"dropRight":e-=s;break;case"take":e=yn(e,t+s);break;case"takeRight":t=vn(t,e-s)}}return{start:t,end:e}}(0,i,this.__views__),s=o.start,a=o.end,u=a-s,c=r?a:s-1,l=this.__iteratees__,f=l.length,d=0,h=yn(u,this.__takeCount__);if(!n||!r&&i==u&&h==u)return fi(t,this.__actions__);var p=[];t:for(;u--&&d<h;){for(var g=-1,v=t[c+=e];++g<f;){var y=l[g],m=y.iteratee,_=y.type,b=m(v);if(2==_)v=b;else if(!b){if(1==_)continue t;break t}}p[d++]=v}return p},Dn.prototype.at=hs,Dn.prototype.chain=function(){return fs(this)},Dn.prototype.commit=function(){return new qn(this.value(),this.__chain__)},Dn.prototype.next=function(){this.__values__===i&&(this.__values__=fa(this.value()));var t=this.__index__>=this.__values__.length;return{done:t,value:t?i:this.__values__[this.__index__++]}},Dn.prototype.plant=function(t){for(var e,n=this;n instanceof Bn;){var r=Do(n);r.__index__=0,r.__values__=i,e?o.__wrapped__=r:e=r;var o=r;n=n.__wrapped__}return o.__wrapped__=t,e},Dn.prototype.reverse=function(){var t=this.__wrapped__;if(t instanceof Hn){var e=t;return this.__actions__.length&&(e=new Hn(this)),(e=e.reverse()).__actions__.push({func:ds,args:[Qo],thisArg:i}),new qn(e,this.__chain__)}return this.thru(Qo)},Dn.prototype.toJSON=Dn.prototype.valueOf=Dn.prototype.value=function(){return fi(this.__wrapped__,this.__actions__)},Dn.prototype.first=Dn.prototype.head,Gt&&(Dn.prototype[Gt]=function(){return this}),Dn}();fe._=pn,(r=function(){return pn}.call(e,n,e,t))===i||(t.exports=r)}.call(this)},3669:(t,e,n)=>{e.formatArgs=function(e){if(e[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+e[0]+(this.useColors?"%c ":" ")+"+"+t.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;e.splice(1,0,n,"color: inherit");let r=0,i=0;e[0].replace(/%[a-zA-Z%]/g,(t=>{"%%"!==t&&(r++,"%c"===t&&(i=r))})),e.splice(i,0,n)},e.save=function(t){try{t?e.storage.setItem("debug",t):e.storage.removeItem("debug")}catch(t){}},e.load=function(){let t;try{t=e.storage.getItem("debug")}catch(t){}return!t&&"undefined"!=typeof process&&"env"in process&&(t=process.env.DEBUG),t},e.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+)/))},e.storage=function(){try{return localStorage}catch(t){}}(),e.destroy=(()=>{let t=!1;return()=>{t||(t=!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`."))}})(),e.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"],e.log=console.debug||console.log||(()=>{}),t.exports=n(9231)(e);const{formatters:r}=t.exports;r.j=function(t){try{return JSON.stringify(t)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}}},9231:(t,e,n)=>{t.exports=function(t){function e(t){let n,i,o,s=null;function a(...t){if(!a.enabled)return;const r=a,i=Number(new Date),o=i-(n||i);r.diff=o,r.prev=n,r.curr=i,n=i,t[0]=e.coerce(t[0]),"string"!=typeof t[0]&&t.unshift("%O");let s=0;t[0]=t[0].replace(/%([a-zA-Z%])/g,((n,i)=>{if("%%"===n)return"%";s++;const o=e.formatters[i];if("function"==typeof o){const e=t[s];n=o.call(r,e),t.splice(s,1),s--}return n})),e.formatArgs.call(r,t),(r.log||e.log).apply(r,t)}return a.namespace=t,a.useColors=e.useColors(),a.color=e.selectColor(t),a.extend=r,a.destroy=e.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==s?s:(i!==e.namespaces&&(i=e.namespaces,o=e.enabled(t)),o),set:t=>{s=t}}),"function"==typeof e.init&&e.init(a),a}function r(t,n){const r=e(this.namespace+(void 0===n?":":n)+t);return r.log=this.log,r}function i(t){return t.toString().substring(2,t.toString().length-2).replace(/\.\*\?$/,"*")}return e.debug=e,e.default=e,e.coerce=function(t){return t instanceof Error?t.stack||t.message:t},e.disable=function(){const t=[...e.names.map(i),...e.skips.map(i).map((t=>"-"+t))].join(",");return e.enable(""),t},e.enable=function(t){let n;e.save(t),e.namespaces=t,e.names=[],e.skips=[];const r=("string"==typeof t?t:"").split(/[\s,]+/),i=r.length;for(n=0;n<i;n++)r[n]&&("-"===(t=r[n].replace(/\*/g,".*?"))[0]?e.skips.push(new RegExp("^"+t.slice(1)+"$")):e.names.push(new RegExp("^"+t+"$")))},e.enabled=function(t){if("*"===t[t.length-1])return!0;let n,r;for(n=0,r=e.skips.length;n<r;n++)if(e.skips[n].test(t))return!1;for(n=0,r=e.names.length;n<r;n++)if(e.names[n].test(t))return!0;return!1},e.humanize=n(4241),e.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(t).forEach((n=>{e[n]=t[n]})),e.names=[],e.skips=[],e.formatters={},e.selectColor=function(t){let n=0;for(let e=0;e<t.length;e++)n=(n<<5)-n+t.charCodeAt(e),n|=0;return e.colors[Math.abs(n)%e.colors.length]},e.enable(e.load()),e}},4241:t=>{var e=1e3,n=60*e,r=60*n,i=24*r;function o(t,e,n,r){var i=e>=1.5*n;return Math.round(t/n)+" "+r+(i?"s":"")}t.exports=function(t,s){s=s||{};var a,u,c=typeof t;if("string"===c&&t.length>0)return function(t){if(!((t=String(t)).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(t);if(o){var s=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*s;case"weeks":case"week":case"w":return 6048e5*s;case"days":case"day":case"d":return s*i;case"hours":case"hour":case"hrs":case"hr":case"h":return s*r;case"minutes":case"minute":case"mins":case"min":case"m":return s*n;case"seconds":case"second":case"secs":case"sec":case"s":return s*e;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return s;default:return}}}}(t);if("number"===c&&isFinite(t))return s.long?(a=t,(u=Math.abs(a))>=i?o(a,u,i,"day"):u>=r?o(a,u,r,"hour"):u>=n?o(a,u,n,"minute"):u>=e?o(a,u,e,"second"):a+" ms"):function(t){var o=Math.abs(t);return o>=i?Math.round(t/i)+"d":o>=r?Math.round(t/r)+"h":o>=n?Math.round(t/n)+"m":o>=e?Math.round(t/e)+"s":t+"ms"}(t);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(t))}},1618:(t,e,n)=>{e.formatArgs=function(e){if(e[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+e[0]+(this.useColors?"%c ":" ")+"+"+t.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;e.splice(1,0,n,"color: inherit");let r=0,i=0;e[0].replace(/%[a-zA-Z%]/g,(t=>{"%%"!==t&&(r++,"%c"===t&&(i=r))})),e.splice(i,0,n)},e.save=function(t){try{t?e.storage.setItem("debug",t):e.storage.removeItem("debug")}catch(t){}},e.load=function(){let t;try{t=e.storage.getItem("debug")}catch(t){}return!t&&"undefined"!=typeof process&&"env"in process&&(t=process.env.DEBUG),t},e.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+)/))},e.storage=function(){try{return localStorage}catch(t){}}(),e.destroy=(()=>{let t=!1;return()=>{t||(t=!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`."))}})(),e.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"],e.log=console.debug||console.log||(()=>{}),t.exports=n(5224)(e);const{formatters:r}=t.exports;r.j=function(t){try{return JSON.stringify(t)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}}},5224:(t,e,n)=>{t.exports=function(t){function e(t){let n,i,o,s=null;function a(...t){if(!a.enabled)return;const r=a,i=Number(new Date),o=i-(n||i);r.diff=o,r.prev=n,r.curr=i,n=i,t[0]=e.coerce(t[0]),"string"!=typeof t[0]&&t.unshift("%O");let s=0;t[0]=t[0].replace(/%([a-zA-Z%])/g,((n,i)=>{if("%%"===n)return"%";s++;const o=e.formatters[i];if("function"==typeof o){const e=t[s];n=o.call(r,e),t.splice(s,1),s--}return n})),e.formatArgs.call(r,t),(r.log||e.log).apply(r,t)}return a.namespace=t,a.useColors=e.useColors(),a.color=e.selectColor(t),a.extend=r,a.destroy=e.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==s?s:(i!==e.namespaces&&(i=e.namespaces,o=e.enabled(t)),o),set:t=>{s=t}}),"function"==typeof e.init&&e.init(a),a}function r(t,n){const r=e(this.namespace+(void 0===n?":":n)+t);return r.log=this.log,r}function i(t){return t.toString().substring(2,t.toString().length-2).replace(/\.\*\?$/,"*")}return e.debug=e,e.default=e,e.coerce=function(t){return t instanceof Error?t.stack||t.message:t},e.disable=function(){const t=[...e.names.map(i),...e.skips.map(i).map((t=>"-"+t))].join(",");return e.enable(""),t},e.enable=function(t){let n;e.save(t),e.namespaces=t,e.names=[],e.skips=[];const r=("string"==typeof t?t:"").split(/[\s,]+/),i=r.length;for(n=0;n<i;n++)r[n]&&("-"===(t=r[n].replace(/\*/g,".*?"))[0]?e.skips.push(new RegExp("^"+t.slice(1)+"$")):e.names.push(new RegExp("^"+t+"$")))},e.enabled=function(t){if("*"===t[t.length-1])return!0;let n,r;for(n=0,r=e.skips.length;n<r;n++)if(e.skips[n].test(t))return!1;for(n=0,r=e.names.length;n<r;n++)if(e.names[n].test(t))return!0;return!1},e.humanize=n(8896),e.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(t).forEach((n=>{e[n]=t[n]})),e.names=[],e.skips=[],e.formatters={},e.selectColor=function(t){let n=0;for(let e=0;e<t.length;e++)n=(n<<5)-n+t.charCodeAt(e),n|=0;return e.colors[Math.abs(n)%e.colors.length]},e.enable(e.load()),e}},8896:t=>{var e=1e3,n=60*e,r=60*n,i=24*r;function o(t,e,n,r){var i=e>=1.5*n;return Math.round(t/n)+" "+r+(i?"s":"")}t.exports=function(t,s){s=s||{};var a,u,c=typeof t;if("string"===c&&t.length>0)return function(t){if(!((t=String(t)).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(t);if(o){var s=parseFloat(o[1]);switch((o[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return 315576e5*s;case"weeks":case"week":case"w":return 6048e5*s;case"days":case"day":case"d":return s*i;case"hours":case"hour":case"hrs":case"hr":case"h":return s*r;case"minutes":case"minute":case"mins":case"min":case"m":return s*n;case"seconds":case"second":case"secs":case"sec":case"s":return s*e;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return s;default:return}}}}(t);if("number"===c&&isFinite(t))return s.long?(a=t,(u=Math.abs(a))>=i?o(a,u,i,"day"):u>=r?o(a,u,r,"hour"):u>=n?o(a,u,n,"minute"):u>=e?o(a,u,e,"second"):a+" ms"):function(t){var o=Math.abs(t);return o>=i?Math.round(t/i)+"d":o>=r?Math.round(t/r)+"h":o>=n?Math.round(t/n)+"m":o>=e?Math.round(t/e)+"s":t+"ms"}(t);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(t))}},9336:function(t,e,n){"use strict";var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.configureChat=void 0;const i=r(n(3336));let o;function s(t){(0,i.default)("#chat-messages").html(t.map((t=>`<div class="chat-message" title="${new Date(parseInt(t.sentAt))}" id="${t.id}">\n    <span class="from">${t.from}</span>\n    <span class="message">${t.msg}</span>\n    </div>`)).join("\n")),(0,i.default)("#chat-messages").scrollTop((0,i.default)("#chat-messages")[0].scrollHeight)}function a(t){(0,i.default)("#chat-messages").append(`<div class="chat-message" title="${new Date(parseInt(t.sentAt))}" id="${t.id}">\n                             <span class="from">${t.from}</span>\n                             <span class="message">${t.msg}</span>\n                             </div>`),(0,i.default)("#chat-messages").scrollTop((0,i.default)("#chat-messages")[0].scrollHeight)}e.configureChat=function(t){o=t,o.on("chathistory",s),o.on("chat",a),(0,i.default)("#chat-form").on("submit",(t=>{t.preventDefault(),t.stopPropagation();const e=(0,i.default)("#message").val().toString();e.length>0&&(o.emit("chat",e),(0,i.default)("#message").val(""))})),console.log("Chat Configured")}},3253:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.CustomEventManager=void 0,e.CustomEventManager=class{constructor(){this.events={}}on(t,e){this.events[t]||(this.events[t]=[]),this.events[t].push(e)}emit(t,e=[]){this.events[t]&&this.events[t].forEach((t=>t.apply(null,e)))}}},5862:function(t,e){"use strict";var n=this&&this.__awaiter||function(t,e,n,r){return new(n||(n=Promise))((function(i,o){function s(t){try{u(r.next(t))}catch(t){o(t)}}function a(t){try{u(r.throw(t))}catch(t){o(t)}}function u(t){var e;t.done?i(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(s,a)}u((r=r.apply(t,e||[])).next())}))};function r(){return localStorage.getItem("authToken")}Object.defineProperty(e,"__esModule",{value:!0}),e.http=e.authToken=void 0,e.authToken=r,e.http={get:t=>n(void 0,void 0,void 0,(function*(){return(yield fetch(t,{headers:{"x-authtoken":r()}})).json()})),post:(t,e)=>n(void 0,void 0,void 0,(function*(){return(yield fetch(t,{method:"post",body:JSON.stringify(e),headers:{"x-authtoken":r(),"content-type":"application/json"}})).json()}))}},2174:function(t,e,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(t,e,n,r){void 0===r&&(r=n);var i=Object.getOwnPropertyDescriptor(e,n);i&&!("get"in i?!e.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return e[n]}}),Object.defineProperty(t,r,i)}:function(t,e,n,r){void 0===r&&(r=n),t[r]=e[n]}),i=this&&this.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),o=this&&this.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)"default"!==n&&Object.prototype.hasOwnProperty.call(t,n)&&r(e,t,n);return i(e,t),e},s=this&&this.__awaiter||function(t,e,n,r){return new(n||(n=Promise))((function(i,o){function s(t){try{u(r.next(t))}catch(t){o(t)}}function a(t){try{u(r.throw(t))}catch(t){o(t)}}function u(t){var e;t.done?i(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(s,a)}u((r=r.apply(t,e||[])).next())}))},a=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});const u=n(7046),c=a(n(3336)),l=n(4738),f=n(5862),d=n(3253),h=n(7429),p=n(6486),g=n(9502),v=n(9336),y=n(1916),m=o(n(7355)),_=new(n(8182).TimeManager),b=new Map,C=new d.CustomEventManager,w=(0,u.io)({extraHeaders:{"x-authtoken":(0,f.authToken)()}});function k(){const t=_.gradientName(),e=(0,c.default)("body");let n;e.removeClass(Array.from(e[0].classList)).addClass(t),e.addClass(_.getTimePeriod()),n=_.get24Hour()>=5&&_.get24Hour()<9?"morning":_.get24Hour()>=9&&_.get24Hour()<17?"afternoon":_.get24Hour()>=17&&_.get24Hour()<20?"evening":"night",(0,c.default)("#time-of-day").html(`<img src="/assets/img/icons/time-of-day/${n}.png"> ${_.getHour()}${_.getAmPm()}`)}function E(t){return`<img src="/assets/img/${t}.png" class="icon">`}function S(t,e,n,r=!0){let i=0;e>0&&(i=Math.floor(t/e*100));const o=r?`${i}% - `:"";return`<div class="progress-bar" style="background: linear-gradient(to right, ${n}, ${n} ${i}%, transparent ${i}%, transparent)" title="${o}${t}/${e}">${o}${t}/${e}</div>`}function A(t,e,n,r){let i=0;e>0&&(i=Math.floor(t/e*100)),(0,c.default)(`#${n}`).css("background",`linear-gradient(to right, ${r}, ${r} ${i}%, transparent ${i}%, transparent)`).attr("title",`${i}% - ${t}/${e}`).html(`${t}/${e} - ${i}%`)}function x(){const t=b.get("player");(0,c.default)("#username").html(`${t.username}, level ${t.level} ${t.profession}`),A(t.hp,(0,l.maxHp)(t.constitution,t.level),"hp-bar","#ff7070"),A(t.exp,(0,l.expToLevel)(t.level+1),"exp-bar","#5997f9"),["strength","constitution","dexterity","intelligence","hp","exp"].forEach((e=>{(0,c.default)(`.${e}`).html(t[e])})),(0,c.default)(".maxHp").html((0,l.maxHp)(t.constitution,t.level).toString()),(0,c.default)(".expToLevel").html((0,l.expToLevel)(t.level+1).toString()),(0,c.default)(".gold").html(t.gold.toLocaleString()),"session"===t.account_type&&(0,c.default)("#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>\n          <form id="signup">\n            <div class="form-group">\n              <label>Username:</label>\n              <input type="text" name="username">\n            </div>\n            <div class="form-group">\n              <label>Password:</label>\n              <input type="password" name="password">\n            </div>\n            <button type="submit" class="success">Create your Account</button>\n            <button type="button" id="login">Login To Existing Account</button>\n          </form></p>').removeClass("hidden"),(0,c.default)("#extra-inventory-info").html(T())}function O(t,e="error"){let n=(0,h.v4)();(0,c.default)("#alerts").append(`<div class="alert ${e}" id="alert-${n}">${t}</div>`),setTimeout((()=>{(0,c.default)(`#alert-${n}`).remove()}),3e3)}function T(){const t=b.get("player");let e='<table id="stat-breakdown">';return l.StatDef.forEach((n=>{e+=`<tr>\n      <th>${n.display}</th>\n      <td class="${n.id}">\n        ${t[n.id]}\n        ${t.stat_points?function(t){return`<button class="increase-stat emit-event" data-event="spend-stat-point" data-args="${t.id}">+</button>`}(n):""}\n      </td>\n    </tr>`})),e+=`<tr><th>Stat Points</th><td class="stat_points">${t.stat_points}</td></tr>`,e+="</table>",e}function F(t){return t.map((t=>function(t,e){return`<div class="store-list">\n    <div>\n      <img src="https://via.placeholder.com/64x64">\n    </div>\n    <div class="details">\n      <div class="name">${t.name}</div>\n      <div class="requirements">\n      ${t.requirements.level?$("LVL",t.requirements.level):""}\n      ${t.requirements.strength?$("STR",t.requirements.strength):""}\n      ${t.requirements.constitution?$("CON",t.requirements.constitution):""}\n      ${t.requirements.dexterity?$("DEX",t.requirements.dexterity):""}\n      ${t.requirements.intelligence?$("INT",t.requirements.intelligence):""}\n      ${$("PRF",t.profession)}\n      </div>\n      <div class="stat-mods">\n      ${t.boosts.strength?P("STR",t.boosts.strength):""}\n      ${t.boosts.constitution?P("CON",t.boosts.constitution):""}\n      ${t.boosts.dexterity?P("DEX",t.boosts.dexterity):""}\n      ${t.boosts.intelligence?P("INT",t.boosts.intelligence):""}\n      ${t.boosts.damage?P("DMG",t.boosts.damage):""}\n      ${t.boosts.damage_mitigation?P("MIT",t.boosts.damage_mitigation.toString())+"%":""}\n      ${["WEAPON","SPELL"].includes(t.type)?"":S(t.currentAp,t.maxAp,"#7be67b")}\n      </div>\n      ${t.hasOwnProperty("id")?`<div>${t.cost.toLocaleString()}G</div>`:""}\n    </div>\n    <div class="store-actions">\n      ${(t=>t.is_equipped?`<button type="button" class="unequip-item error" data-id="${t.item_id}">Unequip</button>`:"ANY_HAND"===t.equipment_slot?`<button type="button" class="equip-item" data-id="${t.item_id}" data-slot="LEFT_HAND">Equip L</button>\n          <button type="button" class="equip-item" data-id="${t.item_id}" data-slot="RIGHT_HAND">Equip R</button>`:"LEFT_HAND"===t.equipment_slot?`<button type="button" class="equip-item" data-id="${t.item_id}" data-slot="${t.equipment_slot}">Equip Left</button>`:"RIGHT_HAND"===t.equipment_slot?`<button type="button" class="equip-item" data-id="${t.item_id}" data-slot="${t.equipment_slot}">Equip Right</button>`:(t.equipment_slot,`<button type="button" class="equip-item" data-id="${t.item_id}" data-slot="${t.equipment_slot}">Equip</button>`))(t)}\n    </div>\n    </div>`}(t))).join("\n")}function j(t){(0,c.default)("#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/${t}.jpeg")`})}function $(t,e,n){let r="";return n&&(r=n>=e?"success":"error"),`<span class="requirement-title">${t}</span>: <span class="requirement-value ${r}">${e.toLocaleString()}</span>`}function P(t,e){let n="";return"number"==typeof e&&(n=e>0?"+":"-"),`<span class="requirement-title">${t}</span>: <span class="requirement-value ${"number"==typeof e?e>0?"success":"error":""}">${n}${e}</span>`}function R(t,e){const n=b.get("player");return`<div class="store-list">\n    <div>\n      <img src="https://via.placeholder.com/64x64">\n    </div>\n    <div class="details">\n      <div class="name">${t.name}${"TWO_HANDED"===t.equipment_slot?" (2H)":""}</div>\n      <div class="requirements">\n      ${t.requirements.level?$("LVL",t.requirements.level,n.level):""}\n      ${t.requirements.strength?$("STR",t.requirements.strength,n.strength):""}\n      ${t.requirements.constitution?$("CON",t.requirements.constitution,n.constitution):""}\n      ${t.requirements.dexterity?$("DEX",t.requirements.dexterity,n.dexterity):""}\n      ${t.requirements.intelligence?$("INT",t.requirements.intelligence,n.intelligence):""}\n      ${$("PRF",t.profession)}\n      </div>\n      <div class="stat-mods">\n      ${t.boosts.strength?P("STR",t.boosts.strength):""}\n      ${t.boosts.constitution?P("CON",t.boosts.constitution):""}\n      ${t.boosts.dexterity?P("DEX",t.boosts.dexterity):""}\n      ${t.boosts.intelligence?P("INT",t.boosts.intelligence):""}\n      ${t.boosts.damage?P(t.affectedSkills.includes("restoration_magic")?"HP":"DMG",t.boosts.damage):""}\n      ${t.boosts.damage_mitigation?P("MIT",t.boosts.damage_mitigation.toString())+"%":""}\n      ${["WEAPON","SPELL"].includes(t.type)?"":P("AP",t.maxAp.toString())}\n      </div>\n      ${t.hasOwnProperty("id")?`<div>${t.cost.toLocaleString()}G</div>`:""}\n    </div>\n    <div class="store-actions">\n      ${e(t)}\n    </div>\n    </div>`}function M(){const t=(0,c.default)("#keep-walking").data("block"),e=parseInt(t)||0;if(e>0){const t=Math.ceil((e-Date.now())/1e3);if(t>0)return(0,c.default)("#keep-walking").prop("disabled",!0).html(`Keep walking (${t}s)`),void setTimeout(M,300)}(0,c.default)("#keep-walking").prop("disabled",!1).html("Keep walking")}function L(t){const e=Math.floor(t.hp/t.maxHp*100);return`<div id="fight-container">\n    <div id="defender-info">\n      <div class="avatar-container">\n        <img id="avatar" src="https://via.placeholder.com/64x64">\n      </div>\n      <div id="defender-stat-bars">\n        <div id="defender-name">${t.name}</div>\n        <div class="progress-bar" id="defender-hp-bar" style="background: linear-gradient(to right, red, red ${e}%, transparent ${e}%, transparent)" title="${e}% - ${t.hp}/${t.maxHp}">${e}% - ${t.hp} / ${t.maxHp}</div>\n      </div>\n    </div>\n    <div id="fight-actions">\n      <select id="fight-target">\n        <option value="head">Head</option>\n        <option value="body">Body</option>\n        <option value="arms">Arms</option>\n        <option value="legs">Legs</option>\n      </select>\n      <button type="button" class="fight-action" data-action="attack">Attack</button>\n      <button type="button" class="fight-action" data-action="cast">Cast</button>\n      <button type="button" class="fight-action" data-action="flee">Flee</button>\n    </div>\n    <div id="fight-results"></div>\n  </div>`}function N(t,e="explore"){return s(this,void 0,void 0,(function*(){if(b.get("player").hp<=0)C.emit("alert",[{type:"error",text:"You don't have enough HP to go looking for a fight"}]);else{b.set("last-selected-monster",t);try{const n=yield f.http.post("/fight",{monsterId:t,fightTrigger:e});(0,c.default)("#map").html(L(n))}catch(t){C.emit("alert",[{type:"error",text:"Sorry, you can't start that fight"}])}}}))}(0,v.configureChat)(w),k(),setInterval(k,6e4),w.on("connect",(()=>{console.log(`Connected: ${w.id}`)})),w.on("ready",(function(){console.log("Server connection verified"),w.emit("inventory"),(0,c.default)("nav a").first().click()})),w.on("server-stats",(t=>{(0,c.default)("#server-stats").html(`${t.onlinePlayers} players online`)})),(0,p.each)(m,(t=>{console.log(`Binding Event ${t.eventName}`),t instanceof y.SocketEvent?w.on(t.eventName,t.handler.bind(null,{cache:b,socket:w,events:C})):console.log("Skipped binding",t)})),w.on("calc:ap",(t=>{var e,n,r,i,o,s,a,u;const{ap:l}=t,f=`\n  <div>\n    ${E("helm")}\n    ${S((null===(e=l.HEAD)||void 0===e?void 0:e.currentAp)||0,(null===(n=l.HEAD)||void 0===n?void 0:n.maxAp)||0,"#7be67b")}\n  </div>\n  <div>\n    ${E("arms")}\n    ${S((null===(r=l.ARMS)||void 0===r?void 0:r.currentAp)||0,(null===(i=l.ARMS)||void 0===i?void 0:i.maxAp)||0,"#7be67b")}\n  </div>\n  <div>\n    ${E("chest")}\n    ${S((null===(o=l.CHEST)||void 0===o?void 0:o.currentAp)||0,(null===(s=l.CHEST)||void 0===s?void 0:s.maxAp)||0,"#7be67b")}\n  </div>\n  <div>\n    ${E("legs")}\n    ${S((null===(a=l.LEGS)||void 0===a?void 0:a.currentAp)||0,(null===(u=l.LEGS)||void 0===u?void 0:u.maxAp)||0,"#7be67b")}\n  </div>\n  `;(0,c.default)("#ap-bar").html(f)})),C.on("tab:skills",(()=>{(0,c.default)("#skills").html(""),w.emit("skills")})),w.on("skills",(t=>{let e=`<table id="skill-list">\n  ${t.skills.map((t=>{const e=g.Skills.get(t.id),n=t.exp/e.expToLevel(t.level+1);return`\n    <tr>\n    <td class="skill-level">${t.level.toLocaleString()}</td>\n    <td class="skill-description" title="Total Exp: ${t.exp.toLocaleString()}/${e.expToLevel(t.level+1).toLocaleString()}">\n      <span class="skill-exp">${(100*n).toPrecision(2)}% to next level</span>\n      <b>${e.display}</b>\n      <p>${e.description}</p>\n    </td>\n    </tr>\n    `})).join("\n")}\n  </table>`;(0,c.default)("#skills").html(e)})),C.on("alert",(t=>{O(t.text,t.type)})),w.on("alert",(t=>{C.emit("alert",[t])})),w.on("init",(t=>{(0,c.default)("#version").html(`v${t.version}`)})),w.on("authToken",(t=>{console.log(`recv auth token ${t}`),localStorage.setItem("authToken",t)})),w.on("player",(t=>{b.set("player",t),x()})),(0,c.default)("nav a").on("click",(t=>s(void 0,void 0,void 0,(function*(){t.preventDefault(),t.stopPropagation(),yield function(){return s(this,void 0,void 0,(function*(){const t=yield f.http.get("/state");b.set("state",t)}))}();const e=b.get("state"),n=(0,c.default)(`#${(0,c.default)(t.target).data("container")}`);let r=(0,c.default)(t.target).data("section");["skills","inventory"].includes(r)&&null!==(null==e?void 0:e.fight)&&(O("You are currently in a fight","error"),r="explore"),n.find(".tab").removeClass("active"),(0,c.default)(`#${r}`).addClass("active"),"Settings"!==t.target.innerHTML&&((0,c.default)(t.target).closest("nav").find("a").removeClass("active"),(0,c.default)(`nav a[data-section=${r}]`).addClass("active")),C.emit(`tab:${r}`)})))),C.on("tab:inventory",(()=>{w.emit("inventory")})),(0,c.default)("body").on("click","nav.filter",(t=>{t.preventDefault(),t.stopPropagation();const e=(0,c.default)(t.target),n=e.data("filter");(0,c.default)(".filter-result").removeClass("active").addClass("hidden"),(0,c.default)(`#filter_${n}`).addClass("active").removeClass("hidden"),e.closest("nav").find("a").removeClass("active"),e.addClass("active");const r=`active-${(0,c.default)(t.target).closest("nav").attr("id")}`;b.set(r,n)})),w.on("inventory",(t=>{b.get("player");const e=b.get("active-inventory-section")||"ARMOUR",n={ARMOUR:[],WEAPON:[],SPELL:[]};t.inventory.forEach((t=>{n[t.type].push(t)}));const r=`\n  <div id="inventory-page">\n    <div id="character-summary">\n    ${function(t){const e="https://via.placeholder.com/64x64",n=t.filter((t=>t.is_equipped)).reduce(((t,e)=>(t[e.equipment_slot]=e,t)),{});return`\n  <table id="character-equipment-placement">\n  <tr>\n    <td>\n    </td>\n    <td style="background-image: url('${e}');" title="${n.HEAD?n.HEAD.name:"Empty"}">\n    ${n.HEAD?n.HEAD.name:"HEAD"}\n    </td>\n    <td style="background-image: url('${e}');" title="${n.ARMS?n.ARMS.name:"Empty"}">\n    ${n.ARMS?n.ARMS.name:"ARMS"}\n    </td>\n  </tr>\n  <tr>\n    <td style="background-image: url('${e}');" title="${n.LEFT_HAND?n.LEFT_HAND.name:n.TWO_HANDED?n.TWO_HANDED.name:""}">\n    ${n.LEFT_HAND?n.LEFT_HAND.name:n.TWO_HANDED?n.TWO_HANDED.name:"L_HAND"}\n    </td>\n    <td style="background-image: url('${e}');" title="${n.CHEST?n.CHEST.name:""}">\n    ${n.CHEST?n.CHEST.name:"CHEST"}\n    </td>\n    <td style="background-image: url('${e}');" title="${n.RIGHT_HAND?n.RIGHT_HAND.name:n.TWO_HANDED?n.TWO_HANDED.name:""}">\n    ${n.RIGHT_HAND?n.RIGHT_HAND.name:n.TWO_HANDED?n.TWO_HANDED.name:"R_HAND"}\n    </td>\n  </tr>\n  <tr>\n    <td>\n    </td>\n    <td style="background-image: url('${e}');" title="${n.LEGS?n.LEGS.name:""}">\n    ${n.LEGS?n.LEGS.name:"LEGS"}\n    </td>\n    <td>\n    </td>\n  </tr>\n  </table>\n  `}(t.inventory)}\n      <div id="extra-inventory-info">\n        ${T()}\n      </div>\n    </div>\n    <div id="inventory-section" class="filter-container">\n      <nav class="filter" id="inventory-section">\n        <a href="#" data-filter="ARMOUR" class="${"ARMOUR"===e?"active":""}">Armour</a>\n        <a href="#" data-filter="WEAPON" class="${"WEAPON"===e?"active":""}">Weapons</a>\n        <a href="#" data-filter="SPELL" class="${"SPELL"===e?"active":""}">Spells</a>\n      </nav>\n      <div class="inventory-listing listing">\n        <div class="filter-result ${"ARMOUR"===e?"active":"hidden"}" id="filter_ARMOUR">\n          ${F(n.ARMOUR)}\n        </div>\n        <div class="filter-result ${"WEAPON"===e?"active":"hidden"}" id="filter_WEAPON">\n          ${F(n.WEAPON)}\n        </div>\n        <div class="filter-result ${"SPELL"===e?"active":"hidden"}" id="filter_SPELL">\n          ${F(n.SPELL)}\n        </div>\n      </div>\n    </div>\n  </div>\n  `;(0,c.default)("#inventory").html(r)})),(0,c.default)("body").on("click",".equip-item",(t=>{t.preventDefault(),t.stopPropagation();const e=(0,c.default)(t.target),n=e.data("id"),r=e.data("slot");w.emit("equip",{id:n,slot:r})})),(0,c.default)("body").on("click",".unequip-item",(t=>{t.preventDefault(),t.stopPropagation(),w.emit("unequip",{id:(0,c.default)(t.target).data("id")})})),C.on("renderMap",(function(t){return s(this,void 0,void 0,(function*(){if(!t&&b.has("currentMapHTML"))return void(0,c.default)("#map").html(b.get("currentMapHTML"));t||console.error("oh no.. this got triggered without any city data"),j(t.city.id);const e={SERVICES:[],STORES:[],EXPLORE:[]};t.locations.forEach((t=>{e[t.type].push(`<a href="#" class="city-emit-event" data-event="${t.event_name}" data-args="${t.id}">${t.name}</a>`)}));let n=`<h1>${t.city.name}</h1>\n  <div class="city-details">`;e.SERVICES.length&&(n+=`<div><h3>Services</h3>${e.SERVICES.join("<br>")}</div>`),e.STORES.length&&(n+=`<div><h3>Stores</h3>${e.STORES.join("<br>")}</div>`),e.EXPLORE.length&&(n+=`<div><h3>Explore</h3>${e.EXPLORE.join("<br>")}</div>`),n+=`\n    <div>\n      <h3>Travel</h3>\n      ${t.paths.map((t=>`<a href="#" class="city-emit-event" data-event="city:travel" data-args="${t.ending_city}">${t.ending_city_name}</a>`)).join("<br>")}\n    </div>\n  </div>\n  `,b.set("currentMapHTML",n),(0,c.default)("#map").html(n)}))})),w.on("city:stores",(t=>{const e={},n=new Set;t.forEach((t=>{"ARMOUR"===t.type?(n.add(t.equipment_slot),e[t.equipment_slot]||(e[t.equipment_slot]=""),e[t.equipment_slot]+=R(t,(t=>`<button type="button" class="purchase-item" data-id="${t.id}" data-type="${t.type}" data-equipment-slot="${t.equipment_slot}" data-cost="${t.cost}">Buy</button>`))):(n.add(t.type),e[t.type]||(e[t.type]=""),e[t.type]+=R(t,(t=>`<button type="button" class="purchase-item" data-id="${t.id}" data-type="${t.type}" data-equipment-slot="${t.equipment_slot}" data-cost="${t.cost}">Buy</button>`)))}));const r=Object.keys(e);let i=b.get("active-shop-inventory-listing");r.includes(i)||(i=r[0]);const o=[],s=[];n.forEach((t=>{o.push(`<a href="#" data-filter="${t}" class="${i===t?"active":""}">${(0,p.capitalize)(t)}</a>`),s.push(`<div class="filter-result ${i===t?"active":"hidden"}" id="filter_${t}">${e[t]}</div>`)}));let a=`<div class="shop-inventory-listing filter-container">\n    <nav class="filter" id="shop-inventory-listing">${o.join(" ")}</nav><div class="inventory-listing listing">\n      ${s.join("\n")}\n    </div>\n  </div>`;(0,c.default)("#map").html(a)})),(0,c.default)("body").on("click",".purchase-item",(t=>{t.preventDefault(),t.stopPropagation();const e=b.get("player"),n=parseInt((0,c.default)(t.target).data("cost")),r=(0,c.default)(t.target).data("id");e.gold<n?C.emit("alert",[{type:"error",text:"You don't have enough gold!"}]):((0,c.default)(t.target).data("type"),w.emit("purchase",{id:r}))})),(0,c.default)("body").on("click",".emit-event",(t=>{const e=(0,c.default)(t.target),n=e.data("event"),r=e.data("args"),i=e.data("block");i&&(parseInt(i)||0)>Date.now()?O("Sorry, clicked too quick"):(console.log(`Sending event ${n}`,{args:r}),w.emit(n,{args:r}))})),(0,c.default)("body").on("click",".city-emit-event",(t=>{const e=(0,c.default)(t.target),n=e.data("event"),r=e.data("args");console.log(`Sending event ${n}`,{args:r}),w.emit(n,{args:r})})),(0,c.default)("body").on("click",".emit-event-internal",(t=>{var e;const n=(0,c.default)(t.target),r=n.data("event"),i=null===(e=n.data("args"))||void 0===e?void 0:e.toString().split("|");console.log(`Trigger internal event [${r}]`),C.emit(r,i)})),w.on("explore:fights",(t=>{const e=b.get("last-selected-monster");if(t.length){let n=`<form id="fight-selector"><select id="monster-selector">\n    ${t.map((t=>`<option value="${t.id}" ${e==t.id?"selected":""}>${t.name}</option>`)).join("\n")}\n    </select> <button type="submit">Fight</button></option>`;(0,c.default)("#map").html(n)}})),C.on("tab:explore",(()=>s(void 0,void 0,void 0,(function*(){const t=b.get("state");if(b.get("player").hp<=0||!t.fight&&!t.travel){let e;(!b.has("currentMapHTML")||b.get("player").hp<=0)&&(e=yield f.http.get(`/city/${b.get("player").city_id}`)),C.emit("renderMap",[e,t.travel])}else t.fight?(j(t.closestTown),(0,c.default)("#map").html(L(t.fight))):t.travel&&C.emit("renderTravel",[t.travel])})))),C.on("renderTravel",(function(t){j(t.closestTown);let e=t.walkingText;const n=t.nextAction||0;let r='<div id="travelling">';r+='<div id="travelling-actions">',r+=`<button class="emit-event" id="keep-walking" data-event="travel:step" data-block="${n}">Keep Walking</button>`,t.things.length&&(e=`You see a ${t.things[0].name}`,r+=`<button class="emit-event-internal" data-event="startFight" data-args="${t.things[0].id}|travel">Fight</button>`),r+="</div>",r+=`<p>${e}</p>`,r+="</div>",(0,c.default)("#map").html(r),n&&M()})),w.on("updatePlayer",(t=>{b.set("player",t),x()})),w.on("fight-over",(t=>{const{roundData:e,monsters:n}=t;b.set("player",e.player),x(),(0,c.default)("#map").html(L(e.monster));let r=e.roundDetails.map((t=>`<div>${t}</div>`));if("player"===e.winner&&(r.push(`<div>You defeated the ${e.monster.name}!</div>`),e.rewards.gold&&r.push(`<div>You gained ${e.rewards.gold} gold`),e.rewards.exp&&r.push(`<div>You gained ${e.rewards.exp} exp`),e.rewards.levelIncrease&&r.push(`<div>You gained a level! ${e.player.level}`)),0===e.player.hp)r.push("<p>You were killed...</p>"),r.push('<p><button class="emit-event-internal" data-event="tab:explore" data-args="">Back to Town</button></p>');else switch(e.fightTrigger){case"explore":if(n.length){const t=b.get("last-selected-monster");r.unshift(`<h2>Fight Again</h2><form id="fight-selector"><select id="monster-selector">\n            ${n.map((e=>`<option value="${e.id}" ${t==e.id?"selected":""}>${e.name}</option>`)).join("\n")}\n            </select> <button type="submit">Fight</button></option>\n          </select></form><hr>`)}break;case"travel":r.push('<p><button class="emit-event" data-event="travel:step">Keep Walking</button></p>');break;default:console.error(`Unknown fight trigger [${e.fightTrigger}]`,e)}(0,c.default)("#fight-results").html(r.join("\n")),(0,c.default)("#fight-actions").html("")})),w.on("fight-round",(t=>{(0,c.default)(".fight-action").prop("disabled",!1),b.set("player",t.player),x(),(0,c.default)("#map").html(L(t.monster)),(0,c.default)("#fight-results").html(t.roundDetails.map((t=>`<div>${t}</div>`)).join("\n"))})),C.on("startFight",N),(0,c.default)("body").on("submit","#fight-selector",(t=>s(void 0,void 0,void 0,(function*(){t.preventDefault(),t.stopPropagation();const e=(0,c.default)("#monster-selector option:selected").val();e?N(e.toString()):console.error(`Invalid monster id [${e}]`)})))),(0,c.default)("body").on("click",".fight-action",(t=>{t.preventDefault(),t.stopPropagation();const e=(0,c.default)(t.target).data("action"),n=(0,c.default)("#fight-target option:selected").val();(0,c.default)(".fight-action").prop("disabled",!0),w.emit("fight",{action:e,target:n})})),(0,c.default)("body").on("submit","#signup",(t=>s(void 0,void 0,void 0,(function*(){t.preventDefault(),t.stopPropagation();const e={};(0,c.default)(t.target).serializeArray().forEach((t=>e[t.name]=t.value));const n=yield f.http.post("/signup",e);n.error?C.emit("alert",[{type:"error",text:n.error}]):(b.set("player",n.player),x(),(0,c.default)("#signup-prompt").remove())})))),(0,c.default)("body").on("click","#login",(t=>s(void 0,void 0,void 0,(function*(){t.preventDefault(),t.stopPropagation();const e={};if((0,c.default)(t.target).closest("form").serializeArray().forEach((t=>e[t.name]=t.value)),e.username&&e.password){const t=yield f.http.post("/login",e);t.error?C.emit("alert",[{type:"error",text:t.error}]):(localStorage.setItem("authToken",t.player.id),window.location.reload())}})))),(0,c.default)("body").on("click","#logout",(t=>s(void 0,void 0,void 0,(function*(){t.preventDefault(),t.stopPropagation();let e=!1;const n=b.get("player");e=!/^Player[\d]+$/.test(n.username)||!!confirm("Are you sure? You will not be able to retrieve this character unless you set up an email/password"),e&&(w.emit("logout"),localStorage.clear(),window.location.reload())}))))},1916:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.SocketEvent=void 0,e.SocketEvent=class{constructor(t,e){this.eventName=t,this.handler=e}}},7355:function(t,e,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(t,e,n,r){void 0===r&&(r=n);var i=Object.getOwnPropertyDescriptor(e,n);i&&!("get"in i?!e.__esModule:i.writable||i.configurable)||(i={enumerable:!0,get:function(){return e[n]}}),Object.defineProperty(t,r,i)}:function(t,e,n,r){void 0===r&&(r=n),t[r]=e[n]}),i=this&&this.__exportStar||function(t,e){for(var n in t)"default"===n||Object.prototype.hasOwnProperty.call(e,n)||r(e,t,n)};Object.defineProperty(e,"__esModule",{value:!0}),i(n(5127),e),i(n(6041),e),i(n(9261),e)},9261:function(t,e,n){"use strict";var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.displayHealerDetauls=void 0;const i=n(1916),o=r(n(3336));e.displayHealerDetauls=new i.SocketEvent("city:service:healer",((t,e)=>{(0,o.default)("#map").html(e.text)}))},5127:function(t,e,n){"use strict";var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.professionChangeRogue=e.professionChangeMage=e.professionChangeWarrior=e.professionRecruiter=void 0;const i=n(1916),o=r(n(3336)),s=n(9554);function a(t,e){(0,o.default)("#map").html(e.text)}e.professionRecruiter=new i.SocketEvent(s.EVENT_NAME,a),e.professionChangeWarrior=new i.SocketEvent(`${s.EVENT_NAME}:warrior`,a),e.professionChangeMage=new i.SocketEvent(`${s.EVENT_NAME}:mage`,a),e.professionChangeRogue=new i.SocketEvent(`${s.EVENT_NAME}:rogue`,a)},9554:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.EVENT_NAME=void 0,e.EVENT_NAME="city:services:profession_recruitor_windcross"},6041:function(t,e,n){"use strict";var r=this&&this.__awaiter||function(t,e,n,r){return new(n||(n=Promise))((function(i,o){function s(t){try{u(r.next(t))}catch(t){o(t)}}function a(t){try{u(r.throw(t))}catch(t){o(t)}}function u(t){var e;t.done?i(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(s,a)}u((r=r.apply(t,e||[])).next())}))};Object.defineProperty(e,"__esModule",{value:!0}),e.renderCity=e.travel=void 0;const i=n(1916);e.travel=new i.SocketEvent("city:travel",((t,e)=>{t.events.emit("renderTravel",[e])})),e.renderCity=new i.SocketEvent("city:display",((t,e)=>r(void 0,void 0,void 0,(function*(){t.cache.delete("currentMapHTML"),t.events.emit("renderMap",[e])}))))},4738:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.StatDef=e.expToLevel=e.maxHp=void 0;const r=n(1407);e.maxHp=function(t,e){return Math.ceil(1.3*(t+e))},e.expToLevel=function(t){return t<10?10*t-10:13*t},e.StatDef=new Map,e.StatDef.set(r.Stat.strength,{id:r.Stat.strength,display:"Strength",abbrv:"STR"}),e.StatDef.set(r.Stat.constitution,{id:r.Stat.constitution,display:"Constitution",abbrv:"CON"}),e.StatDef.set(r.Stat.dexterity,{id:r.Stat.dexterity,display:"Dexterity",abbrv:"DEX"}),e.StatDef.set(r.Stat.intelligence,{id:r.Stat.intelligence,display:"Intelligence",abbrv:"INT"})},9502:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Skills=void 0,e.Skills=new Map,e.Skills.set("bladed",{id:"bladed",display:"Bladed Weapon Mastery",description:"Improves Bladed Weapon damage",effect:t=>t.level/100,expToLevel:t=>1e3*t}),e.Skills.set("blunt",{id:"blunt",display:"Blunt Weapons Mastery",description:"Improves Blunt Weapon damage",effect:t=>t.level/100,expToLevel:t=>1e3*t}),e.Skills.set("destruction_magic",{id:"destruction_magic",display:"Destruction Magic Mastery",description:"Improves Destruction Magic damage",effect:t=>t.level/100,expToLevel:t=>1e3*t}),e.Skills.set("restoration_magic",{id:"restoration_magic",display:"Restoration Magic Mastery",description:"Improves effectiveness of Restoration Magic",effect:t=>t.level/100,expToLevel:t=>1e3*t}),e.Skills.set("one_handed_mastery",{id:"one_handed_mastery",display:"One Handed Weapon Mastery",description:"Improves effectiveness when fighting using one-handed weapons",effect:t=>t.level/100,expToLevel:t=>1e3*t}),e.Skills.set("two_handed_mastery",{id:"two_handed_mastery",display:"Two Handed Weapon Mastery",description:"Improves effectiveness when fighting using two-handed weapons",effect:t=>t.level/100,expToLevel:t=>1e3*t})},1407:(t,e)=>{"use strict";var n;Object.defineProperty(e,"__esModule",{value:!0}),e.Stat=void 0,(n=e.Stat||(e.Stat={})).strength="strength",n.constitution="constitution",n.dexterity="dexterity",n.intelligence="intelligence"},8182:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.TimeManager=void 0,e.TimeManager=class{constructor(t=120){this.dayLength=t,this.scaleFactor=30,this.dayLengthAsMS=60*t*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 t=new Date,e=(t.getMinutes()+t.getHours()%2*(this.dayLength/2))/this.dayLength;return Math.floor(24*e)}getHour(){const t=(new Date).getMinutes()/this.dayLength,e=Math.floor(24*t);return e>12?e-12:e}gradientName(){const t=Math.floor(this.get24Hour()/24*this.scaleFactor);return`sky-gradient-${t<10?"0":""}${t}`}isNight(){const t=this.get24Hour();return t>=0&&t<5||t>=22&&t<24}isMorning(){const t=this.get24Hour();return t>=5&&t<12}isAfternoon(){const t=this.get24Hour();return t>=12&&t<18}isEvening(){const t=this.get24Hour();return t>=18&&t<21}}},7429:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"NIL",{enumerable:!0,get:function(){return a.default}}),Object.defineProperty(e,"parse",{enumerable:!0,get:function(){return f.default}}),Object.defineProperty(e,"stringify",{enumerable:!0,get:function(){return l.default}}),Object.defineProperty(e,"v1",{enumerable:!0,get:function(){return r.default}}),Object.defineProperty(e,"v3",{enumerable:!0,get:function(){return i.default}}),Object.defineProperty(e,"v4",{enumerable:!0,get:function(){return o.default}}),Object.defineProperty(e,"v5",{enumerable:!0,get:function(){return s.default}}),Object.defineProperty(e,"validate",{enumerable:!0,get:function(){return c.default}}),Object.defineProperty(e,"version",{enumerable:!0,get:function(){return u.default}});var r=d(n(3990)),i=d(n(8237)),o=d(n(5355)),s=d(n(3764)),a=d(n(6314)),u=d(n(8464)),c=d(n(6435)),l=d(n(4008)),f=d(n(8222));function d(t){return t&&t.__esModule?t:{default:t}}},4163:(t,e)=>{"use strict";function n(t){return 14+(t+64>>>9<<4)+1}function r(t,e){const n=(65535&t)+(65535&e);return(t>>16)+(e>>16)+(n>>16)<<16|65535&n}function i(t,e,n,i,o,s){return r((a=r(r(e,t),r(i,s)))<<(u=o)|a>>>32-u,n);var a,u}function o(t,e,n,r,o,s,a){return i(e&n|~e&r,t,e,o,s,a)}function s(t,e,n,r,o,s,a){return i(e&r|n&~r,t,e,o,s,a)}function a(t,e,n,r,o,s,a){return i(e^n^r,t,e,o,s,a)}function u(t,e,n,r,o,s,a){return i(n^(e|~r),t,e,o,s,a)}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;e.default=function(t){if("string"==typeof t){const e=unescape(encodeURIComponent(t));t=new Uint8Array(e.length);for(let n=0;n<e.length;++n)t[n]=e.charCodeAt(n)}return function(t){const e=[],n=32*t.length,r="0123456789abcdef";for(let i=0;i<n;i+=8){const n=t[i>>5]>>>i%32&255,o=parseInt(r.charAt(n>>>4&15)+r.charAt(15&n),16);e.push(o)}return e}(function(t,e){t[e>>5]|=128<<e%32,t[n(e)-1]=e;let i=1732584193,c=-271733879,l=-1732584194,f=271733878;for(let e=0;e<t.length;e+=16){const n=i,d=c,h=l,p=f;i=o(i,c,l,f,t[e],7,-680876936),f=o(f,i,c,l,t[e+1],12,-389564586),l=o(l,f,i,c,t[e+2],17,606105819),c=o(c,l,f,i,t[e+3],22,-1044525330),i=o(i,c,l,f,t[e+4],7,-176418897),f=o(f,i,c,l,t[e+5],12,1200080426),l=o(l,f,i,c,t[e+6],17,-1473231341),c=o(c,l,f,i,t[e+7],22,-45705983),i=o(i,c,l,f,t[e+8],7,1770035416),f=o(f,i,c,l,t[e+9],12,-1958414417),l=o(l,f,i,c,t[e+10],17,-42063),c=o(c,l,f,i,t[e+11],22,-1990404162),i=o(i,c,l,f,t[e+12],7,1804603682),f=o(f,i,c,l,t[e+13],12,-40341101),l=o(l,f,i,c,t[e+14],17,-1502002290),c=o(c,l,f,i,t[e+15],22,1236535329),i=s(i,c,l,f,t[e+1],5,-165796510),f=s(f,i,c,l,t[e+6],9,-1069501632),l=s(l,f,i,c,t[e+11],14,643717713),c=s(c,l,f,i,t[e],20,-373897302),i=s(i,c,l,f,t[e+5],5,-701558691),f=s(f,i,c,l,t[e+10],9,38016083),l=s(l,f,i,c,t[e+15],14,-660478335),c=s(c,l,f,i,t[e+4],20,-405537848),i=s(i,c,l,f,t[e+9],5,568446438),f=s(f,i,c,l,t[e+14],9,-1019803690),l=s(l,f,i,c,t[e+3],14,-187363961),c=s(c,l,f,i,t[e+8],20,1163531501),i=s(i,c,l,f,t[e+13],5,-1444681467),f=s(f,i,c,l,t[e+2],9,-51403784),l=s(l,f,i,c,t[e+7],14,1735328473),c=s(c,l,f,i,t[e+12],20,-1926607734),i=a(i,c,l,f,t[e+5],4,-378558),f=a(f,i,c,l,t[e+8],11,-2022574463),l=a(l,f,i,c,t[e+11],16,1839030562),c=a(c,l,f,i,t[e+14],23,-35309556),i=a(i,c,l,f,t[e+1],4,-1530992060),f=a(f,i,c,l,t[e+4],11,1272893353),l=a(l,f,i,c,t[e+7],16,-155497632),c=a(c,l,f,i,t[e+10],23,-1094730640),i=a(i,c,l,f,t[e+13],4,681279174),f=a(f,i,c,l,t[e],11,-358537222),l=a(l,f,i,c,t[e+3],16,-722521979),c=a(c,l,f,i,t[e+6],23,76029189),i=a(i,c,l,f,t[e+9],4,-640364487),f=a(f,i,c,l,t[e+12],11,-421815835),l=a(l,f,i,c,t[e+15],16,530742520),c=a(c,l,f,i,t[e+2],23,-995338651),i=u(i,c,l,f,t[e],6,-198630844),f=u(f,i,c,l,t[e+7],10,1126891415),l=u(l,f,i,c,t[e+14],15,-1416354905),c=u(c,l,f,i,t[e+5],21,-57434055),i=u(i,c,l,f,t[e+12],6,1700485571),f=u(f,i,c,l,t[e+3],10,-1894986606),l=u(l,f,i,c,t[e+10],15,-1051523),c=u(c,l,f,i,t[e+1],21,-2054922799),i=u(i,c,l,f,t[e+8],6,1873313359),f=u(f,i,c,l,t[e+15],10,-30611744),l=u(l,f,i,c,t[e+6],15,-1560198380),c=u(c,l,f,i,t[e+13],21,1309151649),i=u(i,c,l,f,t[e+4],6,-145523070),f=u(f,i,c,l,t[e+11],10,-1120210379),l=u(l,f,i,c,t[e+2],15,718787259),c=u(c,l,f,i,t[e+9],21,-343485551),i=r(i,n),c=r(c,d),l=r(l,h),f=r(f,p)}return[i,c,l,f]}(function(t){if(0===t.length)return[];const e=8*t.length,r=new Uint32Array(n(e));for(let n=0;n<e;n+=8)r[n>>5]|=(255&t[n/8])<<n%32;return r}(t),8*t.length))}},4790:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var n={randomUUID:"undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};e.default=n},6314:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0,e.default="00000000-0000-0000-0000-000000000000"},8222:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var r,i=(r=n(6435))&&r.__esModule?r:{default:r};e.default=function(t){if(!(0,i.default)(t))throw TypeError("Invalid UUID");let e;const n=new Uint8Array(16);return n[0]=(e=parseInt(t.slice(0,8),16))>>>24,n[1]=e>>>16&255,n[2]=e>>>8&255,n[3]=255&e,n[4]=(e=parseInt(t.slice(9,13),16))>>>8,n[5]=255&e,n[6]=(e=parseInt(t.slice(14,18),16))>>>8,n[7]=255&e,n[8]=(e=parseInt(t.slice(19,23),16))>>>8,n[9]=255&e,n[10]=(e=parseInt(t.slice(24,36),16))/1099511627776&255,n[11]=e/4294967296&255,n[12]=e>>>24&255,n[13]=e>>>16&255,n[14]=e>>>8&255,n[15]=255&e,n}},58:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0,e.default=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i},3319:(t,e)=>{"use strict";let n;Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(){if(!n&&(n="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!n))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return n(r)};const r=new Uint8Array(16)},3757:(t,e)=>{"use strict";function n(t,e,n,r){switch(t){case 0:return e&n^~e&r;case 1:case 3:return e^n^r;case 2:return e&n^e&r^n&r}}function r(t,e){return t<<e|t>>>32-e}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;e.default=function(t){const e=[1518500249,1859775393,2400959708,3395469782],i=[1732584193,4023233417,2562383102,271733878,3285377520];if("string"==typeof t){const e=unescape(encodeURIComponent(t));t=[];for(let n=0;n<e.length;++n)t.push(e.charCodeAt(n))}else Array.isArray(t)||(t=Array.prototype.slice.call(t));t.push(128);const o=t.length/4+2,s=Math.ceil(o/16),a=new Array(s);for(let e=0;e<s;++e){const n=new Uint32Array(16);for(let r=0;r<16;++r)n[r]=t[64*e+4*r]<<24|t[64*e+4*r+1]<<16|t[64*e+4*r+2]<<8|t[64*e+4*r+3];a[e]=n}a[s-1][14]=8*(t.length-1)/Math.pow(2,32),a[s-1][14]=Math.floor(a[s-1][14]),a[s-1][15]=8*(t.length-1)&4294967295;for(let t=0;t<s;++t){const o=new Uint32Array(80);for(let e=0;e<16;++e)o[e]=a[t][e];for(let t=16;t<80;++t)o[t]=r(o[t-3]^o[t-8]^o[t-14]^o[t-16],1);let s=i[0],u=i[1],c=i[2],l=i[3],f=i[4];for(let t=0;t<80;++t){const i=Math.floor(t/20),a=r(s,5)+n(i,u,c,l)+f+e[i]+o[t]>>>0;f=l,l=c,c=r(u,30)>>>0,u=s,s=a}i[0]=i[0]+s>>>0,i[1]=i[1]+u>>>0,i[2]=i[2]+c>>>0,i[3]=i[3]+l>>>0,i[4]=i[4]+f>>>0}return[i[0]>>24&255,i[0]>>16&255,i[0]>>8&255,255&i[0],i[1]>>24&255,i[1]>>16&255,i[1]>>8&255,255&i[1],i[2]>>24&255,i[2]>>16&255,i[2]>>8&255,255&i[2],i[3]>>24&255,i[3]>>16&255,i[3]>>8&255,255&i[3],i[4]>>24&255,i[4]>>16&255,i[4]>>8&255,255&i[4]]}},4008:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0,e.unsafeStringify=s;var r,i=(r=n(6435))&&r.__esModule?r:{default:r};const o=[];for(let t=0;t<256;++t)o.push((t+256).toString(16).slice(1));function s(t,e=0){return(o[t[e+0]]+o[t[e+1]]+o[t[e+2]]+o[t[e+3]]+"-"+o[t[e+4]]+o[t[e+5]]+"-"+o[t[e+6]]+o[t[e+7]]+"-"+o[t[e+8]]+o[t[e+9]]+"-"+o[t[e+10]]+o[t[e+11]]+o[t[e+12]]+o[t[e+13]]+o[t[e+14]]+o[t[e+15]]).toLowerCase()}e.default=function(t,e=0){const n=s(t,e);if(!(0,i.default)(n))throw TypeError("Stringified UUID is invalid");return n}},3990:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var r,i=(r=n(3319))&&r.__esModule?r:{default:r},o=n(4008);let s,a,u=0,c=0;e.default=function(t,e,n){let r=e&&n||0;const l=e||new Array(16);let f=(t=t||{}).node||s,d=void 0!==t.clockseq?t.clockseq:a;if(null==f||null==d){const e=t.random||(t.rng||i.default)();null==f&&(f=s=[1|e[0],e[1],e[2],e[3],e[4],e[5]]),null==d&&(d=a=16383&(e[6]<<8|e[7]))}let h=void 0!==t.msecs?t.msecs:Date.now(),p=void 0!==t.nsecs?t.nsecs:c+1;const g=h-u+(p-c)/1e4;if(g<0&&void 0===t.clockseq&&(d=d+1&16383),(g<0||h>u)&&void 0===t.nsecs&&(p=0),p>=1e4)throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");u=h,c=p,a=d,h+=122192928e5;const v=(1e4*(268435455&h)+p)%4294967296;l[r++]=v>>>24&255,l[r++]=v>>>16&255,l[r++]=v>>>8&255,l[r++]=255&v;const y=h/4294967296*1e4&268435455;l[r++]=y>>>8&255,l[r++]=255&y,l[r++]=y>>>24&15|16,l[r++]=y>>>16&255,l[r++]=d>>>8|128,l[r++]=255&d;for(let t=0;t<6;++t)l[r+t]=f[t];return e||(0,o.unsafeStringify)(l)}},8237:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var r=o(n(7925)),i=o(n(4163));function o(t){return t&&t.__esModule?t:{default:t}}var s=(0,r.default)("v3",48,i.default);e.default=s},7925:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.URL=e.DNS=void 0,e.default=function(t,e,n){function r(t,r,s,a){var u;if("string"==typeof t&&(t=function(t){t=unescape(encodeURIComponent(t));const e=[];for(let n=0;n<t.length;++n)e.push(t.charCodeAt(n));return e}(t)),"string"==typeof r&&(r=(0,o.default)(r)),16!==(null===(u=r)||void 0===u?void 0:u.length))throw TypeError("Namespace must be array-like (16 iterable integer values, 0-255)");let c=new Uint8Array(16+t.length);if(c.set(r),c.set(t,r.length),c=n(c),c[6]=15&c[6]|e,c[8]=63&c[8]|128,s){a=a||0;for(let t=0;t<16;++t)s[a+t]=c[t];return s}return(0,i.unsafeStringify)(c)}try{r.name=t}catch(t){}return r.DNS=s,r.URL=a,r};var r,i=n(4008),o=(r=n(8222))&&r.__esModule?r:{default:r};const s="6ba7b810-9dad-11d1-80b4-00c04fd430c8";e.DNS=s;const a="6ba7b811-9dad-11d1-80b4-00c04fd430c8";e.URL=a},5355:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var r=s(n(4790)),i=s(n(3319)),o=n(4008);function s(t){return t&&t.__esModule?t:{default:t}}e.default=function(t,e,n){if(r.default.randomUUID&&!e&&!t)return r.default.randomUUID();const s=(t=t||{}).random||(t.rng||i.default)();if(s[6]=15&s[6]|64,s[8]=63&s[8]|128,e){n=n||0;for(let t=0;t<16;++t)e[n+t]=s[t];return e}return(0,o.unsafeStringify)(s)}},3764:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var r=o(n(7925)),i=o(n(3757));function o(t){return t&&t.__esModule?t:{default:t}}var s=(0,r.default)("v5",80,i.default);e.default=s},6435:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var r,i=(r=n(58))&&r.__esModule?r:{default:r};e.default=function(t){return"string"==typeof t&&i.default.test(t)}},8464:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0;var r,i=(r=n(6435))&&r.__esModule?r:{default:r};e.default=function(t){if(!(0,i.default)(t))throw TypeError("Invalid UUID");return parseInt(t.slice(14,15),16)}},3336:t=>{"use strict";t.exports=$},8419:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.hasCORS=void 0;let n=!1;try{n="undefined"!=typeof XMLHttpRequest&&"withCredentials"in new XMLHttpRequest}catch(t){}e.hasCORS=n},5754:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.decode=e.encode=void 0,e.encode=function(t){let e="";for(let n in t)t.hasOwnProperty(n)&&(e.length&&(e+="&"),e+=encodeURIComponent(n)+"="+encodeURIComponent(t[n]));return e},e.decode=function(t){let e={},n=t.split("&");for(let t=0,r=n.length;t<r;t++){let r=n[t].split("=");e[decodeURIComponent(r[0])]=decodeURIComponent(r[1])}return e}},5222:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.parse=void 0;const n=/^(?:(?![^:@\/?#]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@\/?#]*)(?::([^:@\/?#]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,r=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"];e.parse=function(t){const e=t,i=t.indexOf("["),o=t.indexOf("]");-1!=i&&-1!=o&&(t=t.substring(0,i)+t.substring(i,o).replace(/:/g,";")+t.substring(o,t.length));let s=n.exec(t||""),a={},u=14;for(;u--;)a[r[u]]=s[u]||"";return-1!=i&&-1!=o&&(a.source=e,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(t,e){const n=e.replace(/\/{2,9}/g,"/").split("/");return"/"!=e.slice(0,1)&&0!==e.length||n.splice(0,1),"/"==e.slice(-1)&&n.splice(n.length-1,1),n}(0,a.path),a.queryKey=function(t,e){const n={};return e.replace(/(?:^|&)([^&=]*)=?([^&]*)/g,(function(t,e,r){e&&(n[e]=r)})),n}(0,a.query),a}},8726:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.yeast=e.decode=e.encode=void 0;const n="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(""),r={};let i,o=0,s=0;function a(t){let e="";do{e=n[t%64]+e,t=Math.floor(t/64)}while(t>0);return e}for(e.encode=a,e.decode=function(t){let e=0;for(s=0;s<t.length;s++)e=64*e+r[t.charAt(s)];return e},e.yeast=function(){const t=a(+new Date);return t!==i?(o=0,i=t):t+"."+a(o++)};s<64;s++)r[n[s]]=s},6242:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.globalThisShim=void 0,e.globalThisShim="undefined"!=typeof self?self:"undefined"!=typeof window?window:Function("return this")()},4679:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.nextTick=e.parse=e.installTimerFunctions=e.transports=e.Transport=e.protocol=e.Socket=void 0;const r=n(3481);Object.defineProperty(e,"Socket",{enumerable:!0,get:function(){return r.Socket}}),e.protocol=r.Socket.protocol;var i=n(9870);Object.defineProperty(e,"Transport",{enumerable:!0,get:function(){return i.Transport}});var o=n(7385);Object.defineProperty(e,"transports",{enumerable:!0,get:function(){return o.transports}});var s=n(9622);Object.defineProperty(e,"installTimerFunctions",{enumerable:!0,get:function(){return s.installTimerFunctions}});var a=n(5222);Object.defineProperty(e,"parse",{enumerable:!0,get:function(){return a.parse}});var u=n(5552);Object.defineProperty(e,"nextTick",{enumerable:!0,get:function(){return u.nextTick}})},3481:function(t,e,n){"use strict";var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.Socket=void 0;const i=n(7385),o=n(9622),s=n(5754),a=n(5222),u=r(n(4802)),c=n(5260),l=n(1373),f=(0,u.default)("engine.io-client:socket");class d extends c.Emitter{constructor(t,e={}){super(),this.writeBuffer=[],t&&"object"==typeof t&&(e=t,t=null),t?(t=(0,a.parse)(t),e.hostname=t.host,e.secure="https"===t.protocol||"wss"===t.protocol,e.port=t.port,t.query&&(e.query=t.query)):e.host&&(e.hostname=(0,a.parse)(e.host).host),(0,o.installTimerFunctions)(this,e),this.secure=null!=e.secure?e.secure:"undefined"!=typeof location&&"https:"===location.protocol,e.hostname&&!e.port&&(e.port=this.secure?"443":"80"),this.hostname=e.hostname||("undefined"!=typeof location?location.hostname:"localhost"),this.port=e.port||("undefined"!=typeof location&&location.port?location.port:this.secure?"443":"80"),this.transports=e.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},e),this.opts.path=this.opts.path.replace(/\/$/,"")+(this.opts.addTrailingSlash?"/":""),"string"==typeof this.opts.query&&(this.opts.query=(0,s.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(t){f('creating transport "%s"',t);const e=Object.assign({},this.opts.query);e.EIO=l.protocol,e.transport=t,this.id&&(e.sid=this.id);const n=Object.assign({},this.opts.transportOptions[t],this.opts,{query:e,socket:this,hostname:this.hostname,secure:this.secure,port:this.port});return f("options: %j",n),new i.transports[t](n)}open(){let t;if(this.opts.rememberUpgrade&&d.priorWebsocketSuccess&&-1!==this.transports.indexOf("websocket"))t="websocket";else{if(0===this.transports.length)return void this.setTimeoutFn((()=>{this.emitReserved("error","No transports available")}),0);t=this.transports[0]}this.readyState="opening";try{t=this.createTransport(t)}catch(t){return f("error while creating transport: %s",t),this.transports.shift(),void this.open()}t.open(),this.setTransport(t)}setTransport(t){f("setting transport %s",t.name),this.transport&&(f("clearing existing transport %s",this.transport.name),this.transport.removeAllListeners()),this.transport=t,t.on("drain",this.onDrain.bind(this)).on("packet",this.onPacket.bind(this)).on("error",this.onError.bind(this)).on("close",(t=>this.onClose("transport close",t)))}probe(t){f('probing transport "%s"',t);let e=this.createTransport(t),n=!1;d.priorWebsocketSuccess=!1;const r=()=>{n||(f('probe transport "%s" opened',t),e.send([{type:"ping",data:"probe"}]),e.once("packet",(r=>{if(!n)if("pong"===r.type&&"probe"===r.data){if(f('probe transport "%s" pong',t),this.upgrading=!0,this.emitReserved("upgrading",e),!e)return;d.priorWebsocketSuccess="websocket"===e.name,f('pausing current transport "%s"',this.transport.name),this.transport.pause((()=>{n||"closed"!==this.readyState&&(f("changing transport and sending upgrade packet"),c(),this.setTransport(e),e.send([{type:"upgrade"}]),this.emitReserved("upgrade",e),e=null,this.upgrading=!1,this.flush())}))}else{f('probe transport "%s" failed',t);const n=new Error("probe error");n.transport=e.name,this.emitReserved("upgradeError",n)}})))};function i(){n||(n=!0,c(),e.close(),e=null)}const o=n=>{const r=new Error("probe error: "+n);r.transport=e.name,i(),f('probe transport "%s" failed because of error: %s',t,n),this.emitReserved("upgradeError",r)};function s(){o("transport closed")}function a(){o("socket closed")}function u(t){e&&t.name!==e.name&&(f('"%s" works - aborting "%s"',t.name,e.name),i())}const c=()=>{e.removeListener("open",r),e.removeListener("error",o),e.removeListener("close",s),this.off("close",a),this.off("upgrading",u)};e.once("open",r),e.once("error",o),e.once("close",s),this.once("close",a),this.once("upgrading",u),e.open()}onOpen(){if(f("socket open"),this.readyState="open",d.priorWebsocketSuccess="websocket"===this.transport.name,this.emitReserved("open"),this.flush(),"open"===this.readyState&&this.opts.upgrade){f("starting upgrade probes");let t=0;const e=this.upgrades.length;for(;t<e;t++)this.probe(this.upgrades[t])}}onPacket(t){if("opening"===this.readyState||"open"===this.readyState||"closing"===this.readyState)switch(f('socket receive: type "%s", data "%s"',t.type,t.data),this.emitReserved("packet",t),this.emitReserved("heartbeat"),t.type){case"open":this.onHandshake(JSON.parse(t.data));break;case"ping":this.resetPingTimeout(),this.sendPacket("pong"),this.emitReserved("ping"),this.emitReserved("pong");break;case"error":const e=new Error("server error");e.code=t.data,this.onError(e);break;case"message":this.emitReserved("data",t.data),this.emitReserved("message",t.data)}else f('packet received with socket readyState "%s"',this.readyState)}onHandshake(t){this.emitReserved("handshake",t),this.id=t.sid,this.transport.query.sid=t.sid,this.upgrades=this.filterUpgrades(t.upgrades),this.pingInterval=t.pingInterval,this.pingTimeout=t.pingTimeout,this.maxPayload=t.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 t=this.getWritablePackets();f("flushing %d packets in socket",t.length),this.transport.send(t),this.prevBufferLen=t.length,this.emitReserved("flush")}}getWritablePackets(){if(!(this.maxPayload&&"polling"===this.transport.name&&this.writeBuffer.length>1))return this.writeBuffer;let t=1;for(let e=0;e<this.writeBuffer.length;e++){const n=this.writeBuffer[e].data;if(n&&(t+=(0,o.byteLength)(n)),e>0&&t>this.maxPayload)return f("only send %d out of %d packets",e,this.writeBuffer.length),this.writeBuffer.slice(0,e);t+=2}return f("payload size is %d (max: %d)",t,this.maxPayload),this.writeBuffer}write(t,e,n){return this.sendPacket("message",t,e,n),this}send(t,e,n){return this.sendPacket("message",t,e,n),this}sendPacket(t,e,n,r){if("function"==typeof e&&(r=e,e=void 0),"function"==typeof n&&(r=n,n=null),"closing"===this.readyState||"closed"===this.readyState)return;(n=n||{}).compress=!1!==n.compress;const i={type:t,data:e,options:n};this.emitReserved("packetCreate",i),this.writeBuffer.push(i),r&&this.once("flush",r),this.flush()}close(){const t=()=>{this.onClose("forced close"),f("socket closing - telling transport to close"),this.transport.close()},e=()=>{this.off("upgrade",e),this.off("upgradeError",e),t()},n=()=>{this.once("upgrade",e),this.once("upgradeError",e)};return"opening"!==this.readyState&&"open"!==this.readyState||(this.readyState="closing",this.writeBuffer.length?this.once("drain",(()=>{this.upgrading?n():t()})):this.upgrading?n():t()),this}onError(t){f("socket error %j",t),d.priorWebsocketSuccess=!1,this.emitReserved("error",t),this.onClose("transport error",t)}onClose(t,e){"opening"!==this.readyState&&"open"!==this.readyState&&"closing"!==this.readyState||(f('socket close with reason: "%s"',t),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",t,e),this.writeBuffer=[],this.prevBufferLen=0)}filterUpgrades(t){const e=[];let n=0;const r=t.length;for(;n<r;n++)~this.transports.indexOf(t[n])&&e.push(t[n]);return e}}e.Socket=d,d.protocol=l.protocol},9870:function(t,e,n){"use strict";var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.Transport=void 0;const i=n(1373),o=n(5260),s=n(9622),a=(0,r(n(4802)).default)("engine.io-client:transport");class u extends Error{constructor(t,e,n){super(t),this.description=e,this.context=n,this.type="TransportError"}}class c extends o.Emitter{constructor(t){super(),this.writable=!1,(0,s.installTimerFunctions)(this,t),this.opts=t,this.query=t.query,this.socket=t.socket}onError(t,e,n){return super.emitReserved("error",new u(t,e,n)),this}open(){return this.readyState="opening",this.doOpen(),this}close(){return"opening"!==this.readyState&&"open"!==this.readyState||(this.doClose(),this.onClose()),this}send(t){"open"===this.readyState?this.write(t):a("transport is not open, discarding packets")}onOpen(){this.readyState="open",this.writable=!0,super.emitReserved("open")}onData(t){const e=(0,i.decodePacket)(t,this.socket.binaryType);this.onPacket(e)}onPacket(t){super.emitReserved("packet",t)}onClose(t){this.readyState="closed",super.emitReserved("close",t)}pause(t){}}e.Transport=c},7385:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.transports=void 0;const r=n(484),i=n(1308);e.transports={websocket:i.WS,polling:r.Polling}},484:function(t,e,n){"use strict";var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.Request=e.Polling=void 0;const i=n(9870),o=r(n(4802)),s=n(8726),a=n(5754),u=n(1373),c=n(6666),l=n(5260),f=n(9622),d=n(6242),h=(0,o.default)("engine.io-client:polling");function p(){}const g=null!=new c.XHR({xdomain:!1}).responseType;class v extends i.Transport{constructor(t){if(super(t),this.polling=!1,"undefined"!=typeof location){const e="https:"===location.protocol;let n=location.port;n||(n=e?"443":"80"),this.xd="undefined"!=typeof location&&t.hostname!==location.hostname||n!==t.port,this.xs=t.secure!==e}const e=t&&t.forceBase64;this.supportsBinary=g&&!e}get name(){return"polling"}doOpen(){this.poll()}pause(t){this.readyState="pausing";const e=()=>{h("paused"),this.readyState="paused",t()};if(this.polling||!this.writable){let t=0;this.polling&&(h("we are currently polling - waiting to pause"),t++,this.once("pollComplete",(function(){h("pre-pause polling complete"),--t||e()}))),this.writable||(h("we are currently writing - waiting to pause"),t++,this.once("drain",(function(){h("pre-pause writing complete"),--t||e()})))}else e()}poll(){h("polling"),this.polling=!0,this.doPoll(),this.emitReserved("poll")}onData(t){h("polling got data %s",t),(0,u.decodePayload)(t,this.socket.binaryType).forEach((t=>{if("opening"===this.readyState&&"open"===t.type&&this.onOpen(),"close"===t.type)return this.onClose({description:"transport closed by the server"}),!1;this.onPacket(t)})),"closed"!==this.readyState&&(this.polling=!1,this.emitReserved("pollComplete"),"open"===this.readyState?this.poll():h('ignoring poll - transport state "%s"',this.readyState))}doClose(){const t=()=>{h("writing close packet"),this.write([{type:"close"}])};"open"===this.readyState?(h("transport open - closing"),t()):(h("transport not open - deferring close"),this.once("open",t))}write(t){this.writable=!1,(0,u.encodePayload)(t,(t=>{this.doWrite(t,(()=>{this.writable=!0,this.emitReserved("drain")}))}))}uri(){let t=this.query||{};const e=this.opts.secure?"https":"http";let n="";!1!==this.opts.timestampRequests&&(t[this.opts.timestampParam]=(0,s.yeast)()),this.supportsBinary||t.sid||(t.b64=1),this.opts.port&&("https"===e&&443!==Number(this.opts.port)||"http"===e&&80!==Number(this.opts.port))&&(n=":"+this.opts.port);const r=(0,a.encode)(t);return e+"://"+(-1!==this.opts.hostname.indexOf(":")?"["+this.opts.hostname+"]":this.opts.hostname)+n+this.opts.path+(r.length?"?"+r:"")}request(t={}){return Object.assign(t,{xd:this.xd,xs:this.xs},this.opts),new y(this.uri(),t)}doWrite(t,e){const n=this.request({method:"POST",data:t});n.on("success",e),n.on("error",((t,e)=>{this.onError("xhr post error",t,e)}))}doPoll(){h("xhr poll");const t=this.request();t.on("data",this.onData.bind(this)),t.on("error",((t,e)=>{this.onError("xhr poll error",t,e)})),this.pollXhr=t}}e.Polling=v;class y extends l.Emitter{constructor(t,e){super(),(0,f.installTimerFunctions)(this,e),this.opts=e,this.method=e.method||"GET",this.uri=t,this.async=!1!==e.async,this.data=void 0!==e.data?e.data:null,this.create()}create(){const t=(0,f.pick)(this.opts,"agent","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","autoUnref");t.xdomain=!!this.opts.xd,t.xscheme=!!this.opts.xs;const e=this.xhr=new c.XHR(t);try{h("xhr open %s: %s",this.method,this.uri),e.open(this.method,this.uri,this.async);try{if(this.opts.extraHeaders){e.setDisableHeaderCheck&&e.setDisableHeaderCheck(!0);for(let t in this.opts.extraHeaders)this.opts.extraHeaders.hasOwnProperty(t)&&e.setRequestHeader(t,this.opts.extraHeaders[t])}}catch(t){}if("POST"===this.method)try{e.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(t){}try{e.setRequestHeader("Accept","*/*")}catch(t){}"withCredentials"in e&&(e.withCredentials=this.opts.withCredentials),this.opts.requestTimeout&&(e.timeout=this.opts.requestTimeout),e.onreadystatechange=()=>{4===e.readyState&&(200===e.status||1223===e.status?this.onLoad():this.setTimeoutFn((()=>{this.onError("number"==typeof e.status?e.status:0)}),0))},h("xhr data %s",this.data),e.send(this.data)}catch(t){return void this.setTimeoutFn((()=>{this.onError(t)}),0)}"undefined"!=typeof document&&(this.index=y.requestsCount++,y.requests[this.index]=this)}onError(t){this.emitReserved("error",t,this.xhr),this.cleanup(!0)}cleanup(t){if(void 0!==this.xhr&&null!==this.xhr){if(this.xhr.onreadystatechange=p,t)try{this.xhr.abort()}catch(t){}"undefined"!=typeof document&&delete y.requests[this.index],this.xhr=null}}onLoad(){const t=this.xhr.responseText;null!==t&&(this.emitReserved("data",t),this.emitReserved("success"),this.cleanup())}abort(){this.cleanup()}}if(e.Request=y,y.requestsCount=0,y.requests={},"undefined"!=typeof document)if("function"==typeof attachEvent)attachEvent("onunload",m);else if("function"==typeof addEventListener){const t="onpagehide"in d.globalThisShim?"pagehide":"unload";addEventListener(t,m,!1)}function m(){for(let t in y.requests)y.requests.hasOwnProperty(t)&&y.requests[t].abort()}},5552:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.defaultBinaryType=e.usingBrowserWebSocket=e.WebSocket=e.nextTick=void 0;const r=n(6242);e.nextTick="function"==typeof Promise&&"function"==typeof Promise.resolve?t=>Promise.resolve().then(t):(t,e)=>e(t,0),e.WebSocket=r.globalThisShim.WebSocket||r.globalThisShim.MozWebSocket,e.usingBrowserWebSocket=!0,e.defaultBinaryType="arraybuffer"},1308:function(t,e,n){"use strict";var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.WS=void 0;const i=n(9870),o=n(5754),s=n(8726),a=n(9622),u=n(5552),c=r(n(4802)),l=n(1373),f=(0,c.default)("engine.io-client:websocket"),d="undefined"!=typeof navigator&&"string"==typeof navigator.product&&"reactnative"===navigator.product.toLowerCase();class h extends i.Transport{constructor(t){super(t),this.supportsBinary=!t.forceBase64}get name(){return"websocket"}doOpen(){if(!this.check())return;const t=this.uri(),e=this.opts.protocols,n=d?{}:(0,a.pick)(this.opts,"agent","perMessageDeflate","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized","localAddress","protocolVersion","origin","maxPayload","family","checkServerIdentity");this.opts.extraHeaders&&(n.headers=this.opts.extraHeaders);try{this.ws=u.usingBrowserWebSocket&&!d?e?new u.WebSocket(t,e):new u.WebSocket(t):new u.WebSocket(t,e,n)}catch(t){return this.emitReserved("error",t)}this.ws.binaryType=this.socket.binaryType||u.defaultBinaryType,this.addEventListeners()}addEventListeners(){this.ws.onopen=()=>{this.opts.autoUnref&&this.ws._socket.unref(),this.onOpen()},this.ws.onclose=t=>this.onClose({description:"websocket connection closed",context:t}),this.ws.onmessage=t=>this.onData(t.data),this.ws.onerror=t=>this.onError("websocket error",t)}write(t){this.writable=!1;for(let e=0;e<t.length;e++){const n=t[e],r=e===t.length-1;(0,l.encodePacket)(n,this.supportsBinary,(t=>{const e={};!u.usingBrowserWebSocket&&(n.options&&(e.compress=n.options.compress),this.opts.perMessageDeflate)&&("string"==typeof t?Buffer.byteLength(t):t.length)<this.opts.perMessageDeflate.threshold&&(e.compress=!1);try{u.usingBrowserWebSocket?this.ws.send(t):this.ws.send(t,e)}catch(t){f("websocket closed before onclose event")}r&&(0,u.nextTick)((()=>{this.writable=!0,this.emitReserved("drain")}),this.setTimeoutFn)}))}}doClose(){void 0!==this.ws&&(this.ws.close(),this.ws=null)}uri(){let t=this.query||{};const e=this.opts.secure?"wss":"ws";let n="";this.opts.port&&("wss"===e&&443!==Number(this.opts.port)||"ws"===e&&80!==Number(this.opts.port))&&(n=":"+this.opts.port),this.opts.timestampRequests&&(t[this.opts.timestampParam]=(0,s.yeast)()),this.supportsBinary||(t.b64=1);const r=(0,o.encode)(t);return e+"://"+(-1!==this.opts.hostname.indexOf(":")?"["+this.opts.hostname+"]":this.opts.hostname)+n+this.opts.path+(r.length?"?"+r:"")}check(){return!!u.WebSocket}}e.WS=h},6666:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.XHR=void 0;const r=n(8419),i=n(6242);e.XHR=function(t){const e=t.xdomain;try{if("undefined"!=typeof XMLHttpRequest&&(!e||r.hasCORS))return new XMLHttpRequest}catch(t){}if(!e)try{return new(i.globalThisShim[["Active"].concat("Object").join("X")])("Microsoft.XMLHTTP")}catch(t){}}},9622:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.byteLength=e.installTimerFunctions=e.pick=void 0;const r=n(6242);e.pick=function(t,...e){return e.reduce(((e,n)=>(t.hasOwnProperty(n)&&(e[n]=t[n]),e)),{})};const i=r.globalThisShim.setTimeout,o=r.globalThisShim.clearTimeout;e.installTimerFunctions=function(t,e){e.useNativeTimers?(t.setTimeoutFn=i.bind(r.globalThisShim),t.clearTimeoutFn=o.bind(r.globalThisShim)):(t.setTimeoutFn=r.globalThisShim.setTimeout.bind(r.globalThisShim),t.clearTimeoutFn=r.globalThisShim.clearTimeout.bind(r.globalThisShim))},e.byteLength=function(t){return"string"==typeof t?function(t){let e=0,n=0;for(let r=0,i=t.length;r<i;r++)e=t.charCodeAt(r),e<128?n+=1:e<2048?n+=2:e<55296||e>=57344?n+=3:(r++,n+=4);return n}(t):Math.ceil(1.33*(t.byteLength||t.size))}},3087:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.ERROR_PACKET=e.PACKET_TYPES_REVERSE=e.PACKET_TYPES=void 0;const n=Object.create(null);e.PACKET_TYPES=n,n.open="0",n.close="1",n.ping="2",n.pong="3",n.message="4",n.upgrade="5",n.noop="6";const r=Object.create(null);e.PACKET_TYPES_REVERSE=r,Object.keys(n).forEach((t=>{r[n[t]]=t})),e.ERROR_PACKET={type:"error",data:"parser error"}},2469:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.decode=e.encode=void 0;const n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",r="undefined"==typeof Uint8Array?[]:new Uint8Array(256);for(let t=0;t<64;t++)r[n.charCodeAt(t)]=t;e.encode=t=>{let e,r=new Uint8Array(t),i=r.length,o="";for(e=0;e<i;e+=3)o+=n[r[e]>>2],o+=n[(3&r[e])<<4|r[e+1]>>4],o+=n[(15&r[e+1])<<2|r[e+2]>>6],o+=n[63&r[e+2]];return i%3==2?o=o.substring(0,o.length-1)+"=":i%3==1&&(o=o.substring(0,o.length-2)+"=="),o},e.decode=t=>{let e,n,i,o,s,a=.75*t.length,u=t.length,c=0;"="===t[t.length-1]&&(a--,"="===t[t.length-2]&&a--);const l=new ArrayBuffer(a),f=new Uint8Array(l);for(e=0;e<u;e+=4)n=r[t.charCodeAt(e)],i=r[t.charCodeAt(e+1)],o=r[t.charCodeAt(e+2)],s=r[t.charCodeAt(e+3)],f[c++]=n<<2|i>>4,f[c++]=(15&i)<<4|o>>2,f[c++]=(3&o)<<6|63&s;return l}},7572:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0});const r=n(3087),i=n(2469),o="function"==typeof ArrayBuffer,s=(t,e)=>{if(o){const n=(0,i.decode)(t);return a(n,e)}return{base64:!0,data:t}},a=(t,e)=>"blob"===e&&t instanceof ArrayBuffer?new Blob([t]):t;e.default=(t,e)=>{if("string"!=typeof t)return{type:"message",data:a(t,e)};const n=t.charAt(0);return"b"===n?{type:"message",data:s(t.substring(1),e)}:r.PACKET_TYPES_REVERSE[n]?t.length>1?{type:r.PACKET_TYPES_REVERSE[n],data:t.substring(1)}:{type:r.PACKET_TYPES_REVERSE[n]}:r.ERROR_PACKET}},3908:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0});const r=n(3087),i="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===Object.prototype.toString.call(Blob),o="function"==typeof ArrayBuffer,s=(t,e)=>{const n=new FileReader;return n.onload=function(){const t=n.result.split(",")[1];e("b"+(t||""))},n.readAsDataURL(t)};e.default=({type:t,data:e},n,a)=>{return i&&e instanceof Blob?n?a(e):s(e,a):o&&(e instanceof ArrayBuffer||(u=e,"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(u):u&&u.buffer instanceof ArrayBuffer))?n?a(e):s(new Blob([e]),a):a(r.PACKET_TYPES[t]+(e||""));var u}},1373:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.decodePayload=e.decodePacket=e.encodePayload=e.encodePacket=e.protocol=void 0;const r=n(3908);e.encodePacket=r.default;const i=n(7572);e.decodePacket=i.default;const o=String.fromCharCode(30);e.encodePayload=(t,e)=>{const n=t.length,i=new Array(n);let s=0;t.forEach(((t,a)=>{(0,r.default)(t,!1,(t=>{i[a]=t,++s===n&&e(i.join(o))}))}))},e.decodePayload=(t,e)=>{const n=t.split(o),r=[];for(let t=0;t<n.length;t++){const o=(0,i.default)(n[t],e);if(r.push(o),"error"===o.type)break}return r},e.protocol=4},5159:(t,e)=>{"use strict";function n(t){t=t||{},this.ms=t.min||100,this.max=t.max||1e4,this.factor=t.factor||2,this.jitter=t.jitter>0&&t.jitter<=1?t.jitter:0,this.attempts=0}Object.defineProperty(e,"__esModule",{value:!0}),e.Backoff=void 0,e.Backoff=n,n.prototype.duration=function(){var t=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var e=Math.random(),n=Math.floor(e*this.jitter*t);t=0==(1&Math.floor(10*e))?t-n:t+n}return 0|Math.min(t,this.max)},n.prototype.reset=function(){this.attempts=0},n.prototype.setMin=function(t){this.ms=t},n.prototype.setMax=function(t){this.max=t},n.prototype.setJitter=function(t){this.jitter=t}},7046:function(t,e,n){"use strict";var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.connect=e.io=e.Socket=e.Manager=e.protocol=void 0;const i=n(3084),o=n(4168);Object.defineProperty(e,"Manager",{enumerable:!0,get:function(){return o.Manager}});const s=n(8312);Object.defineProperty(e,"Socket",{enumerable:!0,get:function(){return s.Socket}});const a=r(n(3669)).default("socket.io-client"),u={};function c(t,e){"object"==typeof t&&(e=t,t=void 0),e=e||{};const n=i.url(t,e.path||"/socket.io"),r=n.source,s=n.id,c=n.path,l=u[s]&&c in u[s].nsps;let f;return e.forceNew||e["force new connection"]||!1===e.multiplex||l?(a("ignoring socket cache for %s",r),f=new o.Manager(r,e)):(u[s]||(a("new io instance for %s",r),u[s]=new o.Manager(r,e)),f=u[s]),n.query&&!e.query&&(e.query=n.queryKey),f.socket(n.path,e)}e.io=c,e.connect=c,e.default=c,Object.assign(c,{Manager:o.Manager,Socket:s.Socket,io:c,connect:c});var l=n(4514);Object.defineProperty(e,"protocol",{enumerable:!0,get:function(){return l.protocol}}),t.exports=c},4168:function(t,e,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(t,e,n,r){void 0===r&&(r=n),Object.defineProperty(t,r,{enumerable:!0,get:function(){return e[n]}})}:function(t,e,n,r){void 0===r&&(r=n),t[r]=e[n]}),i=this&&this.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),o=this&&this.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var n in t)"default"!==n&&Object.prototype.hasOwnProperty.call(t,n)&&r(e,t,n);return i(e,t),e},s=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.Manager=void 0;const a=n(4679),u=n(8312),c=o(n(4514)),l=n(7149),f=n(5159),d=n(5260),h=s(n(3669)).default("socket.io-client:manager");class p extends d.Emitter{constructor(t,e){var n;super(),this.nsps={},this.subs=[],t&&"object"==typeof t&&(e=t,t=void 0),(e=e||{}).path=e.path||"/socket.io",this.opts=e,a.installTimerFunctions(this,e),this.reconnection(!1!==e.reconnection),this.reconnectionAttempts(e.reconnectionAttempts||1/0),this.reconnectionDelay(e.reconnectionDelay||1e3),this.reconnectionDelayMax(e.reconnectionDelayMax||5e3),this.randomizationFactor(null!==(n=e.randomizationFactor)&&void 0!==n?n:.5),this.backoff=new f.Backoff({min:this.reconnectionDelay(),max:this.reconnectionDelayMax(),jitter:this.randomizationFactor()}),this.timeout(null==e.timeout?2e4:e.timeout),this._readyState="closed",this.uri=t;const r=e.parser||c;this.encoder=new r.Encoder,this.decoder=new r.Decoder,this._autoConnect=!1!==e.autoConnect,this._autoConnect&&this.open()}reconnection(t){return arguments.length?(this._reconnection=!!t,this):this._reconnection}reconnectionAttempts(t){return void 0===t?this._reconnectionAttempts:(this._reconnectionAttempts=t,this)}reconnectionDelay(t){var e;return void 0===t?this._reconnectionDelay:(this._reconnectionDelay=t,null===(e=this.backoff)||void 0===e||e.setMin(t),this)}randomizationFactor(t){var e;return void 0===t?this._randomizationFactor:(this._randomizationFactor=t,null===(e=this.backoff)||void 0===e||e.setJitter(t),this)}reconnectionDelayMax(t){var e;return void 0===t?this._reconnectionDelayMax:(this._reconnectionDelayMax=t,null===(e=this.backoff)||void 0===e||e.setMax(t),this)}timeout(t){return arguments.length?(this._timeout=t,this):this._timeout}maybeReconnectOnOpen(){!this._reconnecting&&this._reconnection&&0===this.backoff.attempts&&this.reconnect()}open(t){if(h("readyState %s",this._readyState),~this._readyState.indexOf("open"))return this;h("opening %s",this.uri),this.engine=new a.Socket(this.uri,this.opts);const e=this.engine,n=this;this._readyState="opening",this.skipReconnect=!1;const r=l.on(e,"open",(function(){n.onopen(),t&&t()})),i=l.on(e,"error",(e=>{h("error"),n.cleanup(),n._readyState="closed",this.emitReserved("error",e),t?t(e):n.maybeReconnectOnOpen()}));if(!1!==this._timeout){const t=this._timeout;h("connect attempt will timeout after %d",t),0===t&&r();const n=this.setTimeoutFn((()=>{h("connect attempt timed out after %d",t),r(),e.close(),e.emit("error",new Error("timeout"))}),t);this.opts.autoUnref&&n.unref(),this.subs.push((function(){clearTimeout(n)}))}return this.subs.push(r),this.subs.push(i),this}connect(t){return this.open(t)}onopen(){h("open"),this.cleanup(),this._readyState="open",this.emitReserved("open");const t=this.engine;this.subs.push(l.on(t,"ping",this.onping.bind(this)),l.on(t,"data",this.ondata.bind(this)),l.on(t,"error",this.onerror.bind(this)),l.on(t,"close",this.onclose.bind(this)),l.on(this.decoder,"decoded",this.ondecoded.bind(this)))}onping(){this.emitReserved("ping")}ondata(t){try{this.decoder.add(t)}catch(t){this.onclose("parse error",t)}}ondecoded(t){a.nextTick((()=>{this.emitReserved("packet",t)}),this.setTimeoutFn)}onerror(t){h("error",t),this.emitReserved("error",t)}socket(t,e){let n=this.nsps[t];return n?this._autoConnect&&!n.active&&n.connect():(n=new u.Socket(this,t,e),this.nsps[t]=n),n}_destroy(t){const e=Object.keys(this.nsps);for(const t of e)if(this.nsps[t].active)return void h("socket %s is still active, skipping close",t);this._close()}_packet(t){h("writing packet %j",t);const e=this.encoder.encode(t);for(let n=0;n<e.length;n++)this.engine.write(e[n],t.options)}cleanup(){h("cleanup"),this.subs.forEach((t=>t())),this.subs.length=0,this.decoder.destroy()}_close(){h("disconnect"),this.skipReconnect=!0,this._reconnecting=!1,this.onclose("forced close"),this.engine&&this.engine.close()}disconnect(){return this._close()}onclose(t,e){h("closed due to %s",t),this.cleanup(),this.backoff.reset(),this._readyState="closed",this.emitReserved("close",t,e),this._reconnection&&!this.skipReconnect&&this.reconnect()}reconnect(){if(this._reconnecting||this.skipReconnect)return this;const t=this;if(this.backoff.attempts>=this._reconnectionAttempts)h("reconnect failed"),this.backoff.reset(),this.emitReserved("reconnect_failed"),this._reconnecting=!1;else{const e=this.backoff.duration();h("will wait %dms before reconnect attempt",e),this._reconnecting=!0;const n=this.setTimeoutFn((()=>{t.skipReconnect||(h("attempting reconnect"),this.emitReserved("reconnect_attempt",t.backoff.attempts),t.skipReconnect||t.open((e=>{e?(h("reconnect attempt error"),t._reconnecting=!1,t.reconnect(),this.emitReserved("reconnect_error",e)):(h("reconnect success"),t.onreconnect())})))}),e);this.opts.autoUnref&&n.unref(),this.subs.push((function(){clearTimeout(n)}))}}onreconnect(){const t=this.backoff.attempts;this._reconnecting=!1,this.backoff.reset(),this.emitReserved("reconnect",t)}}e.Manager=p},7149:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.on=void 0,e.on=function(t,e,n){return t.on(e,n),function(){t.off(e,n)}}},8312:function(t,e,n){"use strict";var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.Socket=void 0;const i=n(4514),o=n(7149),s=n(5260),a=r(n(3669)).default("socket.io-client:socket"),u=Object.freeze({connect:1,connect_error:1,disconnect:1,disconnecting:1,newListener:1,removeListener:1});class c extends s.Emitter{constructor(t,e,n){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=t,this.nsp=e,n&&n.auth&&(this.auth=n.auth),this._opts=Object.assign({},n),this.io._autoConnect&&this.open()}get disconnected(){return!this.connected}subEvents(){if(this.subs)return;const t=this.io;this.subs=[o.on(t,"open",this.onopen.bind(this)),o.on(t,"packet",this.onpacket.bind(this)),o.on(t,"error",this.onerror.bind(this)),o.on(t,"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(...t){return t.unshift("message"),this.emit.apply(this,t),this}emit(t,...e){if(u.hasOwnProperty(t))throw new Error('"'+t.toString()+'" is a reserved event name');if(e.unshift(t),this._opts.retries&&!this.flags.fromQueue&&!this.flags.volatile)return this._addToQueue(e),this;const n={type:i.PacketType.EVENT,data:e,options:{}};if(n.options.compress=!1!==this.flags.compress,"function"==typeof e[e.length-1]){const t=this.ids++;a("emitting packet with ack id %d",t);const r=e.pop();this._registerAckCallback(t,r),n.id=t}const r=this.io.engine&&this.io.engine.transport&&this.io.engine.transport.writable;return!this.flags.volatile||r&&this.connected?this.connected?(this.notifyOutgoingListeners(n),this.packet(n)):this.sendBuffer.push(n):a("discard packet as the transport is not currently writable"),this.flags={},this}_registerAckCallback(t,e){var n;const r=null!==(n=this.flags.timeout)&&void 0!==n?n:this._opts.ackTimeout;if(void 0===r)return void(this.acks[t]=e);const i=this.io.setTimeoutFn((()=>{delete this.acks[t];for(let e=0;e<this.sendBuffer.length;e++)this.sendBuffer[e].id===t&&(a("removing packet with ack id %d from the buffer",t),this.sendBuffer.splice(e,1));a("event with ack id %d has timed out after %d ms",t,r),e.call(this,new Error("operation has timed out"))}),r);this.acks[t]=(...t)=>{this.io.clearTimeoutFn(i),e.apply(this,[null,...t])}}emitWithAck(t,...e){const n=void 0!==this.flags.timeout||void 0!==this._opts.ackTimeout;return new Promise(((r,i)=>{e.push(((t,e)=>n?t?i(t):r(e):r(t))),this.emit(t,...e)}))}_addToQueue(t){let e;"function"==typeof t[t.length-1]&&(e=t.pop());const n={id:this._queueSeq++,tryCount:0,pending:!1,args:t,flags:Object.assign({fromQueue:!0},this.flags)};t.push(((t,...r)=>{if(n===this._queue[0])return null!==t?n.tryCount>this._opts.retries&&(a("packet [%d] is discarded after %d tries",n.id,n.tryCount),this._queue.shift(),e&&e(t)):(a("packet [%d] was successfully sent",n.id),this._queue.shift(),e&&e(null,...r)),n.pending=!1,this._drainQueue()})),this._queue.push(n),this._drainQueue()}_drainQueue(t=!1){if(a("draining queue"),!this.connected||0===this._queue.length)return;const e=this._queue[0];!e.pending||t?(e.pending=!0,e.tryCount++,a("sending packet [%d] (try n°%d)",e.id,e.tryCount),this.flags=e.flags,this.emit.apply(this,e.args)):a("packet [%d] has already been sent and is waiting for an ack",e.id)}packet(t){t.nsp=this.nsp,this.io._packet(t)}onopen(){a("transport is open - connecting"),"function"==typeof this.auth?this.auth((t=>{this._sendConnectPacket(t)})):this._sendConnectPacket(this.auth)}_sendConnectPacket(t){this.packet({type:i.PacketType.CONNECT,data:this._pid?Object.assign({pid:this._pid,offset:this._lastOffset},t):t})}onerror(t){this.connected||this.emitReserved("connect_error",t)}onclose(t,e){a("close (%s)",t),this.connected=!1,delete this.id,this.emitReserved("disconnect",t,e)}onpacket(t){if(t.nsp===this.nsp)switch(t.type){case i.PacketType.CONNECT:t.data&&t.data.sid?this.onconnect(t.data.sid,t.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 i.PacketType.EVENT:case i.PacketType.BINARY_EVENT:this.onevent(t);break;case i.PacketType.ACK:case i.PacketType.BINARY_ACK:this.onack(t);break;case i.PacketType.DISCONNECT:this.ondisconnect();break;case i.PacketType.CONNECT_ERROR:this.destroy();const e=new Error(t.data.message);e.data=t.data.data,this.emitReserved("connect_error",e)}}onevent(t){const e=t.data||[];a("emitting event %j",e),null!=t.id&&(a("attaching ack callback to event"),e.push(this.ack(t.id))),this.connected?this.emitEvent(e):this.receiveBuffer.push(Object.freeze(e))}emitEvent(t){if(this._anyListeners&&this._anyListeners.length){const e=this._anyListeners.slice();for(const n of e)n.apply(this,t)}super.emit.apply(this,t),this._pid&&t.length&&"string"==typeof t[t.length-1]&&(this._lastOffset=t[t.length-1])}ack(t){const e=this;let n=!1;return function(...r){n||(n=!0,a("sending ack %j",r),e.packet({type:i.PacketType.ACK,id:t,data:r}))}}onack(t){const e=this.acks[t.id];"function"==typeof e?(a("calling ack %s with %j",t.id,t.data),e.apply(this,t.data),delete this.acks[t.id]):a("bad ack %s",t.id)}onconnect(t,e){a("socket connected with id %s",t),this.id=t,this.recovered=e&&this._pid===e,this._pid=e,this.connected=!0,this.emitBuffered(),this.emitReserved("connect"),this._drainQueue(!0)}emitBuffered(){this.receiveBuffer.forEach((t=>this.emitEvent(t))),this.receiveBuffer=[],this.sendBuffer.forEach((t=>{this.notifyOutgoingListeners(t),this.packet(t)})),this.sendBuffer=[]}ondisconnect(){a("server disconnect (%s)",this.nsp),this.destroy(),this.onclose("io server disconnect")}destroy(){this.subs&&(this.subs.forEach((t=>t())),this.subs=void 0),this.io._destroy(this)}disconnect(){return this.connected&&(a("performing disconnect (%s)",this.nsp),this.packet({type:i.PacketType.DISCONNECT})),this.destroy(),this.connected&&this.onclose("io client disconnect"),this}close(){return this.disconnect()}compress(t){return this.flags.compress=t,this}get volatile(){return this.flags.volatile=!0,this}timeout(t){return this.flags.timeout=t,this}onAny(t){return this._anyListeners=this._anyListeners||[],this._anyListeners.push(t),this}prependAny(t){return this._anyListeners=this._anyListeners||[],this._anyListeners.unshift(t),this}offAny(t){if(!this._anyListeners)return this;if(t){const e=this._anyListeners;for(let n=0;n<e.length;n++)if(t===e[n])return e.splice(n,1),this}else this._anyListeners=[];return this}listenersAny(){return this._anyListeners||[]}onAnyOutgoing(t){return this._anyOutgoingListeners=this._anyOutgoingListeners||[],this._anyOutgoingListeners.push(t),this}prependAnyOutgoing(t){return this._anyOutgoingListeners=this._anyOutgoingListeners||[],this._anyOutgoingListeners.unshift(t),this}offAnyOutgoing(t){if(!this._anyOutgoingListeners)return this;if(t){const e=this._anyOutgoingListeners;for(let n=0;n<e.length;n++)if(t===e[n])return e.splice(n,1),this}else this._anyOutgoingListeners=[];return this}listenersAnyOutgoing(){return this._anyOutgoingListeners||[]}notifyOutgoingListeners(t){if(this._anyOutgoingListeners&&this._anyOutgoingListeners.length){const e=this._anyOutgoingListeners.slice();for(const n of e)n.apply(this,t.data)}}}e.Socket=c},3084:function(t,e,n){"use strict";var r=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.url=void 0;const i=n(4679),o=r(n(3669)).default("socket.io-client:url");e.url=function(t,e="",n){let r=t;n=n||"undefined"!=typeof location&&location,null==t&&(t=n.protocol+"//"+n.host),"string"==typeof t&&("/"===t.charAt(0)&&(t="/"===t.charAt(1)?n.protocol+t:n.host+t),/^(https?|wss?):\/\//.test(t)||(o("protocol-less url %s",t),t=void 0!==n?n.protocol+"//"+t:"https://"+t),o("parse %s",t),r=i.parse(t)),r.port||(/^(http|ws)$/.test(r.protocol)?r.port="80":/^(http|ws)s$/.test(r.protocol)&&(r.port="443")),r.path=r.path||"/";const s=-1!==r.host.indexOf(":")?"["+r.host+"]":r.host;return r.id=r.protocol+"://"+s+":"+r.port+e,r.href=r.protocol+"://"+s+(n&&n.port===r.port?"":":"+r.port),r}},4880:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.reconstructPacket=e.deconstructPacket=void 0;const r=n(665);function i(t,e){if(!t)return t;if((0,r.isBinary)(t)){const n={_placeholder:!0,num:e.length};return e.push(t),n}if(Array.isArray(t)){const n=new Array(t.length);for(let r=0;r<t.length;r++)n[r]=i(t[r],e);return n}if("object"==typeof t&&!(t instanceof Date)){const n={};for(const r in t)Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=i(t[r],e));return n}return t}function o(t,e){if(!t)return t;if(t&&!0===t._placeholder){if("number"==typeof t.num&&t.num>=0&&t.num<e.length)return e[t.num];throw new Error("illegal attachments")}if(Array.isArray(t))for(let n=0;n<t.length;n++)t[n]=o(t[n],e);else if("object"==typeof t)for(const n in t)Object.prototype.hasOwnProperty.call(t,n)&&(t[n]=o(t[n],e));return t}e.deconstructPacket=function(t){const e=[],n=t.data,r=t;return r.data=i(n,e),r.attachments=e.length,{packet:r,buffers:e}},e.reconstructPacket=function(t,e){return t.data=o(t.data,e),delete t.attachments,t}},4514:(t,e,n)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.Decoder=e.Encoder=e.PacketType=e.protocol=void 0;const r=n(5260),i=n(4880),o=n(665),s=(0,n(1618).default)("socket.io-parser");var a;e.protocol=5,function(t){t[t.CONNECT=0]="CONNECT",t[t.DISCONNECT=1]="DISCONNECT",t[t.EVENT=2]="EVENT",t[t.ACK=3]="ACK",t[t.CONNECT_ERROR=4]="CONNECT_ERROR",t[t.BINARY_EVENT=5]="BINARY_EVENT",t[t.BINARY_ACK=6]="BINARY_ACK"}(a=e.PacketType||(e.PacketType={})),e.Encoder=class{constructor(t){this.replacer=t}encode(t){return s("encoding packet %j",t),t.type!==a.EVENT&&t.type!==a.ACK||!(0,o.hasBinary)(t)?[this.encodeAsString(t)]:this.encodeAsBinary({type:t.type===a.EVENT?a.BINARY_EVENT:a.BINARY_ACK,nsp:t.nsp,data:t.data,id:t.id})}encodeAsString(t){let e=""+t.type;return t.type!==a.BINARY_EVENT&&t.type!==a.BINARY_ACK||(e+=t.attachments+"-"),t.nsp&&"/"!==t.nsp&&(e+=t.nsp+","),null!=t.id&&(e+=t.id),null!=t.data&&(e+=JSON.stringify(t.data,this.replacer)),s("encoded %j as %s",t,e),e}encodeAsBinary(t){const e=(0,i.deconstructPacket)(t),n=this.encodeAsString(e.packet),r=e.buffers;return r.unshift(n),r}};class u extends r.Emitter{constructor(t){super(),this.reviver=t}add(t){let e;if("string"==typeof t){if(this.reconstructor)throw new Error("got plaintext data when reconstructing a packet");e=this.decodeString(t);const n=e.type===a.BINARY_EVENT;n||e.type===a.BINARY_ACK?(e.type=n?a.EVENT:a.ACK,this.reconstructor=new c(e),0===e.attachments&&super.emitReserved("decoded",e)):super.emitReserved("decoded",e)}else{if(!(0,o.isBinary)(t)&&!t.base64)throw new Error("Unknown type: "+t);if(!this.reconstructor)throw new Error("got binary data when not reconstructing a packet");e=this.reconstructor.takeBinaryData(t),e&&(this.reconstructor=null,super.emitReserved("decoded",e))}}decodeString(t){let e=0;const n={type:Number(t.charAt(0))};if(void 0===a[n.type])throw new Error("unknown packet type "+n.type);if(n.type===a.BINARY_EVENT||n.type===a.BINARY_ACK){const r=e+1;for(;"-"!==t.charAt(++e)&&e!=t.length;);const i=t.substring(r,e);if(i!=Number(i)||"-"!==t.charAt(e))throw new Error("Illegal attachments");n.attachments=Number(i)}if("/"===t.charAt(e+1)){const r=e+1;for(;++e&&","!==t.charAt(e)&&e!==t.length;);n.nsp=t.substring(r,e)}else n.nsp="/";const r=t.charAt(e+1);if(""!==r&&Number(r)==r){const r=e+1;for(;++e;){const n=t.charAt(e);if(null==n||Number(n)!=n){--e;break}if(e===t.length)break}n.id=Number(t.substring(r,e+1))}if(t.charAt(++e)){const r=this.tryParse(t.substr(e));if(!u.isPayloadValid(n.type,r))throw new Error("invalid payload");n.data=r}return s("decoded %s as %j",t,n),n}tryParse(t){try{return JSON.parse(t,this.reviver)}catch(t){return!1}}static isPayloadValid(t,e){switch(t){case a.CONNECT:return"object"==typeof e;case a.DISCONNECT:return void 0===e;case a.CONNECT_ERROR:return"string"==typeof e||"object"==typeof e;case a.EVENT:case a.BINARY_EVENT:return Array.isArray(e)&&("string"==typeof e[0]||"number"==typeof e[0]);case a.ACK:case a.BINARY_ACK:return Array.isArray(e)}}destroy(){this.reconstructor&&(this.reconstructor.finishedReconstruction(),this.reconstructor=null)}}e.Decoder=u;class c{constructor(t){this.packet=t,this.buffers=[],this.reconPack=t}takeBinaryData(t){if(this.buffers.push(t),this.buffers.length===this.reconPack.attachments){const t=(0,i.reconstructPacket)(this.reconPack,this.buffers);return this.finishedReconstruction(),t}return null}finishedReconstruction(){this.reconPack=null,this.buffers=[]}}},665:(t,e)=>{"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.hasBinary=e.isBinary=void 0;const n="function"==typeof ArrayBuffer,r=Object.prototype.toString,i="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===r.call(Blob),o="function"==typeof File||"undefined"!=typeof File&&"[object FileConstructor]"===r.call(File);function s(t){return n&&(t instanceof ArrayBuffer||(t=>"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(t):t.buffer instanceof ArrayBuffer)(t))||i&&t instanceof Blob||o&&t instanceof File}e.isBinary=s,e.hasBinary=function t(e,n){if(!e||"object"!=typeof e)return!1;if(Array.isArray(e)){for(let n=0,r=e.length;n<r;n++)if(t(e[n]))return!0;return!1}if(s(e))return!0;if(e.toJSON&&"function"==typeof e.toJSON&&1===arguments.length)return t(e.toJSON(),!0);for(const n in e)if(Object.prototype.hasOwnProperty.call(e,n)&&t(e[n]))return!0;return!1}},5260:(t,e,n)=>{"use strict";function r(t){if(t)return function(t){for(var e in r.prototype)t[e]=r.prototype[e];return t}(t)}n.r(e),n.d(e,{Emitter:()=>r}),r.prototype.on=r.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+t]=this._callbacks["$"+t]||[]).push(e),this},r.prototype.once=function(t,e){function n(){this.off(t,n),e.apply(this,arguments)}return n.fn=e,this.on(t,n),this},r.prototype.off=r.prototype.removeListener=r.prototype.removeAllListeners=r.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n,r=this._callbacks["$"+t];if(!r)return this;if(1==arguments.length)return delete this._callbacks["$"+t],this;for(var i=0;i<r.length;i++)if((n=r[i])===e||n.fn===e){r.splice(i,1);break}return 0===r.length&&delete this._callbacks["$"+t],this},r.prototype.emit=function(t){this._callbacks=this._callbacks||{};for(var e=new Array(arguments.length-1),n=this._callbacks["$"+t],r=1;r<arguments.length;r++)e[r-1]=arguments[r];if(n){r=0;for(var i=(n=n.slice(0)).length;r<i;++r)n[r].apply(this,e)}return this},r.prototype.emitReserved=r.prototype.emit,r.prototype.listeners=function(t){return this._callbacks=this._callbacks||{},this._callbacks["$"+t]||[]},r.prototype.hasListeners=function(t){return!!this.listeners(t).length}}},e={};function n(r){var i=e[r];if(void 0!==i)return i.exports;var o=e[r]={id:r,loaded:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.loaded=!0,o.exports}n.d=(t,e)=>{for(var r in e)n.o(e,r)&&!n.o(t,r)&&Object.defineProperty(t,r,{enumerable:!0,get:e[r]})},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),n.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.nmd=t=>(t.paths=[],t.children||(t.children=[]),t),n(2174)})();
\ 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))}},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
index cc8264e2d985f71eda28b1691f241edfe0315d77..edb597de6cf56f460816e988cbbcb57b46ae9b9c 100644 (file)
@@ -25,6 +25,10 @@ body {
   padding: 1rem;
   border: 1px solid #000;
 }
   padding: 1rem;
   border: 1px solid #000;
 }
+:disabled {
+  background-color: #aaa;
+  cursor: not-allowed;
+}
 b {
   font-weight: bold;
 }
 b {
   font-weight: bold;
 }
@@ -45,7 +49,7 @@ button {
   color: #000;
 }
 .hidden {
   color: #000;
 }
 .hidden {
-  display: none;
+  display: none !important;
 }
 p {
   margin-bottom: 1rem;
 }
 p {
   margin-bottom: 1rem;
@@ -71,6 +75,34 @@ section {
   display: flex;
 }
 
   display: flex;
 }
 
+#modal-wrapper {
+  width: 100%;
+  height: 100%;
+  backdrop-filter: blur(10px);
+}
+dialog::backdrop {
+  backdrop-filter: blur(3px);
+
+}
+dialog {
+  background-color: #fff;
+  border: solid 1px #000;
+  padding: 0.5rem;
+  width: 300px;
+  top: 20%;
+  font-size: 0.9rem;
+}
+dialog .modal-header {
+  font-weight: bold;
+  text-align: right;
+}
+dialog .actions {
+  text-align: right;
+}
+dialog .close-modal {
+  cursor: pointer;
+}
+
 @media(max-width: 650px) {
   #signup {
     flex-direction: column;
 @media(max-width: 650px) {
   #signup {
     flex-direction: column;
@@ -219,6 +251,54 @@ nav.filter-result.active {
 #inventory-section .listing {
   top: 2px;
 }
 #inventory-section .listing {
   top: 2px;
 }
+.inventory-listing {
+  min-height: 2rem;
+}
+
+.inventory-ITEMS {
+  display: flex;
+}
+.player-item {
+  position: relative;
+  cursor: pointer;
+  margin: 2px;
+  border: solid 1px #000;
+  width: 64px;
+  height: 64px;
+  overflow: hidden;
+}
+.player-item img {
+  filter: grayscale(40%);
+}
+.player-item img:hover {
+  filter: none;
+}
+.player-item .amount {
+  font-weight: bold;
+  position: absolute;
+  bottom: 0;
+  right: 0;
+  background-color: rgba(255, 255, 255, 0.7);
+  font-size: 0.8rem;
+  padding: 4px;
+  border-radius: 3px 0 0 0;
+}
+.item-modal-overview {
+  display: flex;
+}
+.item-modal-overview .icon {
+  width: 64px;
+  height: 64px;
+  margin: 0 1rem 1rem 0;
+}
+.item-modal-overview .name {
+  margin-top: 0;
+  font-weight: bold;
+  margin: 0 1rem 0.8rem 0;
+}
+.item-modal-overview p {
+  margin: 1rem;
+}
 
 .tab {
   display: none;
 
 .tab {
   display: none;
@@ -248,6 +328,8 @@ nav.filter-result.active {
   background-repeat: no-repeat;
   background-position: bottom right;
   background-size: cover;
   background-repeat: no-repeat;
   background-position: bottom right;
   background-size: cover;
+  padding: 3rem 3rem 2rem;
+  line-height: 1.3rem;
 }
 
 #fight-container {
 }
 
 #fight-container {
diff --git a/public/assets/img/icons/items/Minor_Potion_health.png b/public/assets/img/icons/items/Minor_Potion_health.png
new file mode 100755 (executable)
index 0000000..2e09caa
Binary files /dev/null and b/public/assets/img/icons/items/Minor_Potion_health.png differ
index a8eac157b3899271dd4b3b2f2855d523d637dc0d..83f18c6ea617fe7b7f459e241a8bc3e1ad9c877c 100644 (file)
@@ -10,6 +10,7 @@
     <link rel="stylesheet" href="/assets/css/reset.css">
     <link rel="stylesheet" href="/assets/css/game.css">
     <link rel="stylesheet" href="/assets/css/sky.css">
     <link rel="stylesheet" href="/assets/css/reset.css">
     <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>
     <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>
             <div class="progress-bar" id="exp-bar"></div>
           </div>
           <nav>
             <div class="progress-bar" id="exp-bar"></div>
           </div>
           <nav>
-            <li><a href="#" data-section="inventory" data-container="main-nav">Profile</a></li>
-            <li><a href="#" data-section="skills" data-container="main-nav">Skills</a></li>
-            <li><a href="#" data-section="explore" data-container="main-nav">Explore</a></li>
+            <li><a href="#" class="active" hx-get="/player" hx-target="#profile">Profile</a></li>
+            <li><a href="#" hx-get="/player/inventory" hx-target="#inventory">Inventory</a></li>
+            <li><a href="#" hx-get="/player/skills" hx-target="#skills">Skills</a></li>
+            <li><a href="#" hx-get="/player/explore" hx-target="#explore">Explore</a></li>
           </nav>
         </div>
       </header>
           </nav>
         </div>
       </header>
       <div id="announcements" class="hidden"></div>
 
       <div id="alerts"></div>
       <div id="announcements" class="hidden"></div>
 
       <div id="alerts"></div>
+      <div id="modal-wrapper"></div>
 
       <div id="main-nav">
 
       <div id="main-nav">
+        <section id="profile" class="tab active">PROFILE</section>
         <section id="inventory" class="tab">INVENTORY</section>
         <section id="skills" class="tab">SKILLS</section>
         <section id="explore" class="tab">
         <section id="inventory" class="tab">INVENTORY</section>
         <section id="skills" class="tab">SKILLS</section>
         <section id="explore" class="tab">
@@ -59,9 +63,9 @@
       </div>
 
       <section id="chat">
       </div>
 
       <section id="chat">
-        <div id="chat-messages"></div>
-        <form id="chat-form">
-          <input type="text" id="message" autocomplete="off"><button type="submit">Send</button>
+        <div id="chat-messages" hx-trigger="load delay:1s" hx-get="/chat/history"></div>
+        <form id="chat-form" hx-post="/chat">
+          <input type="text" id="message" name="message" autocomplete="off"><button type="submit">Send</button>
         </form>
       </section>
 
         </form>
       </section>
 
@@ -71,7 +75,7 @@
             <a href="#" data-section="settings" data-container="main-nav">Settings</a>
           </nav>
         </div>
             <a href="#" data-section="settings" data-container="main-nav">Settings</a>
           </nav>
         </div>
-        <div id="server-stats">0 Online - Now</div>
+        <div id="server-stats" hx-trigger="load delay:1s" hx-get="/status" hx-swap="outerHTML">...Loading</div>
       </section>
 
       <footer>Another project by <a href="https://xangelo.ca/gardens/rising-legends/">xangelo.ca</a>. <span id="version"></span></footer>
       </section>
 
       <footer>Another project by <a href="https://xangelo.ca/gardens/rising-legends/">xangelo.ca</a>. <span id="version"></span></footer>
index 6aedb579e6dd9c5a750d1949dbb2975c52d7f926..18a754ccab059027628a0ef946c9ee66eb23fa91 100644 (file)
@@ -10,10 +10,10 @@ Airtable.configure({
 
 const base = Airtable.base('appDfPLPajPNog5Iw');
 
 
 const base = Airtable.base('appDfPLPajPNog5Iw');
 
-export async function createShopItems(): Promise<void> {
+export async function createShopEquipment(): Promise<void> {
   return new Promise(async (resolve) => {
   return new Promise(async (resolve) => {
-    base('Shop Items').select().eachPage(async (records, next) => {
-      await db('shop_items').insert(records.map(r => {
+    base('Shop Equipment').select().eachPage(async (records, next) => {
+      await db('shop_equipment').insert(records.map(r => {
         return {
           id: r.fields.id,
           name: r.fields.Name,
         return {
           id: r.fields.id,
           name: r.fields.Name,
@@ -48,8 +48,40 @@ export async function createShopItems(): Promise<void> {
   });
 }
 
   });
 }
 
+export async function createShopItems(): Promise<void> {
+  return new Promise(async (resolve) => {
+    base('Items').select().eachPage(async (records, next) => {
+      const itemsForSale = [];
+      await db('items').insert(records.map(r => {
+        if(r.fields['location_id']) {
+          itemsForSale.push({
+            item_id: r.fields['Id'],
+            location_id: r.fields['location_id'][0],
+            amount: r.fields['Amount'],
+            price_per_unit: r.fields['Cost']
+          });
+        }
+        return {
+          id: r.fields['Id'],
+          name: r.fields.Name,
+          description: r.fields['Description'],
+          effect_name: r.fields['Effect Name'],
+          icon_name: r.fields['Icon Name']
+        };
+      })).onConflict('id').merge();
+
+      if(itemsForSale.length) {
+        await db('shop_items').insert(itemsForSale).onConflict(['item_id', 'location_id']).merge();
+      }
+
+      next();
+    }).finally(() => resolve());
+  });
+
+}
+
 if(!module.parent) {
 if(!module.parent) {
-  createShopItems().then(() => {
+  createShopEquipment().then(createShopItems).then(() => {
     console.log('Complete');
     process.exit(0);
   }).catch(e => {
     console.log('Complete');
     process.exit(0);
   }).catch(e => {
index 549fbcc92bbd86fc329ac1b16056d3c29ec6125e..287207ede476aca15a086aa1b688a4fd7789e8b9 100644 (file)
@@ -1,53 +1,32 @@
-import $ from 'jquery';
 import {Socket} from 'socket.io-client';
 import {Message} from '../shared/message';
 import {Socket} from 'socket.io-client';
 import {Message} from '../shared/message';
-import { configureDiscordChat } from './discord';
 
 // disable chat temporarily to test widgetbot
 let socket: Socket;
 
 // disable chat temporarily to test widgetbot
 let socket: Socket;
+function $<T>(selector: string, root: any = document): T {
+  return root.querySelector(selector) as T;
+}
 
 
-function renderChatHistory(messages: Message[]) {
-  $('#chat-messages').html(messages.map(msg => {
-    return `<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>`;
-
-  }).join("\n"));
-  $('#chat-messages').scrollTop($('#chat-messages')[0].scrollHeight);
+function $$<T>(selector: string, root: any = document): T[] {
+  return Array.from(root.querySelectorAll(selector)) as T[];
 }
 
 function renderChatMessage(msg: Message) {
 }
 
 function renderChatMessage(msg: Message) {
-  $('#chat-messages').append(`<div class="chat-message" title="${new Date(parseInt(msg.sentAt))}" id="${msg.id}">
+  $<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>
                              <span class="from">${msg.from}</span>
                              <span class="message">${msg.msg}</span>
-                             </div>`);
-                             $('#chat-messages').scrollTop($('#chat-messages')[0].scrollHeight);
+                             </div>`;
+  $<HTMLElement>('#chat-messages').scrollTop = $<HTMLElement>('#chat-messages').scrollHeight;
 }
 
 function configureStandardChat() {
 }
 
 function configureStandardChat() {
-  socket.on('chathistory', renderChatHistory);
   socket.on('chat', renderChatMessage);
   socket.on('chat', renderChatMessage);
-
-  // bind HTML event
-  $('#chat-form').on('submit', e => {
-    e.preventDefault();
-    e.stopPropagation();
-
-    const msg = $('#message').val().toString();
-
-    if(msg.length > 0) {
-      socket.emit('chat', msg);
-      $('#message').val('');
-    }
-  });
 }
 
 export function configureChat(_socket: Socket) {
   // disable chat temporarily to test discord chat
   socket = _socket;
 
 }
 
 export function configureChat(_socket: Socket) {
   // disable chat temporarily to test discord chat
   socket = _socket;
 
-  //configureDiscordChat(socket);
   configureStandardChat();
 
   console.log('Chat Configured');
   configureStandardChat();
 
   console.log('Chat Configured');
diff --git a/src/client/htmx.ts b/src/client/htmx.ts
new file mode 100644 (file)
index 0000000..a4107d8
--- /dev/null
@@ -0,0 +1,178 @@
+import { io } from 'socket.io-client';
+import { authToken } from './http';
+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 Array.from(root.querySelectorAll(selector)) as T[];
+}
+function setTimeGradient() {
+  const gradientName = time.gradientName();
+  const $body = $<HTMLElement>('body');
+  $body.classList.value = gradientName; 
+
+  $body.classList.add(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';
+  }
+  
+  $<HTMLElement>('#time-of-day').innerHTML = `<img src="/assets/img/icons/time-of-day/${icon}.png"> ${time.getHour()}${time.getAmPm()}`;
+}
+
+
+const time = new TimeManager();
+const socket = io({
+  extraHeaders: {
+    'x-authtoken': authToken()
+  }
+});
+setTimeGradient();
+setInterval(setTimeGradient, 60 * 1000);
+
+socket.on('connect', () => {
+  console.log(`Connected: ${socket.id}`);
+});
+
+socket.on('authToken', (authToken: string) => {
+  console.log(`recv auth token ${authToken}`);
+  localStorage.setItem('authToken', authToken);
+});
+
+
+socket.on('ready', bootstrap);
+
+
+$$<HTMLElement>('nav a').forEach(el => {
+  el.addEventListener('click', e => {
+    const el = e.target as HTMLElement;
+
+    $$<HTMLElement>('a', el.closest('nav')).forEach(el => {
+      el.classList.remove('active');
+    })
+
+    el.classList.add('active');
+
+    const targetEl = $<HTMLElement>(el.getAttribute('hx-target')!.toString());
+
+    Array.from(targetEl.parentElement!.children).forEach(el => {
+      el.classList.remove('active');
+    });
+    targetEl.classList.add('active');
+  });
+});
+
+$<HTMLElement>('body').addEventListener('click', e => {
+  const target = e.target as HTMLElement;
+
+  if(target!.parentElement!.classList.contains('filter')) {
+    // ok this is afunky filter object!
+    const children = Array.from(target!.parentElement!.children);
+    children.forEach(el => el.classList.remove('active'));
+    target.classList.add('active');
+
+    const dataFilter = target.getAttribute('data-filter');
+
+    const targetPane = $<HTMLElement>(`.filter-result[data-filter="${dataFilter}"]`, target.closest('.filter-container'));
+
+    if(targetPane) {
+      Array.from(targetPane!.parentElement!.children).forEach(el => {
+        if(el.getAttribute('data-filter') === dataFilter) {
+          el.classList.remove('hidden');
+          el.classList.add('active');
+        }
+        else {
+          el.classList.add('hidden');
+          el.classList.remove('active');
+        }
+      })
+    }
+  }
+
+  if(target.getAttribute('formmethod') === 'dialog' && target.getAttribute('value') === 'cancel') {
+    target.closest('dialog')?.close();
+  }
+});
+
+const modalMutations = new MutationObserver((list, observer) => {
+  const states = {
+    modal: false,
+    alert: false
+  };
+
+  list.forEach(mutation => {
+    switch(((mutation.target) as HTMLElement).id) {
+      case 'modal-wrapper':
+        states.modal = true;
+        break;
+      case 'alerts':
+        states.alert = true;
+        break;
+
+    }
+  });
+
+  if(states.modal) {
+    if($<HTMLElement>('#modal-wrapper').children.length) {
+      $$<HTMLDialogElement>('#modal-wrapper dialog').forEach(el => {
+        if(!el.open) {
+          el.showModal();
+        }
+      })
+    }
+  }
+
+  if(states.alert) {
+    if($<HTMLElement>('#alerts').children.length) {
+      $$<HTMLElement>('#alerts .alert').forEach(el => {
+        if(!el.getAttribute('data-dismiss-at')) {
+          const dismiss = Date.now() + 3000;
+          el.setAttribute('data-dismiss-at', dismiss.toString());
+          setTimeout(() => { el.remove(); }, 3000);
+        }
+      });
+    }
+  }
+
+});
+
+modalMutations.observe($<HTMLElement>('#modal-wrapper'), { childList: true });
+
+modalMutations.observe($<HTMLElement>('#alerts'), { childList: true });
+
+
+function bootstrap() {
+  console.log('Server connection verified');
+  configureChat(socket);
+  $$<HTMLElement>('nav a')[0].click();
+}
+document.body.addEventListener('htmx:configRequest', function(evt) {
+  //@ts-ignore
+  evt.detail.headers['x-authtoken'] = authToken();
+});
+document.body.addEventListener('htmx:load', function(evt) {
+  $$<HTMLElement>('.disabled[data-block]').forEach(el => {
+    setTimeout(() => { el.removeAttribute('disabled'); }, 3000);
+  });
+});
+document.body.addEventListener('htmx:beforeSwap', function(e) {
+  const el = e.target as HTMLElement;
+  if(el.id === 'chat-form') {
+    $<HTMLInputElement>('#message').value = '';
+  }
+});
+
index 3298b5710bed3f029a0081405680b3bdbe8753da..312cea1f73a0891ebbc58de3238a5e435c6f17a5 100644 (file)
@@ -1,4 +1,4 @@
-export function authToken() {
+export function authToken(): string {
   return localStorage.getItem('authToken');
 }
 
   return localStorage.getItem('authToken');
 }
 
@@ -21,6 +21,12 @@ export const http = {
       }
     });
 
       }
     });
 
-    return res.json();
+    try {
+      return res.json();
+    }
+    catch {
+      console.log('No valid JSON response');
+      return null;
+    }
   }
 }
   }
 }
index 72e9d803bff1aa744ba4690cdb7e15ef0c443627..b460ead9f20cdf7cb2f78c6a5db6f11b9388a2f4 100644 (file)
@@ -7,7 +7,7 @@ import {Fight, FightTrigger, MonsterForFight, MonsterForList} from '../shared/mo
 import {FightRound} from '../shared/fight';
 import { City, Location, LocationType, Path } from '../shared/map'
 import { v4 as uuid } from 'uuid';
 import {FightRound} from '../shared/fight';
 import { City, Location, LocationType, Path } from '../shared/map'
 import { v4 as uuid } from 'uuid';
-import {EquipmentSlot, ShopItem} from '../shared/inventory';
+import {EquipmentSlot, ShopEquipment} from '../shared/inventory';
 import { capitalize, each } from 'lodash';
 import {EquippedItemDetails} from '../shared/equipped';
 import { Skill, Skills } from '../shared/skills';
 import { capitalize, each } from 'lodash';
 import {EquippedItemDetails} from '../shared/equipped';
 import { Skill, Skills } from '../shared/skills';
@@ -16,6 +16,8 @@ import { SocketEvent } from './socket-event.client';
 import * as EventList from '../events/client';
 import { TimeManager } from '../shared/time';
 import { TravelDTO } from '../events/travel/shared';
 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 time = new TimeManager();
@@ -362,6 +364,39 @@ $('body').on('click', 'nav.filter', e => {
   cache.set(cacheKey, filter);
 });
 
   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 => {
 function renderInventorySection(inventory: EquippedItemDetails[]): string {
   return inventory.map(item => {
     return renderInventoryItem(item, item => {
@@ -390,44 +425,50 @@ function renderInventorySection(inventory: EquippedItemDetails[]): string {
   }).join("\n");
 }
 
   }).join("\n");
 }
 
-socket.on('inventory', (data: {inventory: EquippedItemDetails[]}) => {
+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 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[]} = {
+  const sectionedInventory: {ARMOUR: EquippedItemDetails[], WEAPON: EquippedItemDetails[], SPELL: EquippedItemDetails[], ITEMS: PlayerItem[]} = {
     ARMOUR: [],
     WEAPON: [],
     ARMOUR: [],
     WEAPON: [],
-    SPELL: []
+    SPELL: [],
+    ITEMS: []
   };
 
   data.inventory.forEach(item => {
     sectionedInventory[item.type].push(item);
   });
   };
 
   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)}
 
   const html = `
   <div id="inventory-page">
     <div id="character-summary">
     ${renderEquipmentPlacementGrid(data.inventory)}
-      <div id="extra-inventory-info">
-        ${renderStatDetails()}
-      </div>
     </div>
     <div id="inventory-section" class="filter-container">
       <nav class="filter" id="inventory-section">
     </div>
     <div id="inventory-section" class="filter-container">
       <nav class="filter" id="inventory-section">
-        <a href="#" data-filter="ARMOUR" class="${activeSection === 'ARMOUR' ? 'active': ''}">Armour</a>
-        <a href="#" data-filter="WEAPON" class="${activeSection === 'WEAPON' ? 'active': ''}">Weapons</a>
-        <a href="#" data-filter="SPELL" class="${activeSection === 'SPELL' ? 'active': ''}">Spells</a>
+        ${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">
       </nav>
       <div class="inventory-listing listing">
-        <div class="filter-result ${activeSection === 'ARMOUR' ? 'active' : 'hidden'}" id="filter_ARMOUR">
-          ${renderInventorySection(sectionedInventory.ARMOUR)}
-        </div>
-        <div class="filter-result ${activeSection === 'WEAPON' ? 'active' : 'hidden'}" id="filter_WEAPON">
-          ${renderInventorySection(sectionedInventory.WEAPON)}
-        </div>
-        <div class="filter-result ${activeSection === 'SPELL' ? 'active' : 'hidden'}" id="filter_SPELL">
-          ${renderInventorySection(sectionedInventory.SPELL)}
-        </div>
+        ${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>
       </div>
     </div>
   </div>
@@ -556,7 +597,7 @@ function renderInventoryItem(item: EquippedItemDetails , action: (item: Equipped
     </div>`;
 }
 
     </div>`;
 }
 
-function renderShopItem(item: ShopItem, action: (item: ShopItem) => string): string {
+function renderShopEquipment(item: ShopEquipment, action: (item: ShopEquipment) => string): string {
   const player: Player = cache.get('player');
     return `<div class="store-list">
     <div>
   const player: Player = cache.get('player');
     return `<div class="store-list">
     <div>
@@ -587,13 +628,32 @@ function renderShopItem(item: ShopItem, action: (item: ShopItem) => string): str
       ${action(item)}
     </div>
     </div>`;
       ${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: ShopItem[]) => {
+socket.on('city:stores', (data: {equipment: ShopEquipment[], items: (ShopItem & Item)[]}) => {
   const listing: Record<string, string> = {};
   const listingTypes = new Set<string>();
   const listing: Record<string, string> = {};
   const listingTypes = new Set<string>();
-  data.forEach(item => {
+  const { equipment, items } = data;
+  equipment.forEach(item => {
     if(item.type === 'ARMOUR') {
       listingTypes.add(item.equipment_slot);
 
     if(item.type === 'ARMOUR') {
       listingTypes.add(item.equipment_slot);
 
@@ -601,24 +661,37 @@ socket.on('city:stores', (data: ShopItem[]) => {
         listing[item.equipment_slot] = '';
       }
       
         listing[item.equipment_slot] = '';
       }
       
-      listing[item.equipment_slot] += renderShopItem(item, i => {
+      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>`
       });
     }
         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 {
+    else if(item.type) {
       listingTypes.add(item.type);
       if(!listing[item.type]) {
         listing[item.type] = '';
       }
       
       listingTypes.add(item.type);
       if(!listing[item.type]) {
         listing[item.type] = '';
       }
       
-      listing[item.type] += renderShopItem(item, i => {
+      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>`
       });
     }
         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');
 
   const sections = Object.keys(listing);
   let activeSection = cache.get('active-shop-inventory-listing');
 
@@ -668,11 +741,19 @@ $('body').on('click', '.purchase-item', e => {
   }
 });
 
   }
 });
 
+$('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);
 
 $('body').on('click', '.emit-event', e => {
   const $el = $(e.target);
 
-  const eventName = $el.data('event');
-  const args = $el.data('args');
+  const eventName = $el.closest('[data-event]').data('event');
+  const args = $el.closest('[data-args]').data('args');
 
   const rawBlock = $el.data('block');
 
 
   const rawBlock = $el.data('block');
 
@@ -1026,6 +1107,11 @@ $('body').on('click', '#logout', async e => {
 
 function bootstrap() {
   console.log('Server connection verified');
 
 function bootstrap() {
   console.log('Server connection verified');
-  socket.emit('inventory');
+  //socket.emit('inventory');
   $('nav a').first().click();
   $('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
new file mode 100644 (file)
index 0000000..1eabdac
--- /dev/null
@@ -0,0 +1,41 @@
+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();
+  }
+}
index 49ca3d05c7d5c43c4a863ec3b327c7b86c0e40cf..4d0754fc453343472cab7ae1a85b2ec30b58a448 100644 (file)
@@ -1,3 +1,2 @@
 export * from './profession-changing/client';
 export * from './travel/client';
 export * from './profession-changing/client';
 export * from './travel/client';
-export * from './healer/client';
index 802f66bef86dbc5da12f3925992f5122b4546446..7b0031639a164942854acab8940f02c625ef9480 100644 (file)
@@ -5,6 +5,7 @@ import {getEquippedItems, getInventory, getInventoryItem} from '../../server/inv
 import { equip, unequip } from '../../server/equipment';
 import { logger } from '../../server/lib/logger';
 import {EquippedItemDetails} from '../../shared/equipped';
 import { equip, unequip } from '../../server/equipment';
 import { logger } from '../../server/lib/logger';
 import {EquippedItemDetails} from '../../shared/equipped';
+import { getPlayersItems } from "../../server/items";
 
 class EquipmentInSlotError extends Error {
   code: number;
 
 class EquipmentInSlotError extends Error {
   code: number;
@@ -81,10 +82,12 @@ export const equipItem: SocketEvent = {
     }
 
     const inventory = await getInventory(api.player.id);
     }
 
     const inventory = await getInventory(api.player.id);
-    calcAp(inventory, api.socket);
+    const items = await getPlayersItems(api.player.id);
     api.socket.emit('inventory', {
     api.socket.emit('inventory', {
-      inventory
+      inventory,
+      items
     });
     });
+    calcAp(inventory, api.socket);
 
   }
 }
 
   }
 }
@@ -96,8 +99,10 @@ export const unequipItem: SocketEvent = {
 
     const inventory = await getInventory(api.player.id);
     calcAp(inventory, api.socket);
 
     const inventory = await getInventory(api.player.id);
     calcAp(inventory, api.socket);
+    const items = await getPlayersItems(api.player.id);
     api.socket.emit('inventory', {
     api.socket.emit('inventory', {
-      inventory
+      inventory,
+      items
     });
   }
 }
     });
   }
 }
diff --git a/src/events/healer/client.ts b/src/events/healer/client.ts
deleted file mode 100644 (file)
index 56a0da1..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-import { SocketEvent } from '../../client/socket-event.client';
-import $ from 'jquery';
-
-export const displayHealerDetauls: SocketEvent = new SocketEvent('city:service:healer', (api, data: {text: string}) => {
-  $('#map').html(data.text);
-});
diff --git a/src/events/healer/server.ts b/src/events/healer/server.ts
deleted file mode 100644 (file)
index df8fb8a..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-import {SocketEvent} from "../../server/socket-event.server";
-import { getCityDetails, getService } from "../../server/map";
-import { City, Location } from "../../shared/map";
-import {maxHp, Player} from '../../shared/player';
-import { updatePlayer } from "../../server/player";
-import { sample } from 'lodash';
-
-type TextSegment = 'intro' | 'insufficient_money' | 'heal_successful';
-
-type HealText = Record<TextSegment, string[]>;
-
-const healCost = 10;
-
-const defaultTexts: HealText = {
-  intro: [
-    `Welcome traveller, I am {{NAME}}, Healer of {{CITY_NAME}}`,
-    "Please come in traveller, I am {{NAME}}, Healer of {{CITY_NAME}}",
-  ],
-  insufficient_money: [
-    "Sorry friend, you don't have enough money..",
-    "Sorry, that won't be enough..",
-    "Healing is hard work.. I'm afraid that won't cover it.."
-  ],
-  heal_successful: [
-    "I hope you feel better now",
-    "Good luck on your travels!",
-    "Glad to be of service..."
-  ]
-}
-
-// overrides for specific areas
-const playerTexts: Record<number, HealText> = {
-  [8]: {
-    intro: [
-      'Welcome to Midfield traveller, I am Casim - healer in these parts',
-      'I am Casim the Healer here... how are you enjoying your stay at Midfield?'
-    ],
-    insufficient_money: [
-      'Sorry friend, you don\'t have enough money',
-      'Look.. I\'m sorry.. that won\'t be enough...'
-    ],
-    heal_successful: [
-      'Glad to help!'
-    ]
-  },
-  [16]: {
-    intro: [
-      'Ah, welcome to Wildegard, one of the few safehavens in the Akari Woods. I am Adovras, healer in these parts.',
-      'Welcome traveller, I am Adovras - healer in these parts'
-    ],
-    insufficient_money: [
-      `Sorry friend, you don't have enough money...`
-    ],
-    heal_successful: [
-      "Hope this small healing will be helpful on your journeys"
-    ]
-
-  },
-  [11]: {
-    intro: [
-      'Ah, welcome traveler - I am Uthar, healer of Davelfell',
-      'Hello, I am Uthar, healer of Davelfell',
-      'Sorry I\'m a bit busy today, I am Uthar, healer of Davelfell'
-    ],
-    insufficient_money: [
-      "Bah, don't bother me if you don't have the money",
-      "Look, I'm very busy - come back when you have the money"
-    ],
-    heal_successful: [
-      "*Fizz* *POOF* YOU'RE HEALED!"
-    ]
-  }
-}
-
-function getText(type: TextSegment, location: Location, city: City): string {
-  let selected = sample(defaultTexts[type]);
-
-  if(playerTexts[location.id]) {
-    if(playerTexts[location.id][type].length) {
-      selected = sample(playerTexts[location.id][type]);
-    }
-  }
-
-  return selected.replace("{{NAME}}", location.name).replace("{{CITY_NAME}}", city.name);
-
-}
-
-export const healer: SocketEvent = {
-  eventName: 'city:services:healer',
-  handler: async (api, data: { args: number }) => {
-    const text: string[] = [];
-    const healerId = data.args;
-    const service = await getService(healerId);
-
-    if(service.city_id !== api.player.city_id) {
-      api.socket.emit('alert', {
-        type: 'error',
-        text: `You don't seem to be in the right city...`
-      });
-      return;
-    }
-
-    const city = await getCityDetails(service.city_id);
-
-    text.push(`<p><b>${service.name}</b></p>`);
-    text.push(`<p>"${getText('intro', service, city)}"</p>`);
-
-
-    if(api.player.hp === maxHp(api.player.constitution, api.player.level)) {
-      text.push(`<p>You're already at full health?</p>`);
-    }
-    else {
-      if(api.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" class="city-emit-event" data-event="city:services:healer:heal" data-args="${service.id}">Heal for free!</button></p>`);
-      }
-      else {
-        text.push(`<p><button type="button" class="city-emit-event" data-event="city:services:healer:heal" data-args="${service.id}">Heal for ${healCost}g!</button></p>`);
-      }
-
-    }
-
-    api.socket.emit('city:service:healer', {
-      text: text.join("\n")
-    });
-  }
-}
-
-export const heal: SocketEvent = {
-  eventName: 'city:services:healer:heal',
-  handler: async (api, data: { args: number }) => {
-    const text: string[] = [];
-    const healerId = data.args;
-    const service = await getService(healerId);
-
-    if(service.city_id !== api.player.city_id) {
-      api.socket.emit('alert', {
-        type: 'error',
-        text: `You don't seem to be in the right city...`
-      });
-      return;
-    }
-
-    const city = await getCityDetails(service.city_id);
-
-    text.push(`<p><b>${service.name}</b></p>`);
-
-    const cost = api.player.gold <= (healCost * 2) ? 0 : healCost;
-
-    if(api.player.gold < cost) {
-      text.push(`<p>${getText('insufficient_money', service, city)}</p>`)
-      api.socket.emit('city:service:healer', {
-        text: text.join("\n")
-      });
-      return;
-    }
-
-    api.player.hp = maxHp(api.player.constitution, api.player.level);
-    api.player.gold -= cost;
-
-    await updatePlayer(api.player);
-    api.socket.emit('updatePlayer', api.player);
-
-
-    text.push(`<p>${getText('heal_successful', service, city)}</p>`);
-    text.push('<p><button class="emit-event-internal" data-event="tab:explore">Back to Town</button></p>');
-    api.socket.emit('city:service:healer', {
-      text: text.join("\n")
-    });
-  }
-}
diff --git a/src/events/items/server.ts b/src/events/items/server.ts
new file mode 100644 (file)
index 0000000..0c9023d
--- /dev/null
@@ -0,0 +1,54 @@
+import { getItemFromPlayer, getPlayersItems, updateItemCount } from "../../server/items";
+import {API, SocketEvent} from "../../server/socket-event.server";
+import { maxHp } from "../../shared/player";
+import { updatePlayer } from "../../server/player";
+import { HealthPotionSmall } from "../../shared/items/health_potion";
+import { getInventory } from "../../server/inventory";
+
+export const smallHeal: SocketEvent = {
+  eventName: 'item:use:heal_small',
+  handler: async (api: API, data: {args: string}): Promise<any> => {
+    const itemId = parseInt(data.args);
+    const item = await getItemFromPlayer(api.player.id, itemId);
+
+    if(!item) {
+      console.log(`Can't find item [${data.args}]`);
+      return;
+    }
+
+    if(item.amount < 1) {
+      api.socket.emit('alert', {
+        type: 'error',
+        text: `You don't have enough ${item.name}`
+      });
+      return;
+    }
+
+    item.amount -= 1;
+
+    const hpGain = HealthPotionSmall.effect(api.player);
+
+    api.player.hp += hpGain;
+
+    if(api.player.hp > maxHp(api.player.constitution, api.player.level)) {
+      api.player.hp = maxHp(api.player.constitution, api.player.level);
+    }
+
+    await updateItemCount(api.player.id, item.item_id, -1);
+    await updatePlayer(api.player);
+    const inventory = await getInventory(api.player.id);
+    const items = await getPlayersItems(api.player.id);
+
+    api.socket.emit('updatePlayer', api.player);
+    api.socket.emit('inventory', {
+      inventory,
+      items
+    });
+    api.socket.emit('alert', {
+      type: 'success',
+      text: `You used the Small Health Potion`
+    });
+
+    return;
+  }
+}
index 6ac369034b9dfb588bf27cfcd261cb5708c09eeb..6f9811a535385d46599ee8f0a1ad7075e791b5d4 100644 (file)
@@ -3,5 +3,5 @@ export * from './equipping-items/server';
 export * from './travel/server';
 export * from './explore/server';
 export * from './stores/server';
 export * from './travel/server';
 export * from './explore/server';
 export * from './stores/server';
-export * from './healer/server';
 export * from './stat-points/server';
 export * from './stat-points/server';
+export * from './items/server';
index 076cab4e93b6f74b47e3b3c8e03fdf34ada30873..1acbd8c56035e74b953ec0805ff42d4796f215f8 100644 (file)
@@ -1,5 +1,6 @@
 import {SocketEvent} from "../../server/socket-event.server";
 import {SocketEvent} from "../../server/socket-event.server";
-import {listShopItems} from '../../server/shopItem';
+import {listShopItems} from '../../server/shopEquipment';
+import { getShopItems } from "../../server/items";
 import { logger } from '../../server/lib/logger';
 
 export const stores: SocketEvent = {
 import { logger } from '../../server/lib/logger';
 
 export const stores: SocketEvent = {
@@ -11,15 +12,19 @@ export const stores: SocketEvent = {
       logger.log(`Invalid store id: ${storeId}`);
     }
 
       logger.log(`Invalid store id: ${storeId}`);
     }
 
-    const shopItems = await listShopItems({
-      location_id: storeId
-    });
+    const [shopEquipemnt, shopItems] = await Promise.all([
+      listShopItems({location_id: storeId}),
+      getShopItems(storeId)
+    ]);
 
 
-    if(shopItems && shopItems.length) {
-      api.socket.emit('city:stores', shopItems);
+    if(shopEquipemnt && shopEquipemnt.length) {
+      api.socket.emit('city:stores', {
+        equipment: shopEquipemnt,
+        items: shopItems
+      });
     }
     else {
     }
     else {
-      logger.log(`Insufficient shop items: ${shopItems.length}`);
+      logger.log(`Insufficient shop items: ${shopEquipemnt.length}`);
     }
   }
 }
     }
   }
 }
index aed47d41831d8261459b751175a2fe31f6784e31..bd86f977d9eaae3652e87312803ccc74aae6da0f 100644 (file)
@@ -3,31 +3,50 @@ import { version } from "../../package.json";
 import { config as dotenv } from 'dotenv';
 import { join } from 'path';
 import express, {Request, Response} from 'express';
 import { config as dotenv } from 'dotenv';
 import { join } from 'path';
 import express, {Request, Response} from 'express';
+import bodyParser from 'body-parser';
+
 import http from 'http';
 import { Server, Socket } from 'socket.io';
 import { logger } from './lib/logger';
 import http from 'http';
 import { Server, Socket } from 'socket.io';
 import { logger } from './lib/logger';
-import { loadPlayer, createPlayer, updatePlayer } from './player';
-import * as _ from 'lodash';
+import { loadPlayer, createPlayer, updatePlayer, movePlayer } from './player';
+import { random, sample } from 'lodash';
 import {broadcastMessage, Message} from '../shared/message';
 import {expToLevel, maxHp, Player} from '../shared/player';
 import {broadcastMessage, Message} from '../shared/message';
 import {expToLevel, maxHp, Player} from '../shared/player';
-import {clearFight, createFight, getMonsterList, loadMonster, loadMonsterFromFight, loadMonsterWithFaction, saveFightState} from './monster';
+import {clearFight, createFight, getMonsterList, getRandomMonster, loadMonster, loadMonsterFromFight, loadMonsterWithFaction, saveFightState} from './monster';
 import {FightRound} from '../shared/fight';
 import {FightRound} from '../shared/fight';
-import {addInventoryItem, deleteInventoryItem, getEquippedItems, getInventory, updateAp} from './inventory';
-import {FightTrigger, MonsterForFight} from '../shared/monsters';
-import {getShopItem } from './shopItem';
+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 {EquippedItemDetails} from '../shared/equipped';
 import {ArmourEquipmentSlot, EquipmentSlot} from '../shared/inventory';
 import {EquippedItemDetails} from '../shared/equipped';
 import {ArmourEquipmentSlot, EquipmentSlot} from '../shared/inventory';
-import { clearTravelPlan, getAllPaths, getAllServices, getCityDetails, getTravelPlan, travel } from './map';
-import { signup, login } from './auth';
+import { clearTravelPlan, completeTravel, getAllPaths, getAllServices, getCityDetails, getService, getTravelPlan, stepForward, travel } from './map';
+import { signup, login, authEndpoint } 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';
-import * as EventList from '../events/server';
+
+import  { router as healerRouter } from './locations/healer';
+
+import * as Alert from './views/alert';
+import { renderPlayerBar } from './views/player-bar'
+import { renderEquipmentDetails, renderStore } from './views/stores';
+import { renderMap } from './views/map';
+import { renderProfilePage } from './views/profile';
+import { renderSkills } from './views/skills';
+import { renderInventoryPage } from './views/inventory';
+import { renderMonsterSelector } from './views/monster-selector';
+import { renderFight, renderRoundDetails } from './views/fight';
+import { renderTravel, travelButton } from './views/travel';
+import { renderChatMessage } from './views/chat';
 
 // TEMP!
 import { createMonsters } from '../../seeds/monsters';
 import { createAllCitiesAndLocations } from '../../seeds/cities';
 import { createShopItems } from '../../seeds/shop_items';
 
 // TEMP!
 import { createMonsters } from '../../seeds/monsters';
 import { createAllCitiesAndLocations } from '../../seeds/cities';
 import { createShopItems } from '../../seeds/shop_items';
+import { Item, PlayerItem, ShopItem } from 'shared/items';
+import { equip, unequip } from './equipment';
+import { HealthPotionSmall } from '../shared/items/health_potion';
 
 dotenv();
 
 
 dotenv();
 
@@ -37,6 +56,7 @@ const app = express();
 const server = http.createServer(app);
 
 app.use(express.static(join(__dirname, '..', '..', 'public')));
 const server = http.createServer(app);
 
 app.use(express.static(join(__dirname, '..', '..', 'public')));
+app.use(bodyParser.urlencoded({ extended: true }));
 app.use(express.json());
 
 const io = new Server(server);
 app.use(express.json());
 
 const io = new Server(server);
@@ -44,27 +64,10 @@ const io = new Server(server);
 const cache = new Map<string, any>();
 const chatHistory: Message[] = [];
 
 const cache = new Map<string, any>();
 const chatHistory: Message[] = [];
 
-function calcAp(inventoryItem: EquippedItemDetails[], socket: Socket) {
-  const ap: Record<any | EquipmentSlot, {currentAp: number, maxAp: number}> = {};
-  inventoryItem.forEach(item => {
-    if(item.is_equipped && item.type === 'ARMOUR') {
-      ap[item.equipment_slot] = {
-        currentAp: item.currentAp,
-        maxAp: item.maxAp
-      };
-    }
-  });
-
-  socket.emit('calc:ap', {ap});
-}
-
-function setServerStats() {
-  io.emit('server-stats', {
-    onlinePlayers: io.sockets.sockets.size
-  });
-}
-
-setTimeout(setServerStats, 5000);
+app.use((req, res, next) => {
+  console.log(req.method, req.url);
+  next();
+});
 
 io.on('connection', async socket => {
   logger.log(`socket ${socket.id} connected, authToken: ${socket.handshake.headers['x-authtoken']}`);
 
 io.on('connection', async socket => {
   logger.log(`socket ${socket.id} connected, authToken: ${socket.handshake.headers['x-authtoken']}`);
@@ -90,479 +93,820 @@ io.on('connection', async socket => {
   // ref to get the player object
   cache.set(`token:${player.id}`, player);
 
   // ref to get the player object
   cache.set(`token:${player.id}`, player);
 
-  socket.emit('init', {
-    version
+  socket.emit('authToken', player.id);
+
+  socket.emit('chat', broadcastMessage('server', `${player.username} just logged in`));
+
+  socket.on('disconnect', () => {
+    console.log(`Player ${player.username} left`);
   });
 
   });
 
-  socket.emit('authToken', player.id);
-  socket.emit('player', player);
+  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`);
+    }
+  });
 
 
-  const inventory = await getEquippedItems(player.id);
-  calcAp(inventory, socket);
+  // this is a special event to let the client know it can start 
+  // requesting data
+  socket.emit('ready');
+});
 
 
-  setServerStats();
+async function fightRound(player: Player, monster: MonsterWithFaction,  data: {action: 'attack' | 'cast' | 'flee', target: 'head' | 'body' | 'arms' | 'legs'}) {
+  const playerSkills = await getPlayerSkillsAsObject(player.id);
+  const roundData: FightRound = {
+    monster,
+    player,
+    winner: 'in-progress',
+    fightTrigger: monster.fight_trigger,
+    roundDetails: [],
+    rewards: {
+      exp: 0,
+      gold: 0,
+      levelIncrease: false
+    }
+  };
+  const equippedItems = await getEquippedItems(player.id);
+
+  // we only use this if the player successfully defeated the monster 
+  // they were fighting, then we load the other monsters in this area 
+  // so they can "fight again"
+  let potentialMonsters: MonsterForFight[] = [];
+
+  /*
+   * cumulative chance of head/arms/body/legs
+   * 0 -> 0.2 = head
+   * 0.21 -> 0.4 = arms
+   *
+   * we use the factor to decide how many decimal places 
+   * we care about
+   */
+  const factor = 100;
+  const monsterTarget = [0.2, 0.4, 0.9, 1];
+  const targets: ArmourEquipmentSlot[] = ['HEAD', 'CHEST', 'ARMS', 'LEGS'];
+  // calc weighted
+  const rand = Math.ceil(Math.random() * factor);
+  let target: ArmourEquipmentSlot = 'CHEST';
+  monsterTarget.forEach((i, idx) => {
+    if (rand > (i * factor)) {
+      target = targets[idx] as ArmourEquipmentSlot;
+    }
+  });
 
 
-  io.emit('chathistory', chatHistory);
+  const boost = {
+    strength: 0,
+    constitution: 0,
+    dexterity: 0,
+    intelligence: 0,
+    damage: 0,
+    hp: 0,
+  };
 
 
-  socket.emit('chat', broadcastMessage('server', `${player.username} just logged in`));
+  const equipment: Map<EquipmentSlot, EquippedItemDetails> = new Map<EquipmentSlot, EquippedItemDetails>();
+  const weapons: EquippedItemDetails[] = [];
+  let anyDamageSpells: boolean = false;
+  equippedItems.forEach(item => {
+    if(item.type === 'ARMOUR') {
+      equipment.set(item.equipment_slot, item);
+    }
+    else if(item.type === 'WEAPON') {
+      weapons.push(item);
+    }
+    else if(item.type === 'SPELL') {
+      if(item.affectedSkills.includes('destruction_magic')) {
+        anyDamageSpells = true;
+      }
+      weapons.push(item);
+    }
 
 
-  socket.on('disconnect', () => {
-    console.log(`Player ${player.username} left`);
+    boost.strength += item.boosts.strength;
+    boost.constitution += item.boosts.constitution;
+    boost.dexterity += item.boosts.dexterity;
+    boost.intelligence += item.boosts.intelligence;
+
+    if(item.type === 'SPELL' && item.affectedSkills.includes('restoration_magic')) {
+      boost.hp += item.boosts.damage;
+    }
+    else {
+      boost.damage += item.boosts.damage;
+    }
   });
 
   });
 
-  socket.on('chat', async (msg: string) => {
-    if(msg.length > 0) {
+  // if you flee'd, then we want to check your dex vs. the monsters
+  // but we want to give you the item/weapon boosts you need
+  // if not then you're going to get hit.
+  if(data.action === 'flee') {
+    roundData.roundDetails.push(`You managed to escape from the ${monster.name}!`)
+    roundData.winner = 'monster';
+    await clearFight(player.id);
 
 
-      let message: Message;
-      if(msg.startsWith('/server lmnop')) {
-        if(msg === '/server lmnop refresh-monsters') {
-          await createMonsters();
-          message = broadcastMessage('server', 'Monster refresh!');
-        }
-        else if(msg === '/server lmnop refresh-cities') {
-          await createAllCitiesAndLocations();
-          message = broadcastMessage('server', 'Cities, Locations, and Paths refreshed!');
-        }
-        else if(msg === '/server lmnop refresh-shops') {
-          await createShopItems();
-          message = broadcastMessage('server', 'Refresh shop items');
-        }
-        else {
-          const str = msg.split('/server lmnop ')[1];
-          if(str) {
-            message = broadcastMessage('server', str);
-          }
+    return { roundData, monsters: [], player };
+  }
+
+  const attackType = data.action === 'attack' ? 'physical' : 'magical';
+  const primaryStat = data.action === 'attack' ? player.strength : player.intelligence;
+  const boostStat = data.action === 'attack' ? boost.strength : boost.intelligence;
+
+  const playerDamage = Math.floor(((primaryStat + boostStat) * 1.3) + boost.damage);
+  const skillsUsed: Record<SkillID | any, number> = {};
+  let hpHealAfterMasteries: number = -1;
+  let playerDamageAfterMasteries: number = 0;
+  // apply masteries!
+  weapons.forEach(item => {
+    item.affectedSkills.forEach(id => {
+      if(id === 'restoration_magic') {
+        if(hpHealAfterMasteries < 0) {
+          hpHealAfterMasteries = 0;
         }
         }
+        hpHealAfterMasteries += Skills.get(id).effect(playerSkills.get(id));
       }
       else {
       }
       else {
-        const authToken = socket.handshake.headers['x-authtoken'];
-        if(cache.has(`token:${authToken}`)) {
-          const player = cache.get(`token:${authToken}`);
-          message = broadcastMessage(player.username, msg);
-        }
-        else {
-          logger.log(`Missing cache for [token:${authToken}]`);
-        }
+        playerDamageAfterMasteries += playerDamage * Skills.get(id).effect(playerSkills.get(id));
       }
 
       }
 
-      if(message) {
-        chatHistory.push(message);
-        chatHistory.slice(-10);
-        io.emit('chat', message);
+      if(!skillsUsed[id]) {
+        skillsUsed[id] = 0;
       }
       }
-      else {
-        logger.log(`Unset message`);
-      }
-    }
+      skillsUsed[id]++;
+    });
   });
 
   });
 
-  socket.on('purchase', async (data) => {
-    const authToken = socket.handshake.headers['x-authtoken'];
-    if(!cache.has(`token:${authToken}`)) {
-      return;
+  await updatePlayerSkills(player.id, skillsUsed);
+
+  const playerFinalDamage = (data.action === 'cast' && !anyDamageSpells) ? 0 : Math.floor(playerDamage + playerDamageAfterMasteries);
+  const playerFinalHeal = Math.floor(boost.hp + hpHealAfterMasteries);
+
+  roundData.roundDetails.push(`You targeted the monsters ${data.target.toUpperCase()} with ${attackType} damage!`);
+  let armourKey: string;
+  switch(data.target) {
+    case 'arms':
+      armourKey = 'armsAp';
+      break;
+    case 'head':
+      armourKey = 'helmAp';
+      break;
+    case 'legs':
+      armourKey = 'legsAp';
+      break;
+    case 'body':
+      armourKey = 'chestAp';
+      break;
+  }
+
+  if(monster[armourKey] && monster[armourKey] > 0) {
+    monster[armourKey] -= playerFinalDamage;
+
+    roundData.roundDetails.push(`You dealt ${playerFinalDamage} damage to their armour`);
+    if(monster[armourKey] < 0) {
+      roundData.roundDetails.push(`You destroyed the ${monster.name}'s armour!'`);
+      roundData.roundDetails.push(`You dealt ${monster[armourKey] * -1} damage to their HP`);
+      monster.hp += monster[armourKey];
+      monster[armourKey] = 0;
     }
     }
-    const player = cache.get(`token:${authToken}`);
-    const shopItem = await getShopItem(data.id);
-
-    if(shopItem && player) {
-      if(player.gold < shopItem.cost) {
-        socket.emit('alert', {
-          type: 'error',
-          text: `You dont have enough gold to buy the ${shopItem.name}`
-        });
-        return;
+  }
+  else {
+    roundData.roundDetails.push(`You hit the ${monster.name} for ${playerFinalDamage} damage.`);
+    monster.hp -= playerFinalDamage;
+  }
+
+  if(monster.hp <= 0) {
+    roundData.monster.hp = 0;
+    roundData.winner = 'player';
+
+    roundData.rewards.exp = monster.exp;
+    roundData.rewards.gold = monster.gold;
+
+    player.gold += monster.gold;
+    player.exp += monster.exp;
+
+    if(player.exp >= expToLevel(player.level + 1)) {
+      player.exp -= expToLevel(player.level + 1)
+      player.level++;
+      roundData.rewards.levelIncrease = true;
+      let statPointsGained = 1;
+
+      if(player.profession !== 'Wanderer') {
+        statPointsGained = 2;
       }
 
       }
 
-      player.gold -= shopItem.cost;
-      await updatePlayer(player);
-      await addInventoryItem(player.id, shopItem);
+      player.stat_points += statPointsGained;
 
 
-      socket.emit('alert', {
-        type: 'success',
-        text: `You bought the ${shopItem.name}`
-      });
+      roundData.roundDetails.push(`You gained ${statPointsGained} stat points!`);
 
 
-      socket.emit('updatePlayer', player);
+      player.hp = maxHp(player.constitution, player.level);
+    }
+    // get the monster location if it was an EXPLORED fight
+    if(roundData.fightTrigger === 'explore') {
+      const rawMonster = await loadMonster(monster.ref_id);
+      const monsterList  = await getMonsterList(rawMonster.location_id);
+      potentialMonsters = monsterList.map(monster => {
+        return {
+          id: monster.id,
+          name: monster.name,
+          level: monster.level,
+          hp: monster.hp,
+          maxHp: monster.maxHp,
+          fight_trigger: 'explore'
+        }
+      });
     }
     }
-  });
 
 
-  _.each(EventList, event => {
-    logger.log(`Bound event listener: ${event.eventName}`);
-    socket.on(event.eventName, event.handler.bind(null, {
-      socket,
-      io,
-      player,
-      cache
-    }));
-  });
+    await clearFight(player.id);
+    await updatePlayer(player);
+    return { roundData, monsters: potentialMonsters, player };
+  }
 
 
-  socket.on('skills', async () => {
-    const player = cache.get(`token:${socket.handshake.headers['x-authtoken']}`);
-    if(!player) {
-      return;
+  roundData.roundDetails.push(`The ${monster.name} targeted your ${target}!`);
+  if(equipment.has(target)) {
+    const item = equipment.get(target);
+    // apply mitigation!
+    const mitigationPercentage = item.boosts.damage_mitigation || 0;
+    const damageAfterMitigation = Math.floor(monster.strength * ((100-mitigationPercentage)/100));
+
+    item.currentAp -= damageAfterMitigation;
+
+    if(item.currentAp < 0) {
+      roundData.roundDetails.push(`Your ${item.name} amour was destroyed`);
+      roundData.roundDetails.push(`The ${monster.name} hit your HP for ${item.currentAp * -1} damage!`);
+      player.hp += item.currentAp;
+      item.currentAp = 0;
+      await deleteInventoryItem(player.id, item.item_id);
+    }
+    else {
+      roundData.roundDetails.push(`Your ${target} took ${damageAfterMitigation} damage!`);
+      await updateAp(player.id, item.item_id, item.currentAp, item.maxAp);
     }
     }
-    const skills = await getPlayerSkills(player.id);
-    socket.emit('skills', {skills});
-  });
 
 
-  socket.on('inventory', async () => {
-    const player = cache.get(`token:${socket.handshake.headers['x-authtoken']}`);
-    if(!player) {
-      return;
+  }
+  else {
+    roundData.roundDetails.push(`The ${monster.name} hit you for ${monster.strength} damage`);
+    player.hp -= monster.strength;
+  }
+
+  if(playerFinalHeal > 0) {
+    player.hp += playerFinalHeal;
+    if(player.hp > maxHp(player.constitution, player.level)) {
+      player.hp = maxHp(player.constitution, player.level);
     }
     }
-    const inventory = await getInventory(player.id);
-    socket.emit('inventory', {
-      inventory
-    });
-  });
+    roundData.roundDetails.push(`You healed for ${playerFinalHeal} HP`);
+  }
 
 
-  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`);
+  // update the players inventory for this item!
+
+  if(player.hp <= 0) {
+    player.hp = 0;
+    roundData.winner = 'monster';
+
+    roundData.roundDetails.push(`You were killed by the ${monster.name}`);
+
+    await clearFight(player.id);
+    await updatePlayer(player);
+    await clearTravelPlan(player.id);
+
+    return { roundData, monsters: [], player};
+  }
+
+  await updatePlayer(player);
+  await saveFightState(player.id, monster);
+
+  return { roundData, monsters: [], player};
+};
+
+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);
+  }
+
+  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);
+  }
+
+  const msg = req.body.message.trim();
+
+  if(!msg || !msg.length) {
+    res.sendStatus(204);
+    return;
+  }
+
+  let message: Message;
+  if(msg.startsWith('/server lmnop')) {
+    if(msg === '/server lmnop refresh-monsters') {
+      await createMonsters();
+      message = broadcastMessage('server', 'Monster refresh!');
     }
     }
-    else {
-      logger.log(`Invalid user logout`);
+    else if(msg === '/server lmnop refresh-cities') {
+      await createAllCitiesAndLocations();
+      message = broadcastMessage('server', 'Cities, Locations, and Paths refreshed!');
     }
     }
-  });
-
-  socket.on('fight', async (data: {action: 'attack' | 'cast' | 'flee', target: 'head' | 'body' | 'arms' | 'legs'}) => {
-    const authToken = `token:${socket.handshake.headers['x-authtoken']}`;
-    const player = cache.get(authToken);
-    if(!player) {
-      logger.log(`Invalid token for fight`)
-      return;
+    else if(msg === '/server lmnop refresh-shops') {
+      await createShopItems();
+      message = broadcastMessage('server', 'Refresh shop items');
     }
     }
-    const monster = await loadMonsterWithFaction(player.id);
-    const playerSkills = await getPlayerSkillsAsObject(player.id);
-    const roundData: FightRound = {
-      monster,
-      player,
-      winner: 'in-progress',
-      fightTrigger: monster.fight_trigger,
-      roundDetails: [],
-      rewards: {
-        exp: 0,
-        gold: 0,
-        levelIncrease: false
-      }
-    };
-    const equippedItems = await getEquippedItems(player.id);
-
-    // we only use this if the player successfully defeated the monster 
-    // they were fighting, then we load the other monsters in this area 
-    // so they can "fight again"
-    let potentialMonsters: MonsterForFight[] = [];
-
-    /*
-     * cumulative chance of head/arms/body/legs
-     * 0 -> 0.2 = head
-     * 0.21 -> 0.4 = arms
-     *
-     * we use the factor to decide how many decimal places 
-     * we care about
-     */
-    const factor = 100;
-    const monsterTarget = [0.2, 0.4, 0.9, 1];
-    const targets: ArmourEquipmentSlot[] = ['HEAD', 'CHEST', 'ARMS', 'LEGS'];
-    // calc weighted
-    const rand = Math.ceil(Math.random() * factor);
-    let target: ArmourEquipmentSlot = 'CHEST';
-     monsterTarget.forEach((i, idx) => {
-      if (rand > (i * factor)) {
-        target = targets[idx] as ArmourEquipmentSlot;
+    else {
+      const str = msg.split('/server lmnop ')[1];
+      if(str) {
+        message = broadcastMessage('server', str);
       }
       }
-    });
+    }
 
 
-    const boost = {
-      strength: 0,
-      constitution: 0,
-      dexterity: 0,
-      intelligence: 0,
-      damage: 0,
-      hp: 0,
-    };
 
 
-    const equipment: Map<EquipmentSlot, EquippedItemDetails> = new Map<EquipmentSlot, EquippedItemDetails>();
-    const weapons: EquippedItemDetails[] = [];
-    let anyDamageSpells: boolean = false;
-    equippedItems.forEach(item => {
-      if(item.type === 'ARMOUR') {
-        equipment.set(item.equipment_slot, item);
-      }
-      else if(item.type === 'WEAPON') {
-        weapons.push(item);
-      }
-      else if(item.type === 'SPELL') {
-        if(item.affectedSkills.includes('destruction_magic')) {
-          anyDamageSpells = true;
-        }
-        weapons.push(item);
-      }
+  }
+  else {
+    message = broadcastMessage(player.username, msg);
+    chatHistory.push(message);
+    chatHistory.slice(-10);
 
 
-      boost.strength += item.boosts.strength;
-      boost.constitution += item.boosts.constitution;
-      boost.dexterity += item.boosts.dexterity;
-      boost.intelligence += item.boosts.intelligence;
+    io.emit('chat', message);
+    res.sendStatus(204);
+  }
 
 
-      if(item.type === 'SPELL' && item.affectedSkills.includes('restoration_magic')) {
-        boost.hp += item.boosts.damage;
-      }
-      else {
-        boost.damage += item.boosts.damage;
-      }
-    });
+  if(message) {
+    io.emit('chat', message);
+  }
 
 
-    // if you flee'd, then we want to check your dex vs. the monsters
-    // but we want to give you the item/weapon boosts you need
-    // if not then you're going to get hit.
-    if(data.action === 'flee') {
-      roundData.roundDetails.push(`You managed to escape from the ${monster.name}!`)
-      roundData.winner = 'monster';
-      await clearFight(player.id);
+});
 
 
-      socket.emit('fight-over', {roundData, monsters: []});
-      return;
-    }
+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);
+
+  res.send(renderPlayerBar(player, inventory) + (await renderProfilePage(player)));
+});
+
+app.get('/player/skills', 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 attackType = data.action === 'attack' ? 'physical' : 'magical';
-    const primaryStat = data.action === 'attack' ? player.strength : player.intelligence;
-    const boostStat = data.action === 'attack' ? boost.strength : boost.intelligence;
-
-    const playerDamage = Math.floor(((primaryStat + boostStat) * 1.3) + boost.damage);
-    const skillsUsed: Record<SkillID | any, number> = {};
-    let hpHealAfterMasteries: number = -1;
-    let playerDamageAfterMasteries: number = 0;
-    // apply masteries!
-    weapons.forEach(item => {
-      item.affectedSkills.forEach(id => {
-        if(id === 'restoration_magic') {
-          if(hpHealAfterMasteries < 0) {
-            hpHealAfterMasteries = 0;
-          }
-          hpHealAfterMasteries += Skills.get(id).effect(playerSkills.get(id));
+  const skills = await getPlayerSkills(player.id);
+
+  res.send(renderSkills(skills));
+});
+
+app.get('/player/inventory', 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, items] = await Promise.all([
+    getInventory(player.id),
+    getPlayersItems(player.id)
+  ]);
+
+  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);
+  const requestedSlot = req.params.slot;
+  let desiredSlot: EquipmentSlot = inventoryItem.equipment_slot;
+
+  try {
+    // handes the situation where you're trying to equip an item 
+    // that can be equipped to any hand
+    if(inventoryItem.equipment_slot === 'ANY_HAND') {
+      if(requestedSlot === 'LEFT_HAND' || requestedSlot === 'RIGHT_HAND') {
+        // get the players current equipment in that slot!
+        if(equippedItems.some(v => {
+          return v.equipment_slot === requestedSlot || v.equipment_slot === 'TWO_HANDED';
+        })) {
+          throw new Error();
         }
         else {
         }
         else {
-          playerDamageAfterMasteries += playerDamage * Skills.get(id).effect(playerSkills.get(id));
+          desiredSlot = requestedSlot;
         }
         }
+      }
+    }
 
 
-        if(!skillsUsed[id]) {
-          skillsUsed[id] = 0;
-        }
-        skillsUsed[id]++;
-      });
+    if(requestedSlot === 'TWO_HANDED') {
+      if(equippedItems.some(v => {
+        return v.equipment_slot === 'LEFT_HAND' || v.equipment_slot === 'RIGHT_HAND';
+      })) {
+        throw new Error();
+      }
+    }
+
+
+    await equip(player.id, inventoryItem, desiredSlot);
+    const socketId = cache.get(`socket:${player.id}`).toString();
+    io.to(socketId).emit('updatePlayer', player);
+    io.to(socketId).emit('alert', {
+      type: 'success',
+      text: `You equipped your ${inventoryItem.name}`
     });
     });
+  }
+  catch(e) {
+    logger.log(e);
+  }
 
 
-    await updatePlayerSkills(player.id, skillsUsed);
+  const [inventory, items] = await Promise.all([
+    getInventory(player.id),
+    getPlayersItems(player.id)
+  ]);
 
 
-    const playerFinalDamage = (data.action === 'cast' && !anyDamageSpells) ? 0 : Math.floor(playerDamage + playerDamageAfterMasteries);
-    const playerFinalHeal = Math.floor(boost.hp + hpHealAfterMasteries);
+  res.send(renderInventoryPage(inventory, items, inventoryItem.type) + renderPlayerBar(player, inventory));
+});
 
 
-    roundData.roundDetails.push(`You targeted the monsters ${data.target.toUpperCase()} with ${attackType} damage!`);
-    let armourKey: string;
-    switch(data.target) {
-      case 'arms':
-        armourKey = 'armsAp';
-      break;
-      case 'head':
-        armourKey = 'helmAp';
-      break;
-      case 'legs':
-        armourKey = 'legsAp';
-      break;
-      case 'body':
-        armourKey = 'chestAp';
-      break;
-    }
+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(monster[armourKey] && monster[armourKey] > 0) {
-      monster[armourKey] -= playerFinalDamage;
+  if(!player) {
+    logger.log(`Couldnt find player with id ${authToken}`);
+    return res.sendStatus(400);
+  }
 
 
-      roundData.roundDetails.push(`You dealt ${playerFinalDamage} damage to their armour`);
-      if(monster[armourKey] < 0) {
-        roundData.roundDetails.push(`You destroyed the ${monster.name}'s armour!'`);
-        roundData.roundDetails.push(`You dealt ${monster[armourKey] * -1} damage to their HP`);
-        monster.hp += monster[armourKey];
-        monster[armourKey] = 0;
+  const [item, ] = await Promise.all([
+    getInventoryItem(player.id, req.params.item_id),
+    unequip(player.id, req.params.item_id)
+  ]);
+
+  const [inventory, items] = await Promise.all([
+    getInventory(player.id),
+    getPlayersItems(player.id)
+  ]);
+
+  res.send(renderInventoryPage(inventory, items, item.type) + renderPlayerBar(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;
+
+  if(fight) {
+    // ok lets display the fight screen!
+    const data: MonsterForFight = {
+      id: fight.id,
+      hp: fight.hp,
+      maxHp: fight.maxHp,
+      name: fight.name,
+      level: fight.level,
+      fight_trigger: fight.fight_trigger
+    };
+
+    res.send(renderFight(data));
+  }
+  else {
+    const travelPlan = await getTravelPlan(player.id);
+    if(travelPlan) {
+      // traveling!
+      const travelPlan = await getTravelPlan(player.id);
+
+      const closest: number = (travelPlan.current_position / travelPlan.total_distance) > 0.5 ? travelPlan.destination_id : travelPlan.source_id;
+
+      const chanceToSeeMonster = random(0, 100);
+      const things: any[] = [];
+      if(chanceToSeeMonster <= 30) {
+        const monster = await getRandomMonster([closest]);
+        things.push(monster);
       }
       }
+
+      // STEP_DELAY
+      const nextAction = cache[`step:${player.id}`] || 0;
+
+      res.send(renderTravel({
+        things,
+        nextAction,
+        closestTown: closest,
+        walkingText: ''
+      }));
     }
     else {
     }
     else {
-      roundData.roundDetails.push(`You hit the ${monster.name} for ${playerFinalDamage} damage.`);
-      monster.hp -= playerFinalDamage;
+      // display the city info!
+      const [city, locations, paths] = await Promise.all([
+        getCityDetails(player.city_id),
+        getAllServices(player.city_id),
+        getAllPaths(player.city_id)
+      ]);
+
+      res.send(await renderMap({city, locations, paths}, closestTown));
     }
 
     }
 
-    if(monster.hp <= 0) {
-      roundData.monster.hp = 0;
-      roundData.winner = 'player';
+  }
+});
 
 
-      roundData.rewards.exp = monster.exp;
-      roundData.rewards.gold = monster.gold;
+// 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);
+  }
 
 
-      player.gold += monster.gold;
-      player.exp += monster.exp;
+  const item = await getShopEquipment(parseInt(req.params.item_id), parseInt(req.params.location_id));
 
 
-      if(player.exp >= expToLevel(player.level + 1)) {
-        player.exp -= expToLevel(player.level + 1)
-        player.level++;
-        roundData.rewards.levelIncrease = true;
-        let statPointsGained = 1;
+  if(!item) {
+    logger.log(`Invalid item [${req.params.item_id}]`);
+    return res.sendStatus(400);
+  }
 
 
-        if(player.profession !== 'Wanderer') {
-          statPointsGained = 2;
-        }
+  if(player.gold < item.cost) {
+    res.send(Alert.ErrorAlert(`Sorry, you need at least ${item.cost.toLocaleString()}G to purchase this.`));
+    return;
+  }
 
 
-        player.stat_points += statPointsGained;
+  player.gold -= item.cost;
 
 
-        roundData.roundDetails.push(`You gained ${statPointsGained} stat points!`);
+  await updatePlayer(player);
+  await addInventoryItem(player.id, item);
 
 
-        player.hp = maxHp(player.constitution, player.level);
-      }
-      // get the monster location if it was an EXPLORED fight
-      if(roundData.fightTrigger === 'explore') {
-        const rawMonster = await loadMonster(monster.ref_id);
-        const monsterList  = await getMonsterList(rawMonster.location_id);
-        potentialMonsters = monsterList.map(monster => {
-          return {
-            id: monster.id,
-            name: monster.name,
-            level: monster.level,
-            hp: monster.hp,
-            maxHp: monster.maxHp,
-            fight_trigger: 'explore'
-          }
-        });
-      }
+  const equippedItems = await getEquippedItems(player.id);
 
 
-      await clearFight(player.id);
-      await updatePlayer(player);
-      cache.set(authToken, player);
-      socket.emit('fight-over', {roundData, monsters: potentialMonsters});
-      return;
-    }
+  res.send(renderPlayerBar(player, equippedItems) + Alert.SuccessAlert(`You purchased ${item.name}`));
+});
 
 
-    roundData.roundDetails.push(`The ${monster.name} targeted your ${target}!`);
-    if(equipment.has(target)) {
-      const item = equipment.get(target);
-      // apply mitigation!
-      const mitigationPercentage = item.boosts.damage_mitigation || 0;
-      const damageAfterMitigation = Math.floor(monster.strength * ((100-mitigationPercentage)/100));
-
-      item.currentAp -= damageAfterMitigation;
-
-      if(item.currentAp < 0) {
-        roundData.roundDetails.push(`Your ${item.name} amour was destroyed`);
-        roundData.roundDetails.push(`The ${monster.name} hit your HP for ${item.currentAp * -1} damage!`);
-        player.hp += item.currentAp;
-        item.currentAp = 0;
-        await deleteInventoryItem(player.id, item.item_id);
-      }
-      else {
-        roundData.roundDetails.push(`Your ${target} took ${damageAfterMitigation} damage!`);
-        await updateAp(player.id, item.item_id, item.currentAp, item.maxAp);
-      }
+// 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);
+  }
 
 
-    }
-    else {
-      roundData.roundDetails.push(`The ${monster.name} hit you for ${monster.strength} damage`);
-      player.hp -= monster.strength;
-    }
+  const item: (ShopItem & Item) = await getItemFromShop(parseInt(req.params.item_id), parseInt(req.params.location_id));
 
 
-    if(playerFinalHeal > 0) {
-      player.hp += playerFinalHeal;
-      if(player.hp > maxHp(player.constitution, player.level)) {
-        player.hp = maxHp(player.constitution, player.level);
-      }
-      roundData.roundDetails.push(`You healed for ${playerFinalHeal} HP`);
-    }
+  if(!item) {
+    logger.log(`Invalid item [${req.params.item_id}]`);
+    return res.sendStatus(400);
+  }
 
 
-    // update the players inventory for this item!
+  if(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;
+  }
 
 
-    if(player.hp <= 0) {
-      player.hp = 0;
-      roundData.winner = 'monster';
+  player.gold -= item.price_per_unit;
 
 
-      roundData.roundDetails.push(`You were killed by the ${monster.name}`);
+  await updatePlayer(player);
+  await givePlayerItem(player.id, item.id, 1);
 
 
-      await clearFight(player.id);
-      await updatePlayer(player);
-      await clearTravelPlan(player.id);
+  const equippedItems = await getEquippedItems(player.id);
 
 
-      cache.set(authToken, player);
+  res.send(renderPlayerBar(player, equippedItems) + Alert.SuccessAlert(`You purchased a ${item.name}`));
+});
 
 
-      socket.emit('fight-over', {roundData, monsters: []});
-      return;
-    }
+// 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);
+  }
 
 
-    await updatePlayer(player);
-    await saveFightState(player.id, monster);
-    cache.set(authToken, player);
+  const equipment = await getShopEquipment(parseInt(req.params.item_id), parseInt(req.params.location_id));
 
 
-    calcAp(equippedItems, socket);
-    socket.emit('fight-round', roundData);
-  });
+  if(!equipment) {
+    logger.log(`Invalid equipment [${req.params.item_id}]`);
+    return res.sendStatus(400);
+  }
 
 
-  // this is a special event to let the client know it can start 
-  // requesting data
-  socket.emit('ready');
+  let html = `
+<dialog>
+  <div class="item-modal-overview">
+    <div class="icon">
+      <img src="https://via.placeholder.com/64x64" title="${equipment.name}" alt="${equipment.name}"> 
+    </div>
+    <div>
+      ${renderEquipmentDetails(equipment, player)}
+    </div>
+  </div>
+  <div class="actions">
+    <button hx-put="/location/${equipment.location_id}/equipment/${equipment.id}" formmethod="dialog" value="cancel">Buy</button>
+    <button class="close-modal" formmethod="dialog" value="cancel">Cancel</button>
+  </div>
+</dialog>
+`;
+
+  res.send(html);
 });
 
 });
 
-function authEndpoint(req: Request, res: Response, next: any) {
-  const authToken = req.headers['x-authtoken'];
-  if(!authToken) {
-    logger.log(`Invalid auth token ${authToken}`);
-    res.sendStatus(400)
+// 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);
   }
   }
-  else {
-    next()
+
+  const item: (ShopItem & Item) = await getItemFromShop(parseInt(req.params.item_id), parseInt(req.params.location_id));
+
+  if(!item) {
+    logger.log(`Invalid item [${req.params.item_id}]`);
+    return res.sendStatus(400);
   }
   }
-}
 
 
-app.get('/city/:id', async (req: Request, res: Response) => {
-  const id = parseInt(req.params.id);
-  if(!id || isNaN(id)) {
+  let html = `
+<dialog>
+  <div class="item-modal-overview">
+    <div class="icon">
+      <img src="/assets/img/icons/items/${item.icon_name}" title="${item.name}" alt="${item.name}"> 
+    </div>
+    <div>
+      <h4>${item.name}</h4>
+      <p>${item.description}</p>
+    </div>
+  </div>
+  <div class="actions">
+    <button hx-put="/location/${item.location_id}/items/${item.id}" formmethod="dialog" value="cancel">Buy</button>
+    <button class="close-modal" formmethod="dialog" value="cancel">Cancel</button>
+  </div>
+</dialog>
+`;
+
+  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);
   }
     return res.sendStatus(400);
   }
-  const [city, locations, paths] = await Promise.all([
-    getCityDetails(id),
-    getAllServices(id),
-    getAllPaths(id)
-  ]);
 
 
-  res.json({city, locations, paths});
+  const item: PlayerItem = await getItemFromPlayer(player.id, parseInt(req.params.item_id));
+
+  if(!item) {
+    console.log(`Can't find item [${req.params.item_id}]`);
+    return;
+  }
+
+  if(item.amount < 1) {
+    res.send(Alert.ErrorAlert(`You dont have enough ${item.name}`));
+    return;
+  }
+
+  item.amount -= 1;
+
+  switch(item.effect_name) {
+    case 'heal_small':
+      const hpGain = HealthPotionSmall.effect(player);
+
+      player.hp += hpGain;
+
+      if(player.hp > maxHp(player.constitution, player.level)) {
+        player.hp = maxHp(player.constitution, player.level);
+      }
+    break;
+  }
+
+  await updateItemCount(player.id, item.item_id, -1);
+  await updatePlayer(player);
+
+  const inventory = await getInventory(player.id);
+  const equippedItems = inventory.filter(i => i.is_equipped);
+  const items = await getPlayersItems(player.id);
+
+  res.send(
+    [
+      renderPlayerBar(player, equippedItems),
+      renderInventoryPage(inventory, items, 'ITEMS'),
+      Alert.SuccessAlert(`You used the ${item.name}`)
+    ].join("")
+  );
+
 });
 
 });
 
-app.get('/state', 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)
   const authToken = req.headers['x-authtoken'].toString();
   const player: Player = await loadPlayer(authToken)
-  let closestTown: number = player.city_id;
+  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));
+
+  if(!item) {
+    logger.log(`Invalid item [${req.params.item_id}]`);
+    return res.sendStatus(400);
+  }
+
+  let html = `
+<dialog>
+  <div class="item-modal-overview">
+    <div class="icon">
+      <img src="/assets/img/icons/items/${item.icon_name}" title="${item.name}" alt="${item.name}"> 
+    </div>
+    <div>
+      <h4>${item.name}</h4>
+      <p>${item.description}</p>
+    </div>
+  </div>
+  <div class="actions">
+    <button hx-put="/item/${item.item_id}" formmethod="dialog" value="cancel" hx-target="#inventory">Use</button>
+    <button class="close-modal" formmethod="dialog" value="cancel">Cancel</button>
+  </div>
+</dialog>
+`;
+
+  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);
   }
 
   if(!player) {
     logger.log(`Couldnt find player with id ${authToken}`);
     return res.sendStatus(400);
   }
 
-  const fight = await loadMonsterFromFight(player.id);
+  const location = await getService(parseInt(req.params.location_id));
 
 
-  // check if the player is exploring somewhere!
-  const travelPlan = await getTravelPlan(player.id);
+  if(!location || location.city_id !== player.city_id) {
+    logger.log(`Invalid location: [${req.params.location_id}]`);
+    res.sendStatus(400);
+  }
+  const [shopEquipment, shopItems] = await Promise.all([
+    listShopItems({location_id: location.id}),
+    getShopItems(location.id)
+  ]);
 
 
-  if(travelPlan) {
-    closestTown = (travelPlan.current_position / travelPlan.total_distance) > 0.5 ? travelPlan.destination_id : travelPlan.source_id;
-  }
-  
-  const state = {
-    fight: fight || null,
-    closestTown,
-    travel: travelPlan ? {
-      things: [],
-      closestTown,
-      walkingText: 'You keep walking...'
-    } : null
-  };
+  const html = await renderStore(shopEquipment, shopItems, player);
 
 
-  res.json(state);
+  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);
+  }
+
+  const location = await getService(parseInt(req.params.location_id));
+  if(!location || location.city_id !== player.city_id) {
+
+    logger.log(`Invalid location: [${req.params.location_id}]`);
+    res.sendStatus(400);
+  }
+
+  const monsters: Monster[] = await getMonsterList(location.id);
+  res.send(renderMonsterSelector(monsters));
 });
 
 app.post('/travel', authEndpoint, async (req: Request, res: Response) => {
 });
 
 app.post('/travel', authEndpoint, async (req: Request, res: Response) => {
@@ -585,6 +929,50 @@ app.post('/travel', authEndpoint, async (req: Request, res: Response) => {
   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);
+
+  if(!monster) {
+    res.send(Alert.ErrorAlert('Not in a fight'));
+    return;
+  }
+
+  const fightData  = await fightRound(player, monster, {
+    action: req.body.action,
+    target: req.body.fightTarget
+  });
+
+  let html = renderFight(
+    monster,
+    renderRoundDetails(fightData.roundData),
+    fightData.roundData.winner === 'in-progress'
+  );
+
+  if(fightData.monsters.length && monster.fight_trigger === 'explore') {
+    html += renderMonsterSelector(fightData.monsters, monster.ref_id);
+  }
+
+  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 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 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();
 
 app.post('/fight', authEndpoint, async (req: Request, res: Response) => {
   const authToken = req.headers['x-authtoken'].toString();
@@ -601,8 +989,7 @@ app.post('/fight', authEndpoint, async (req: Request, res: Response) => {
   }
 
   const monsterId: number = req.body.monsterId;
   }
 
   const monsterId: number = req.body.monsterId;
-  const fightTrigger: FightTrigger = req.body.fightTrigger;
-
+  const fightTrigger: FightTrigger = req.body.fightTrigger ?? 'travel';
 
   if(!monsterId) {
     logger.log(`Missing monster Id ${monsterId}`);
 
   if(!monsterId) {
     logger.log(`Missing monster Id ${monsterId}`);
@@ -623,6 +1010,7 @@ app.post('/fight', authEndpoint, async (req: Request, res: Response) => {
 
   const fight = await createFight(player.id, monster, fightTrigger);
 
 
   const fight = await createFight(player.id, monster, fightTrigger);
 
+
   const data: MonsterForFight = {
     id: fight.id,
     hp: fight.hp,
   const data: MonsterForFight = {
     id: fight.id,
     hp: fight.hp,
@@ -631,9 +1019,116 @@ app.post('/fight', authEndpoint, async (req: Request, res: Response) => {
     level: fight.level,
     fight_trigger: fight.fight_trigger
   };
     level: fight.level,
     fight_trigger: fight.fight_trigger
   };
-  res.json(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);
+  }
+
+  const travelPlan = await getTravelPlan(player.id);
+  if(!travelPlan) {
+    res.send(Alert.ErrorAlert('You don\'t have a travel plan'));
+    return;
+  }
+
+  if(cache[stepTimerKey]) {
+    if(cache[stepTimerKey] > Date.now()) {
+      res.send(Alert.ErrorAlert('Hmm.. travelling too quickly'));
+      return;
+    }
+  }
+
+  travelPlan.current_position++;
+
+  if(travelPlan.current_position >= travelPlan.total_distance) {
+    const travel = await completeTravel(player.id);
+
+    player.city_id = travel.destination_id;
+    await movePlayer(travel.destination_id, player.id);
+
+    const [city, locations, paths] = await Promise.all([
+      getCityDetails(travel.destination_id),
+      getAllServices(travel.destination_id),
+      getAllPaths(travel.destination_id)
+    ]);
+
+    delete cache[stepTimerKey];
+    res.send(await renderMap({city, locations, paths}, player.city_id));
+  }
+  else {
+    const walkingText: string[] = [
+      'You take a step forward',
+      'You keep moving'
+    ];
+    // update existing plan..
+    // decide if they will run into anything
+    const travelPlan = await stepForward(player.id);
+
+    const closest: number = (travelPlan.current_position / travelPlan.total_distance) > 0.5 ? travelPlan.destination_id : travelPlan.source_id;
+
+    const chanceToSeeMonster = random(0, 100);
+    const things: any[] = [];
+    if(chanceToSeeMonster <= 30) {
+      const monster = await getRandomMonster([closest]);
+      things.push(monster);
+    }
+
+    // STEP_DELAY
+    const nextAction = Date.now() + 3000;
+
+    cache[stepTimerKey] = nextAction;
+
+    res.send(renderTravel({
+      things,
+      nextAction,
+      closestTown: closest,
+      walkingText: sample(walkingText)
+    }));
+
+  }
+});
+
+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) {
+    logger.log(`Player didn\'t have enough hp`);
+    res.send(Alert.ErrorAlert('Sorry, you need some HP to start travelling.'));
+    return;
+  }
+
+  const destination = await getCityDetails(parseInt(req.params.destination_id));
+
+  if(!destination) {
+    res.send(Alert.ErrorAlert(`Thats not a valid desination`));
+    return;
+  }
+
+  await travel(player, destination.id);
+
+  res.send(renderTravel({
+    things: [],
+    nextAction: 0,
+    walkingText: '',
+    closestTown: player.city_id
+  }));
+});
+
+
 app.post('/signup', async (req: Request, res: Response) => {
   const {username, password} = req.body;
   const authToken = req.headers['x-authtoken'];
 app.post('/signup', async (req: Request, res: Response) => {
   const {username, password} = req.body;
   const authToken = req.headers['x-authtoken'];
@@ -691,6 +1186,14 @@ app.post('/login', async (req: Request, res: Response) => {
   }
 });
 
   }
 });
 
+app.get('/status', async (req: Request, res: Response) => {
+  res.send(`
+  <div id="server-stats" hx-trigger="load delay:15s" hx-get="/status" hx-swap="outerHTML">
+    ${io.sockets.sockets.size} Online (v${version})
+  </div>
+`);
+})
+
 server.listen(process.env.API_PORT, () => {
   logger.log(`Listening on port ${process.env.API_PORT}`);
 });
 server.listen(process.env.API_PORT, () => {
   logger.log(`Listening on port ${process.env.API_PORT}`);
 });
index 748c79d6ce9906a9c6830b15caddd9b0ec30af14..d82d4b64c39f06a9460a338fa1f8e3361bf61234 100644 (file)
@@ -3,6 +3,7 @@ import bcrypt from 'bcrypt';
 import { loadPlayer } from './player';
 import { Auth } from '../shared/auth';
 import { db } from './lib/db';
 import { loadPlayer } from './player';
 import { Auth } from '../shared/auth';
 import { db } from './lib/db';
+import { Request, Response } from 'express';
 
 export async function signup(playerId: string, username: string, password: string): Promise<void> {
   const salt = await bcrypt.genSalt(10);
 
 export async function signup(playerId: string, username: string, password: string): Promise<void> {
   const salt = await bcrypt.genSalt(10);
@@ -56,3 +57,14 @@ export async function login(username: string, password: string): Promise<Player>
   }
 
 }
   }
 
 }
+
+export function authEndpoint(req: Request, res: Response, next: any) {
+  const authToken = req.headers['x-authtoken'];
+  if(!authToken) {
+    console.log(`Invalid auth token ${authToken}`);
+    res.sendStatus(400)
+  }
+  else {
+    next()
+  }
+}
index 9a62bdfed3fe533b247f00c5e42cd3b47437d942..c5c2b6717e4cbec2471512b6ca3262979559e891 100644 (file)
@@ -1,10 +1,10 @@
-import {InventoryItem, ShopItem} from "../shared/inventory";
+import {InventoryItem, ShopEquipment} from "../shared/inventory";
 import { v4 as uuid } from 'uuid';
 import { db} from './lib/db';
 import {EquippedItemDetails} from "../shared/equipped";
 
 
 import { v4 as uuid } from 'uuid';
 import { db} from './lib/db';
 import {EquippedItemDetails} from "../shared/equipped";
 
 
-export async function addInventoryItem(playerId: string, item: ShopItem) {
+export async function addInventoryItem(playerId: string, item: ShopEquipment) {
   const inventoryItem: InventoryItem = {
     player_id: playerId,
     item_id: uuid(),
   const inventoryItem: InventoryItem = {
     player_id: playerId,
     item_id: uuid(),
diff --git a/src/server/items.ts b/src/server/items.ts
new file mode 100644 (file)
index 0000000..1811923
--- /dev/null
@@ -0,0 +1,50 @@
+import { db } from './lib/db';
+import {Item, PlayerItem, ShopItem} from '../shared/items';
+
+export async function getShopItems(location_id: number): Promise<(ShopItem & Item)[]> {
+  const res = await db.raw(`select si.*, i.* from shop_items si
+    join items i on si.item_id = i.id where si.location_id = ?`, [location_id]);
+
+  return res.rows as (ShopItem & Item)[];
+}
+
+export async function getItemFromShop(item_id: number, location_id: number): Promise<ShopItem & Item> {
+  const res = await db.raw(`select si.*, i.* from shop_items si
+    join items i on si.item_id = i.id where si.location_id = ? and item_id = ?`, [location_id, item_id]);
+
+  if(res.rows.length === 1) {
+    return res.rows[0] as (ShopItem & Item);
+  }
+}
+
+export async function givePlayerItem(player_id: string, item_id: number, amount: number = 1) {
+  const res = await db.raw(`insert into player_items (item_id, player_id, amount) 
+      values (?, ?, ?) 
+      on conflict(item_id, player_id) 
+      do update set amount = player_items.amount + ? returning *`, [item_id, player_id, amount, amount]);
+
+  return res.rows[0] as {item_id: number, player_id: string, amount: number};
+}
+
+export async function getPlayersItems(player_id: string): Promise<PlayerItem[]> {
+  const res = await db.raw(`select pi.*, i.* from player_items pi 
+join items i on pi.item_id = i.id where pi.player_id = ? and amount > 0`, [player_id]);
+  return res.rows as PlayerItem[];
+}
+
+export async function getItemFromPlayer(player_id: string, item_id: number): Promise<PlayerItem | undefined> {
+  const res = await db.raw(`select pi.*, i.* from player_items pi 
+join items i on pi.item_id = i.id where pi.player_id = ? and pi.item_id = ?`, [player_id, item_id]);
+  if(res.rows.length === 1) {
+    return res.rows[0] as PlayerItem;
+  }
+}
+
+export async function updateItemCount(player_id: string, item_id: number, delta: number): Promise<number> {
+  const rows = await db('player_items').increment('amount', delta).where({
+    player_id,
+    item_id
+  }).returning('*');
+
+  return rows[0].amount;
+}
diff --git a/src/server/locations/healer/index.ts b/src/server/locations/healer/index.ts
new file mode 100644 (file)
index 0000000..bd3ba1c
--- /dev/null
@@ -0,0 +1,171 @@
+import { Request, Response, Router } from "express";
+import { maxHp, Player } from "../../../shared/player";
+import { authEndpoint } from '../../auth';
+import { logger } from "../../lib/logger";
+import { loadPlayer, updatePlayer } from "../../player";
+import { getCityDetails, getService } from '../../map';
+import { sample } from 'lodash';
+import { City, Location } from "../../../shared/map";
+import { renderPlayerBar } from "../../views/player-bar";
+import { getEquippedItems } from "../../inventory";
+
+export const router = Router();
+
+type TextSegment = 'intro' | 'insufficient_money' | 'heal_successful';
+
+type HealText = Record<TextSegment, string[]>;
+
+const healCost = 10;
+
+const defaultTexts: HealText = {
+  intro: [
+    `Welcome traveller, I am {{NAME}}, Healer of {{CITY_NAME}}`,
+    "Please come in traveller, I am {{NAME}}, Healer of {{CITY_NAME}}",
+  ],
+  insufficient_money: [
+    "Sorry friend, you don't have enough money..",
+    "Sorry, that won't be enough..",
+    "Healing is hard work.. I'm afraid that won't cover it.."
+  ],
+  heal_successful: [
+    "I hope you feel better now",
+    "Good luck on your travels!",
+    "Glad to be of service..."
+  ]
+};
+
+// overrides for specific areas
+const playerTexts: Record<number, HealText> = {
+  [8]: {
+    intro: [
+      'Welcome to Midfield traveller, I am Casim - healer in these parts',
+      'I am Casim the Healer here... how are you enjoying your stay at Midfield?'
+    ],
+    insufficient_money: [
+      'Sorry friend, you don\'t have enough money',
+      'Look.. I\'m sorry.. that won\'t be enough...'
+    ],
+    heal_successful: [
+      'Glad to help!'
+    ]
+  },
+  [16]: {
+    intro: [
+      'Ah, welcome to Wildegard, one of the few safehavens in the Akari Woods. I am Adovras, healer in these parts.',
+      'Welcome traveller, I am Adovras - healer in these parts'
+    ],
+    insufficient_money: [
+      `Sorry friend, you don't have enough money...`
+    ],
+    heal_successful: [
+      "Hope this small healing will be helpful on your journeys"
+    ]
+
+  },
+  [11]: {
+    intro: [
+      'Ah, welcome traveler - I am Uthar, healer of Davelfell',
+      'Hello, I am Uthar, healer of Davelfell',
+      'Sorry I\'m a bit busy today, I am Uthar, healer of Davelfell'
+    ],
+    insufficient_money: [
+      "Bah, don't bother me if you don't have the money",
+      "Look, I'm very busy - come back when you have the money"
+    ],
+    heal_successful: [
+      "*Fizz* *POOF* YOU'RE HEALED!"
+    ]
+  }
+}
+
+function getText(type: TextSegment, location: Location, city: City): string {
+  let selected = sample(defaultTexts[type]);
+
+  if(playerTexts[location.id]) {
+    if(playerTexts[location.id][type].length) {
+      selected = sample(playerTexts[location.id][type]);
+    }
+  }
+
+  return selected.replace("{{NAME}}", location.name).replace("{{CITY_NAME}}", city.name);
+
+}
+
+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);
+  }
+
+  const service = await getService(parseInt(req.params.location_id));
+  const city = await getCityDetails(service.city_id);
+
+  if(!service || service.city_id !== player.city_id) {
+    logger.log(`Invalid location: [${req.params.location_id}]`);
+    res.sendStatus(400);
+  }
+
+  const text: string[] = [];
+
+  text.push(`<p><b>${service.name}</b></p>`);
+  text.push(`<p>"${getText('intro', service, city)}"</p>`);
+
+
+  if(player.hp === maxHp(player.constitution, player.level)) {
+    text.push(`<p>You're already at full health?</p>`);
+  }
+  else {
+    if(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>`);
+    }
+    else {
+      text.push(`<p><button type="button" hx-post="/city/services/city:services:healer:heal/${service.id}" hx-target="#explore">Heal for ${healCost}g!</button></p>`);
+    }
+
+  }
+
+  res.send(`<div>${text.join("\n")}</div>`);
+});
+
+
+
+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);
+  }
+
+  const service = await getService(parseInt(req.params.location_id));
+  const city = await getCityDetails(service.city_id);
+
+  if(!service || service.city_id !== player.city_id) {
+    logger.log(`Invalid location: [${req.params.location_id}]`);
+    res.sendStatus(400);
+  }
+
+  const text: string[] = [];
+  text.push(`<p><b>${service.name}</b></p>`);
+
+  const cost = player.gold <= (healCost * 2) ? 0 : healCost;
+
+  if(player.gold < cost) {
+    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;
+
+    await updatePlayer(player);
+    const inventory = await getEquippedItems(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>');
+    res.send(`<div>${text.join("\n")}</div>` + renderPlayerBar(player, inventory));
+  }
+});
index 67cd225305b781d85f83d7c9a9fde7efe099dc05..54f0de8a6becc57f82f27f1f758f318e5ed6b857 100644 (file)
@@ -12,9 +12,9 @@ export async function getAllServices(city_id: number): Promise<Location[]> {
             .orderBy('display_order');
 }
 
             .orderBy('display_order');
 }
 
-export async function getService(serverId: number): Promise<Location> {
+export async function getService(location_id: number): Promise<Location> {
   return db.select('*').first().from<Location>('locations').where({
   return db.select('*').first().from<Location>('locations').where({
-    id: serverId
+    id: location_id
   });
 }
 
   });
 }
 
@@ -85,7 +85,7 @@ export async function stepForward(player_id: string): Promise<Travel> {
 }
 
 export async function clearTravelPlan(player_id: string): Promise<Travel> {
 }
 
 export async function clearTravelPlan(player_id: string): Promise<Travel> {
-  return completeTravel(player_id);
+  return db('travel').where({player_id}).delete();
 }
 
 export async function completeTravel(player_id: string): Promise<Travel> {
 }
 
 export async function completeTravel(player_id: string): Promise<Travel> {
index 1d5f0fd44608e0d49b23e1761eea528c31a260f9..7565146436f687578c619fdae62d0498bf99b9fa 100644 (file)
@@ -31,13 +31,13 @@ export async function loadMonster(id: number): Promise<Monster> {
   }).first();
 }
 
   }).first();
 }
 
-export async function loadMonsterFromFight(authToken: string): Promise<Fight> {
+export async function loadMonsterFromFight(player_id: string): Promise<Fight> {
   return await db.first().select('*').from<Fight>('fight').where({
   return await db.first().select('*').from<Fight>('fight').where({
-    player_id: authToken,
+    player_id,
   });
 }
 
   });
 }
 
-export async function loadMonsterWithFaction(authToken: string): Promise<MonsterWithFaction> {
+export async function loadMonsterWithFaction(player_id: string): Promise<MonsterWithFaction> {
   const res = await db.raw(`
                       select 
                         f.*, fa.id as faction_id, fa.name as faction_name
   const res = await db.raw(`
                       select 
                         f.*, fa.id as faction_id, fa.name as faction_name
@@ -46,7 +46,7 @@ export async function loadMonsterWithFaction(authToken: string): Promise<Monster
                       left outer join factions fa on m.faction_id = fa.id
                       where f.player_id = ?
                         limit 1
                       left outer join factions fa on m.faction_id = fa.id
                       where f.player_id = ?
                         limit 1
-                      `, [authToken]);
+                      `, [player_id]);
 
   return res.rows[0];
 }
 
   return res.rows[0];
 }
diff --git a/src/server/shopEquipment.ts b/src/server/shopEquipment.ts
new file mode 100644 (file)
index 0000000..ab28a6c
--- /dev/null
@@ -0,0 +1,24 @@
+import { db } from './lib/db';
+import {ShopEquipment} from '../shared/inventory';
+
+export function listShopItems(where: Partial<ShopEquipment>): Promise<ShopEquipment[]> {
+  return db.select('*').from<ShopEquipment>('shop_equipment')
+        .where(where)
+        .orderBy('type')
+        .orderBy('equipment_slot')
+        .orderByRaw(`requirements->>'level' asc`);
+}
+
+export function getShopEquipment(item_id: number, location_id: number): Promise<ShopEquipment> {
+  return db.select('*').from<ShopEquipment>('shop_equipment').where({
+    id: item_id,
+    location_id
+  }).first();
+
+}
+
+export function getShopItem(id: number): Promise<ShopEquipment> {
+  return db.select('*').from<ShopEquipment>('shop_equipment').where({
+    id
+  }).first();
+}
diff --git a/src/server/shopItem.ts b/src/server/shopItem.ts
deleted file mode 100644 (file)
index 69c55e6..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-import { db } from './lib/db';
-import {ShopItem} from '../shared/inventory';
-
-export function listShopItems(where: Partial<ShopItem>): Promise<ShopItem[]> {
-  return db.select('*').from<ShopItem>('shop_items')
-        .where(where)
-        .orderBy('type')
-        .orderBy('equipment_slot')
-        .orderByRaw(`requirements->>'level' asc`);
-}
-
-export function getShopItem(id: number): Promise<ShopItem> {
-  return db.select('*').from<ShopItem>('shop_items').where({
-    id
-  }).first();
-}
diff --git a/src/server/views/alert.ts b/src/server/views/alert.ts
new file mode 100644 (file)
index 0000000..8f0fb32
--- /dev/null
@@ -0,0 +1,16 @@
+import { v4 as uuid } from 'uuid';
+
+export function Alert(type: 'error' | 'success', text: string): string {
+  return `<div hx-swap-oob="afterbegin:#alerts">
+  <div class="alert ${type}" id="alert-${uuid()}">${text}</div>
+</div>
+`
+}
+
+export function SuccessAlert(text: string): string {
+  return Alert('success', text);
+}
+
+export function ErrorAlert(text: string): string {
+  return Alert('error', text);
+}
diff --git a/src/server/views/chat.ts b/src/server/views/chat.ts
new file mode 100644 (file)
index 0000000..bca4f8c
--- /dev/null
@@ -0,0 +1,8 @@
+import {Message} from "../../shared/message";
+
+export function renderChatMessage(msg: Message): string {
+    return `<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>`;
+}
diff --git a/src/server/views/fight.ts b/src/server/views/fight.ts
new file mode 100644 (file)
index 0000000..fdd51b4
--- /dev/null
@@ -0,0 +1,68 @@
+import { FightRound } from "shared/fight";
+import { MonsterForFight } from "../../shared/monsters";
+
+export function renderRoundDetails(roundData: FightRound): string {
+  let html: string[] = roundData.roundDetails.map(d => `<div>${d}</div>`);
+
+  switch(roundData.winner) {
+    case '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}`);
+      }
+    break;
+    case 'monster':
+      // prompt to return to town and don't let them do anything
+      html.push(`<p>You were killed...</p>`);
+      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');
+    break;
+  }
+
+
+  return html.join("\n");
+}
+
+export function renderFight(monster: MonsterForFight, results: string = '', displayFightActions: boolean = true) {
+  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">
+      ${displayFightActions ? `
+      <form hx-post="/fight/turn" hx-target="#fight-container">
+        <select id="fight-target" name="fightTarget">
+          <option value="head">Head</option>
+          <option value="body">Body</option>
+          <option value="arms">Arms</option>
+          <option value="legs">Legs</option>
+        </select>
+        <button type="submit" class="fight-action" name="action" value="attack">Attack</button>
+        <button type="submit" class="fight-action" name="action" value="cast">Cast</button>
+        <button type="submit" class="fight-action" name="action" value="flee">Flee</button>
+      </form>
+      `: ''}
+      </div>
+  </form>
+    <div id="fight-results">${results}</div>
+  </div>`;
+
+  return html;
+}
diff --git a/src/server/views/inventory.ts b/src/server/views/inventory.ts
new file mode 100644 (file)
index 0000000..08fce8e
--- /dev/null
@@ -0,0 +1,186 @@
+import { EquipmentSlot, InventoryType } from "shared/inventory";
+import { EquippedItemDetails } from "../../shared/equipped";
+import { PlayerItem } from "../../shared/items";
+import { capitalize } from "lodash";
+
+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 renderInventoryItems(items: PlayerItem[]): string {
+  return items.map(item => {
+    return `
+<div class="player-item" hx-get="/modal/items/${item.item_id}" hx-target="#modal-wrapper">
+<img src="/assets/img/icons/items/${item.icon_name}" title="${item.name}">
+<span class="amount">${item.amount.toLocaleString()}</span>
+</div>`;
+  }).join("<br>");
+}
+
+
+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 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 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 renderInventorySection(inventory: EquippedItemDetails[]): string {
+  return inventory.map(item => {
+    return renderInventoryItem(item, item => {
+      if(item.is_equipped) {
+        return `<button type="button" class="unequip-item error" hx-post="/player/unequip/${item.item_id}">Unequip</button>`;
+      }
+      else {
+        if(item.equipment_slot === 'ANY_HAND') {
+          return `<button type="button" class="equip-item" hx-post="/player/equip/${item.item_id}/LEFT_HAND">Equip L</button>
+<button type="button" class="equip-item" hx-post="/player/equip/${item.item_id}/RIGHT_HAND">Equip R</button>`;
+        }
+        else if(item.equipment_slot === 'LEFT_HAND') {
+          return `<button type="button" class="equip-item" hx-post="/player/equip/${item.item_id}/${item.equipment_slot}">Equip Left</button>`;
+        }
+        else if(item.equipment_slot === 'RIGHT_HAND') {
+          return `<button type="button" class="equip-item" hx-post="/player/equip/${item.item_id}/${item.equipment_slot}">Equip Right</button>`;
+        }
+        else {
+          return `<button type="button" class="equip-item" hx-post="/player/equip/${item.item_id}/${item.equipment_slot}">Equip</button>`;
+        }
+      }
+    })
+  }).join("\n");
+}
+
+
+export function renderInventoryPage(inventory: EquippedItemDetails[], items: PlayerItem[], requestedSlot: string = 'ARMOUR') {
+  const sectionedInventory: {ARMOUR: EquippedItemDetails[], WEAPON: EquippedItemDetails[], SPELL: EquippedItemDetails[], ITEMS: PlayerItem[]} = {
+    ARMOUR: [],
+    WEAPON: [],
+    SPELL: [],
+    ITEMS: []
+  };
+
+  inventory.forEach(item => {
+    sectionedInventory[item.type].push(item);
+  });
+  items.forEach(item => {
+    sectionedInventory.ITEMS.push(item);
+  });
+
+  const html = `
+  <div id="inventory-page" hx-target="section#inventory" hx-swap="true">
+    <div id="character-summary">
+      ${renderEquipmentPlacementGrid(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="${type === requestedSlot ? 'active': ''}">${capitalize(type)}</a>`;
+        }).join("")}
+      </nav>
+
+      <div class="inventory-listing listing">
+        ${Object.keys(sectionedInventory).map((type) => {
+          return `<div class="filter-result inventory-${type} ${type === requestedSlot ? 'active': 'hidden'}" data-filter="${type}" id="filter_${type}">
+          ${type === 'ITEMS' ? renderInventoryItems(sectionedInventory[type]) : renderInventorySection(sectionedInventory[type])}
+          </div>`;
+        }).join("")}
+      </div>
+    </div>
+  </div>
+  `;
+
+  return html;
+
+}
diff --git a/src/server/views/map.ts b/src/server/views/map.ts
new file mode 100644 (file)
index 0000000..6f53fea
--- /dev/null
@@ -0,0 +1,45 @@
+import { LocationType, Location, Path, City } from "../../shared/map";
+
+export async function renderMap(data: { city: City, locations: Location[], paths: Path[]}, closestTown: number): Promise<string> {
+
+  if(!data) {
+    console.error('oh no.. this got triggered without any city data');
+  }
+
+  const servicesParsed: Record<LocationType, string[]> = {
+    'SERVICES': [],
+    'STORES': [],
+    'EXPLORE': []
+  };
+
+  data.locations.forEach(l => {
+    servicesParsed[l.type].push(`<a href="#" hx-get="/city/${l.type.toLowerCase()}/${l.event_name}/${l.id}" hx-target="#explore">${l.name}</a>`);
+  });
+
+  let html = `
+<section id="explore" class="tab active" style="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/${closestTown}.jpeg')" hx-swap-oob="true">
+<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="#" hx-post="/travel/${path.ending_city}" hx-target="#explore">${path.ending_city_name}</a>`
+      }).join("<br>")}
+    </div>
+  </div>
+</div>
+  `;
+
+  return html;
+};
diff --git a/src/server/views/monster-selector.ts b/src/server/views/monster-selector.ts
new file mode 100644 (file)
index 0000000..8acb82f
--- /dev/null
@@ -0,0 +1,13 @@
+import { Monster, MonsterForFight } from "../../shared/monsters";
+
+export function renderMonsterSelector(monsters: Monster[] | MonsterForFight[], activeMonsterId: number = 0): string {
+  let html = `<form id="fight-selector" hx-post="/fight" hx-target="#explore">
+  <input type="hidden" name="fightTrigger" value="explore">
+  <select id="monsterId" name="monsterId">
+  ${monsters.map((monster) => {
+      return `<option value="${monster.id}" ${monster.id === activeMonsterId ? 'selected': ''}>${monster.name}</option>`;
+  }).join("\n")}
+  </select> <button type="submit">Fight</button></form>`;
+
+  return html;
+}
diff --git a/src/server/views/player-bar.ts b/src/server/views/player-bar.ts
new file mode 100644 (file)
index 0000000..effbbdc
--- /dev/null
@@ -0,0 +1,68 @@
+import { EquippedItemDetails } from "shared/equipped";
+import { EquipmentSlot } from "shared/inventory";
+import { expToLevel, maxHp, Player } from "../../shared/player";
+
+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 calcAp(inventoryItem: EquippedItemDetails[]): string {
+  const ap: Record<any | EquipmentSlot, {currentAp: number, maxAp: number}> = {};
+  inventoryItem.forEach(item => {
+    if(item.is_equipped && item.type === 'ARMOUR') {
+      ap[item.equipment_slot] = {
+        currentAp: item.currentAp,
+        maxAp: item.maxAp
+      };
+    }
+  });
+
+  return `
+  <div>
+    <img src="/assets/img/helm.png" class="icon">
+    ${generateProgressBar(ap.HEAD?.currentAp || 0, ap.HEAD?.maxAp || 0, '#7be67b')}
+  </div>
+  <div>
+    <img src="/assets/img/arms.png" class="icon">
+    ${generateProgressBar(ap.ARMS?.currentAp || 0, ap.ARMS?.maxAp || 0, '#7be67b')}
+  </div>
+  <div>
+    <img src="/assets/img/chest.png" class="icon">
+    ${generateProgressBar(ap.CHEST?.currentAp || 0, ap.CHEST?.maxAp || 0, '#7be67b')}
+  </div>
+  <div>
+    <img src="/assets/img/legs.png" class="icon">
+    ${generateProgressBar(ap.LEGS?.currentAp || 0, ap.LEGS?.maxAp || 0, '#7be67b')}
+  </div>
+`;
+}
+
+function progressBar(current: number, max: number, id: string, color: string) {
+  let percent = 0;
+  if(max > 0) {
+    percent = Math.floor((current / max) * 100);
+  }
+
+  return `<div class="progress-bar" id="${id}" style="background: linear-gradient(to right, ${color}, ${color} ${percent}%, transparent ${percent}%, transparent)"
+title="${percent}% - ${current}/${max}">${current}/${max} - ${percent}</div>`;
+}
+
+export function renderPlayerBar(player: Player, inventory: EquippedItemDetails[]): string {
+  return `
+    <div id="stat-bars" hx-swap-oob="true">
+      <div id="player-section">
+        <div id="username">${player.username}, level ${player.level} ${player.profession}</div>
+        <div class="gold">${player.gold.toLocaleString()}</div>
+      </div>
+      <div id="ap-bar">${calcAp(inventory)}</div>
+      ${progressBar(player.hp, maxHp(player.constitution, player.level), 'hp-bar', '#ff7070')}
+      ${progressBar(player.exp, expToLevel(player.level + 1), 'exp-bar', '#5997f9')}
+    </div>
+  `;
+
+}
diff --git a/src/server/views/profile.ts b/src/server/views/profile.ts
new file mode 100644 (file)
index 0000000..0d8468b
--- /dev/null
@@ -0,0 +1,27 @@
+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>`;
+}
+export async function renderProfilePage(player: Player): Promise<string> {
+  let statBreakdown = '';
+
+  StatDef.forEach(stat => {
+    statBreakdown += `<tr>
+      <th>${stat.display}</th>
+      <td class="${stat.id}">
+        ${player[stat.id]}
+        ${player.stat_points ? statPointIncreaser(stat) : ''}
+      </td>
+    </tr>`;
+  });
+
+  const html = `<div id="extra-inventory-info">
+  <table id="stat-breakdown">
+    ${statBreakdown}
+    <tr><th>Stat Points</th><td class="stat_points">${player.stat_points}</td></tr>
+  </table>
+  </div>`;
+
+  return html;
+}
diff --git a/src/server/views/skills.ts b/src/server/views/skills.ts
new file mode 100644 (file)
index 0000000..0c11815
--- /dev/null
@@ -0,0 +1,22 @@
+import { Skill, Skills } from "../../shared/skills";
+
+export function renderSkills(skills: Skill[]): string {
+  let html = `<table id="skill-list">
+  ${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>`;
+
+  return html;
+}
diff --git a/src/server/views/stores.ts b/src/server/views/stores.ts
new file mode 100644 (file)
index 0000000..6c237d1
--- /dev/null
@@ -0,0 +1,127 @@
+import { ShopEquipment } from "../../shared/inventory";
+import { ShopItem, Item } from "../../shared/items";
+import { capitalize } from "lodash";
+import { Player } from "../../shared/player";
+
+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 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 renderShopItem(item: (ShopItem & Item), action: (item: (ShopItem & Item)) => string): string {
+    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>`;
+}
+
+export function renderEquipmentDetails(item: ShopEquipment, player: Player): string {
+  return `
+    <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>
+`
+
+}
+
+function renderShopEquipment(item: ShopEquipment, action: (item: ShopEquipment) => string, player: Player): string {
+    return `<div class="store-list">
+    <div>
+      <img src="https://via.placeholder.com/64x64">
+    </div>
+    ${renderEquipmentDetails(item, player)}
+    <div class="store-actions">
+      ${action(item)}
+    </div>
+    </div>`;
+}
+
+
+
+export async function renderStore(equipment: ShopEquipment[], items: (ShopItem & Item)[], player: Player): Promise<string> {
+  const listing: Record<string, string> = {};
+  const listingTypes = new Set<string>();
+
+  equipment.forEach(item => {
+    const filter = item.type === 'ARMOUR' ? item.equipment_slot : item.type;
+
+    listingTypes.add(filter);
+    if(!listing[filter]) {
+      listing[filter] = '';
+    }
+
+    listing[filter] += renderShopEquipment(item, i => {
+      const id = `data-id="${i.id}"`;
+      return `<button type="button" hx-get="/location/${i.location_id}/equipment/${i.id}/overview" hx-target="#modal-wrapper">Buy</button>`
+    }, player);
+
+  });
+
+  if(items && items.length) {
+    listingTypes.add('ITEMS');
+    listing['ITEMS'] = '';
+    items.forEach(item => {
+      listing['ITEMS'] += renderShopItem(item, i => {
+        return `<button type="button" hx-get="/location/${i.location_id}/items/${i.id}/overview" hx-target="#modal-wrapper">Buy</button>`;
+      });
+    });
+  }
+
+  let activeTab: string = listingTypes.keys().next().value;
+
+  const nav: string[] = [];
+  const finalListing: string[] = [];
+
+  listingTypes.forEach(type => {
+    nav.push(`<a href="#" data-filter="${type}" class="${activeTab === type ? 'active': ''}">${capitalize(type)}</a>`);
+    finalListing.push(`<div class="filter-result ${activeTab === type ? 'active': 'hidden'}" data-filter="${type}" 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>`;
+
+  return html;
+}
diff --git a/src/server/views/travel.ts b/src/server/views/travel.ts
new file mode 100644 (file)
index 0000000..fc70860
--- /dev/null
@@ -0,0 +1,39 @@
+import { TravelDTO } from "../../shared/map";
+
+export function travelButton(blockTime: number): string {
+  return `<button id="keep-walking" hx-post="/travel/step" class="${blockTime ? 'disabled': ''}" data-block="${blockTime}" ${blockTime ? 'disabled': ''}>Keep Walking</button>`;
+}
+
+export function renderTravel(data: TravelDTO): string {
+
+  let promptText = data.walkingText;
+  const blockTime = data.nextAction || 0;
+
+  /*
+  if(blockTime) {
+    updateStepButton();
+  }
+  */
+
+  let html = `<section id="explore" class="tab active" hx-swap-oob="true" style="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/${data.closestTown}.jpeg')">
+<div id="travelling">`;
+  html += '<div id="travelling-actions">';
+  html += travelButton(blockTime);
+  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 += `<form hx-post="/fight" hx-target="#explore">
+<input type="hidden" name="monsterId" value="${data.things[0].id}">
+<button type="submit">Fight</button>
+</form>`;
+  }
+
+  // end #travelling-actions
+  html += '</div>';
+  html += `<p>${promptText}</p>`;
+
+  html += '</div></section>';
+
+  return html;
+}
index c3b58b6faba4fc9c783d74804ba03c9d82a4a774..6c18807635b2bc26100d18b548d5358caa7bf2f9 100644 (file)
@@ -40,7 +40,7 @@ export type InventoryItem = {
 
 // shop items have a numeric id since they're tracked in a separate spreadsheet 
 // and they are also tied to a specific location
 
 // shop items have a numeric id since they're tracked in a separate spreadsheet 
 // and they are also tied to a specific location
-export type ShopItem = Omit<InventoryItem, 'id' | 'player_id'> & {
+export type ShopEquipment = Omit<InventoryItem, 'id' | 'player_id'> & {
   id: number;
   location_id: number;
 };
   id: number;
   location_id: number;
 };
diff --git a/src/shared/items/base.ts b/src/shared/items/base.ts
new file mode 100644 (file)
index 0000000..948362b
--- /dev/null
@@ -0,0 +1,6 @@
+import { Player } from "../player"
+
+export type ItemEffect<T> = {
+  name: string,
+  effect: (player: Player) => T
+};
diff --git a/src/shared/items/health_potion.ts b/src/shared/items/health_potion.ts
new file mode 100644 (file)
index 0000000..248e232
--- /dev/null
@@ -0,0 +1,12 @@
+import { ItemEffect } from "./base";
+import { maxHp, Player } from "../player";
+
+export const HealthPotionSmall: ItemEffect<number> = {
+  name: 'heal_small',
+  effect: (player: Player): number => {
+    const gain = 30;
+    const newHp = player.hp + gain;
+
+    return Math.ceil(newHp);
+  }
+}
diff --git a/src/shared/items/index.ts b/src/shared/items/index.ts
new file mode 100644 (file)
index 0000000..eeb0aef
--- /dev/null
@@ -0,0 +1,33 @@
+import { ItemEffect } from "./base";
+import {HealthPotionSmall} from './health_potion';
+
+export type Item = {
+  id: number;
+  name: string;
+  description: string;
+  effect_name: string;
+  icon_name: string;
+}
+
+// this is the result of a join, the actual 
+// table only maps player_id/item_id + amount
+export type PlayerItem = {
+  item_id: number;
+  player_id: string;
+  amount: number;
+  name: string;
+  effect_name: string;
+  icon_name: string;
+  description: string;
+}
+
+export type ShopItem = {
+  item_id: number;
+  location_id: number;
+  amount: number;
+  price_per_unit: number;
+}
+
+export const ItemEffects: Map<string, ItemEffect<number>> = new Map<string, ItemEffect<any>>();
+
+ItemEffects.set(HealthPotionSmall.name, HealthPotionSmall);
index 015771f86a0dc2a6c08130bc7a7a7080bc6d07ac..5fe8b405548f5ef3417539dfec449782afd39a1a 100644 (file)
@@ -21,3 +21,12 @@ export type Path = {
   ending_city_name: string;
   distance: number;
 }
   ending_city_name: string;
   distance: number;
 }
+
+export type TravelDTO = {
+  things: any[],
+  nextAction: number,
+  walkingText: string,
+  closestTown: number;
+}
+
+export const STEP_DELAY = 3000;
index 8e40f12d697d89f151211711eb5668169f34014c..0fb104f53bae6c4cc83fd7143a1354103a711c0e 100644 (file)
@@ -75,7 +75,7 @@ export class TimeManager {
     const min = this.get24Hour();
     return (
       min >= 0 && min < 5 ||
     const min = this.get24Hour();
     return (
       min >= 0 && min < 5 ||
-        min >= 22 && min < 24
+        min >= 21 && min < 24
     );
   }
 
     );
   }
 
index df9ddbdeb41301a88d3d8569e158a50b43ffe166..d55a9dc98004d156920bdf545f81eeace63b6d6a 100644 (file)
@@ -8,7 +8,7 @@ module.exports = {
   mode: env,
   devtool: env === 'development' ? "inline-source-map" : false,
   entry: {
   mode: env,
   devtool: env === 'development' ? "inline-source-map" : false,
   entry: {
-    main: "./src/client/index.ts",
+    main: "./src/client/htmx.ts",
   },
   module: {
     rules: [
   },
   module: {
     rules: [