From: xangelo Date: Sat, 5 Aug 2023 12:59:04 +0000 (-0400) Subject: chore(release): 0.2.5 X-Git-Tag: v0.2.5 X-Git-Url: https://git.xangelo.ca/?p=risinglegends.git;a=commitdiff_plain;h=v0.2.5;hp=v0.2.4;ds=sidebyside chore(release): 0.2.5 --- diff --git a/CHANGELOG.md b/CHANGELOG.md index 062f564..2be61f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. +### [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) diff --git a/migrations/20230729184427_items.ts b/migrations/20230729184427_items.ts new file mode 100644 index 0000000..4f7d09a --- /dev/null +++ b/migrations/20230729184427_items.ts @@ -0,0 +1,24 @@ +import { Knex } from "knex"; + + +export async function up(knex: Knex): Promise { + 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 { + 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 index 0000000..c0077dc --- /dev/null +++ b/migrations/20230802173517_shop_equipment.ts @@ -0,0 +1,15 @@ +import { Knex } from "knex"; + + +export async function up(knex: Knex): Promise { + 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 { + 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 index 0000000..2579162 --- /dev/null +++ b/migrations/20230802174902_items-in-shop.ts @@ -0,0 +1,18 @@ +import { Knex } from "knex"; + + +export async function up(knex: Knex): Promise { + 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 { + return knex.schema.dropTable('shop_items'); +} + diff --git a/package-lock.json b/package-lock.json index b468207..3d3fe47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rising-legends", - "version": "0.2.4", + "version": "0.2.5", "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", diff --git a/package.json b/package.json index 7b5f04e..7e36845 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "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", diff --git a/public/assets/bundle.js b/public/assets/bundle.js index 14865b9..239b458 100644 --- a/public/assets/bundle.js +++ b/public/assets/bundle.js @@ -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{e[n]=t[n]})),e.names=[],e.skips=[],e.formatters={},e.selectColor=function(t){let n=0;for(let e=0;e{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-1}function Fe(t,e,n){for(var r=-1,i=null==t?0:t.length;++r-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({"&":"&","<":"<",">":">",'"':""","'":"'"});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",""":'"',"'":"'"}),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=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-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;++r0&&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&&ne}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=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-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&&++oo?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>>1,s=t[o];null!==s&&!aa(s)&&(n?s<=e:s=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=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&&t1?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-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;++r1&&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?eu))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-1&&t%1==0&&t1?"& ":"")+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;++n1?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=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);++n1),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));so?0:o+n),(r=r===i||r>o?o:ha(r))<0&&(r+=o),r=n>r?0:pa(r);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=-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&&re){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);++rf)return[];var n=h,r=yn(t,h);e=oo(e),t-=h;for(var i=Ke(r,e);++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=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{e[n]=t[n]})),e.names=[],e.skips=[],e.formatters={},e.selectColor=function(t){let n=0;for(let e=0;e{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{e[n]=t[n]})),e.names=[],e.skips=[],e.formatters={},e.selectColor=function(t){let n=0;for(let e=0;e{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=>`
\n ${t.from}\n ${t.msg}\n
`)).join("\n")),(0,i.default)("#chat-messages").scrollTop((0,i.default)("#chat-messages")[0].scrollHeight)}function a(t){(0,i.default)("#chat-messages").append(`
\n ${t.from}\n ${t.msg}\n
`),(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(` ${_.getHour()}${_.getAmPm()}`)}function E(t){return``}function S(t,e,n,r=!0){let i=0;e>0&&(i=Math.floor(t/e*100));const o=r?`${i}% - `:"";return`
${o}${t}/${e}
`}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('

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.

\n

\n
\n \n \n
\n
\n \n \n
\n \n \n

').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(`
${t}
`),setTimeout((()=>{(0,c.default)(`#alert-${n}`).remove()}),3e3)}function T(){const t=b.get("player");let e='';return l.StatDef.forEach((n=>{e+=`\n \n \n `})),e+=``,e+="
${n.display}\n ${t[n.id]}\n ${t.stat_points?function(t){return``}(n):""}\n
Stat Points${t.stat_points}
",e}function F(t){return t.map((t=>function(t,e){return`
\n
\n \n
\n
\n
${t.name}
\n
\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
\n
\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
\n ${t.hasOwnProperty("id")?`
${t.cost.toLocaleString()}G
`:""}\n
\n
\n ${(t=>t.is_equipped?``:"ANY_HAND"===t.equipment_slot?`\n `:"LEFT_HAND"===t.equipment_slot?``:"RIGHT_HAND"===t.equipment_slot?``:(t.equipment_slot,``))(t)}\n
\n
`}(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"),`${t}: ${e.toLocaleString()}`}function P(t,e){let n="";return"number"==typeof e&&(n=e>0?"+":"-"),`${t}: 0?"success":"error":""}">${n}${e}`}function R(t,e){const n=b.get("player");return`
\n
\n \n
\n
\n
${t.name}${"TWO_HANDED"===t.equipment_slot?" (2H)":""}
\n
\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
\n
\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
\n ${t.hasOwnProperty("id")?`
${t.cost.toLocaleString()}G
`:""}\n
\n
\n ${e(t)}\n
\n
`}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`
\n
\n
\n \n
\n
\n
${t.name}
\n
${e}% - ${t.hp} / ${t.maxHp}
\n
\n
\n
\n \n \n \n \n
\n
\n
`}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
\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
\n
\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
\n
\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
\n
\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
\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=`\n ${t.skills.map((t=>{const e=g.Skills.get(t.id),n=t.exp/e.expToLevel(t.level+1);return`\n \n \n \n \n `})).join("\n")}\n
${t.level.toLocaleString()}\n ${(100*n).toPrecision(2)}% to next level\n ${e.display}\n

${e.description}

\n
`;(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
\n
\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 \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n ${n.HEAD?n.HEAD.name:"HEAD"}\n \n ${n.ARMS?n.ARMS.name:"ARMS"}\n
\n ${n.LEFT_HAND?n.LEFT_HAND.name:n.TWO_HANDED?n.TWO_HANDED.name:"L_HAND"}\n \n ${n.CHEST?n.CHEST.name:"CHEST"}\n \n ${n.RIGHT_HAND?n.RIGHT_HAND.name:n.TWO_HANDED?n.TWO_HANDED.name:"R_HAND"}\n
\n \n ${n.LEGS?n.LEGS.name:"LEGS"}\n \n
\n `}(t.inventory)}\n
\n ${T()}\n
\n
\n
\n \n
\n
\n ${F(n.ARMOUR)}\n
\n
\n ${F(n.WEAPON)}\n
\n
\n ${F(n.SPELL)}\n
\n
\n
\n
\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(`${t.name}`)}));let n=`

${t.city.name}

\n
`;e.SERVICES.length&&(n+=`

Services

${e.SERVICES.join("
")}
`),e.STORES.length&&(n+=`

Stores

${e.STORES.join("
")}
`),e.EXPLORE.length&&(n+=`

Explore

${e.EXPLORE.join("
")}
`),n+=`\n
\n

Travel

\n ${t.paths.map((t=>`${t.ending_city_name}`)).join("
")}\n
\n
\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=>``))):(n.add(t.type),e[t.type]||(e[t.type]=""),e[t.type]+=R(t,(t=>``)))}));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(`${(0,p.capitalize)(t)}`),s.push(`
${e[t]}
`)}));let a=`
\n
\n ${s.join("\n")}\n
\n
`;(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{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=`
`;(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='
';r+='
',r+=``,t.things.length&&(e=`You see a ${t.things[0].name}`,r+=``),r+="
",r+=`

${e}

`,r+="
",(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=>`
${t}
`));if("player"===e.winner&&(r.push(`
You defeated the ${e.monster.name}!
`),e.rewards.gold&&r.push(`
You gained ${e.rewards.gold} gold`),e.rewards.exp&&r.push(`
You gained ${e.rewards.exp} exp`),e.rewards.levelIncrease&&r.push(`
You gained a level! ${e.player.level}`)),0===e.player.hp)r.push("

You were killed...

"),r.push('

');else switch(e.fightTrigger){case"explore":if(n.length){const t=b.get("last-selected-monster");r.unshift(`

Fight Again

\n
`)}break;case"travel":r.push('

');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=>`
${t}
`)).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>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<>5]|=(255&t[n/8])<{"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<>>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>>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{"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{"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{"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{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;e0&&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{"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{const e={};!u.usingBrowserWebSocket&&(n.options&&(e.compress=n.options.compress),this.opts.perMessageDeflate)&&("string"==typeof t?Buffer.byteLength(t):t.length){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=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>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>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{"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;nt())),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.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{"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=0&&t.num{"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{"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{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{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t{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{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t{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{t[s]=e[s]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let s=0;for(let t=0;t{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+=`
\n ${e.from}\n ${e.msg}\n
`,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{"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{"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{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;t0&&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{"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{const t={};!c.usingBrowserWebSocket&&(s.options&&(t.compress=s.options.compress),this.opts.perMessageDeflate)&&("string"==typeof e?Buffer.byteLength(e):e.length){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=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>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>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{"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;se())),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.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{"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=0&&e.num{"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{"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{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=` ${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 diff --git a/public/assets/css/game.css b/public/assets/css/game.css index cc8264e..edb597d 100644 --- a/public/assets/css/game.css +++ b/public/assets/css/game.css @@ -25,6 +25,10 @@ body { padding: 1rem; border: 1px solid #000; } +:disabled { + background-color: #aaa; + cursor: not-allowed; +} b { font-weight: bold; } @@ -45,7 +49,7 @@ button { color: #000; } .hidden { - display: none; + display: none !important; } p { margin-bottom: 1rem; @@ -71,6 +75,34 @@ section { 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; @@ -219,6 +251,54 @@ nav.filter-result.active { #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; @@ -248,6 +328,8 @@ nav.filter-result.active { background-repeat: no-repeat; background-position: bottom right; background-size: cover; + padding: 3rem 3rem 2rem; + line-height: 1.3rem; } #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 index 0000000..2e09caa Binary files /dev/null and b/public/assets/img/icons/items/Minor_Potion_health.png differ diff --git a/public/index.html b/public/index.html index a8eac15..83f18c6 100644 --- a/public/index.html +++ b/public/index.html @@ -10,6 +10,7 @@ + @@ -31,9 +32,10 @@
@@ -42,8 +44,10 @@
+
-
-
- +
+ +
@@ -71,7 +75,7 @@ Settings
-
0 Online - Now
+
...Loading
diff --git a/seeds/shop_items.ts b/seeds/shop_items.ts index 6aedb57..18a754c 100644 --- a/seeds/shop_items.ts +++ b/seeds/shop_items.ts @@ -10,10 +10,10 @@ Airtable.configure({ const base = Airtable.base('appDfPLPajPNog5Iw'); -export async function createShopItems(): Promise { +export async function createShopEquipment(): Promise { 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, @@ -48,8 +48,40 @@ export async function createShopItems(): Promise { }); } +export async function createShopItems(): Promise { + 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) { - createShopItems().then(() => { + createShopEquipment().then(createShopItems).then(() => { console.log('Complete'); process.exit(0); }).catch(e => { diff --git a/src/client/chat.ts b/src/client/chat.ts index 549fbcc..287207e 100644 --- a/src/client/chat.ts +++ b/src/client/chat.ts @@ -1,53 +1,32 @@ -import $ from 'jquery'; import {Socket} from 'socket.io-client'; import {Message} from '../shared/message'; -import { configureDiscordChat } from './discord'; // disable chat temporarily to test widgetbot let socket: Socket; +function $(selector: string, root: any = document): T { + return root.querySelector(selector) as T; +} -function renderChatHistory(messages: Message[]) { - $('#chat-messages').html(messages.map(msg => { - return `
- ${msg.from} - ${msg.msg} -
`; - - }).join("\n")); - $('#chat-messages').scrollTop($('#chat-messages')[0].scrollHeight); +function $$(selector: string, root: any = document): T[] { + return Array.from(root.querySelectorAll(selector)) as T[]; } function renderChatMessage(msg: Message) { - $('#chat-messages').append(`
+ $('#chat-messages').innerHTML += `
${msg.from} ${msg.msg} -
`); - $('#chat-messages').scrollTop($('#chat-messages')[0].scrollHeight); +
`; + $('#chat-messages').scrollTop = $('#chat-messages').scrollHeight; } function configureStandardChat() { - socket.on('chathistory', renderChatHistory); 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; - //configureDiscordChat(socket); configureStandardChat(); console.log('Chat Configured'); diff --git a/src/client/htmx.ts b/src/client/htmx.ts new file mode 100644 index 0000000..a4107d8 --- /dev/null +++ b/src/client/htmx.ts @@ -0,0 +1,178 @@ +import { io } from 'socket.io-client'; +import { authToken } from './http'; +import { TimeManager } from '../shared/time'; +import { configureChat } from './chat'; + +function $(selector: string, root: any = document): T { + return root.querySelector(selector) as T; +} + +function $$(selector: string, root: any = document): T[] { + return Array.from(root.querySelectorAll(selector)) as T[]; +} +function setTimeGradient() { + const gradientName = time.gradientName(); + const $body = $('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'; + } + + $('#time-of-day').innerHTML = ` ${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); + + +$$('nav a').forEach(el => { + el.addEventListener('click', e => { + const el = e.target as HTMLElement; + + $$('a', el.closest('nav')).forEach(el => { + el.classList.remove('active'); + }) + + el.classList.add('active'); + + const targetEl = $(el.getAttribute('hx-target')!.toString()); + + Array.from(targetEl.parentElement!.children).forEach(el => { + el.classList.remove('active'); + }); + targetEl.classList.add('active'); + }); +}); + +$('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 = $(`.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($('#modal-wrapper').children.length) { + $$('#modal-wrapper dialog').forEach(el => { + if(!el.open) { + el.showModal(); + } + }) + } + } + + if(states.alert) { + if($('#alerts').children.length) { + $$('#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($('#modal-wrapper'), { childList: true }); + +modalMutations.observe($('#alerts'), { childList: true }); + + +function bootstrap() { + console.log('Server connection verified'); + configureChat(socket); + $$('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) { + $$('.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') { + $('#message').value = ''; + } +}); + diff --git a/src/client/http.ts b/src/client/http.ts index 3298b57..312cea1 100644 --- a/src/client/http.ts +++ b/src/client/http.ts @@ -1,4 +1,4 @@ -export function authToken() { +export function authToken(): string { 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; + } } } diff --git a/src/client/index.ts b/src/client/index.ts index 72e9d80..b460ead 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -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 {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'; @@ -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 { Item, PlayerItem, ShopItem } from '../shared/items'; +import { Modal } from './modal'; const time = new TimeManager(); @@ -362,6 +364,39 @@ $('body').on('click', 'nav.filter', e => { 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 ` +
+ + ${item.amount.toLocaleString()} +
`; + }).join("
"); + +} + function renderInventorySection(inventory: EquippedItemDetails[]): string { return inventory.map(item => { return renderInventoryItem(item, item => { @@ -390,44 +425,50 @@ function renderInventorySection(inventory: EquippedItemDetails[]): string { }).join("\n"); } -socket.on('inventory', (data: {inventory: EquippedItemDetails[]}) => { +events.on('tab:profile', () => { + const html = `
+ ${renderStatDetails()} +
`; + + $('#profile').html(html); +}); + +socket.on('inventory', (data: {inventory: EquippedItemDetails[], items: PlayerItem[]}) => { const player: Player = cache.get('player'); const activeSection = cache.get('active-inventory-section') || 'ARMOUR'; // split the inventory into sections! - const sectionedInventory: {ARMOUR: EquippedItemDetails[], WEAPON: EquippedItemDetails[], SPELL: EquippedItemDetails[]} = { + const sectionedInventory: {ARMOUR: EquippedItemDetails[], WEAPON: EquippedItemDetails[], SPELL: EquippedItemDetails[], ITEMS: PlayerItem[]} = { ARMOUR: [], WEAPON: [], - SPELL: [] + SPELL: [], + ITEMS: [] }; data.inventory.forEach(item => { sectionedInventory[item.type].push(item); }); + data.items.forEach(item => { + sectionedInventory.ITEMS.push(item); + }); const html = `
${renderEquipmentPlacementGrid(data.inventory)} -
- ${renderStatDetails()} -
-
- ${renderInventorySection(sectionedInventory.ARMOUR)} -
-
- ${renderInventorySection(sectionedInventory.WEAPON)} -
-
- ${renderInventorySection(sectionedInventory.SPELL)} -
+ ${Object.keys(sectionedInventory).map(type => { + return `
+ ${type === 'ITEMS' ? renderInventoryItems(sectionedInventory[type]) : renderInventorySection(sectionedInventory[type])} +
`; + + }).join("")}
@@ -556,7 +597,7 @@ function renderInventoryItem(item: EquippedItemDetails , action: (item: Equipped `; } -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 `
@@ -587,13 +628,32 @@ function renderShopItem(item: ShopItem, action: (item: ShopItem) => string): str ${action(item)}
`; +} +function renderShopItem(item: (ShopItem & Item), action: (item: (ShopItem & Item)) => string): string { + const player: Player = cache.get('player'); + return `
+
+ +
+
+
${item.name}
+
+ ${item.description} +
+ ${item.hasOwnProperty('id') ? `
${item.price_per_unit.toLocaleString()}G
` : ''} +
+
+ ${action(item)} +
+
`; } -socket.on('city:stores', (data: ShopItem[]) => { +socket.on('city:stores', (data: {equipment: ShopEquipment[], items: (ShopItem & Item)[]}) => { const listing: Record = {}; const listingTypes = new Set(); - data.forEach(item => { + const { equipment, items } = data; + equipment.forEach(item => { 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] += renderShopItem(item, i => { + listing[item.equipment_slot] += renderShopEquipment(item, i => { const id = `data-id="${i.id}"`; return `` }); } - else { + else if(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 `` }); } + else { + console.log('no type', item); + } }); + if(items && items.length) { + listingTypes.add('ITEMS'); + listing['ITEMS'] = ''; + items.forEach(item => { + listing['ITEMS'] += renderShopItem(item, i => { + return ``; + }); + }); + } + 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); - 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'); @@ -1026,6 +1107,11 @@ $('body').on('click', '#logout', async e => { function bootstrap() { console.log('Server connection verified'); - socket.emit('inventory'); + //socket.emit('inventory'); $('nav a').first().click(); + } +document.body.addEventListener('htmx:configRequest', function(evt) { + //@ts-ignore + evt.detail.headers['x-authtoken'] = authToken(); +}); diff --git a/src/client/modal.ts b/src/client/modal.ts new file mode 100644 index 0000000..1eabdac --- /dev/null +++ b/src/client/modal.ts @@ -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 = ` + + + + + `; + + if(this.$el().length) { + this.showModal(); + } + else { + $('body').append(html); + this.emit('ready', [this]); + } + } + + $el() { + return $(`#${this.id}`); + } + + showModal() { + // @ts-ignore + this.$el().get(0)?.showModal(); + } +} diff --git a/src/events/client.ts b/src/events/client.ts index 49ca3d0..4d0754f 100644 --- a/src/events/client.ts +++ b/src/events/client.ts @@ -1,3 +1,2 @@ export * from './profession-changing/client'; export * from './travel/client'; -export * from './healer/client'; diff --git a/src/events/equipping-items/server.ts b/src/events/equipping-items/server.ts index 802f66b..7b00316 100644 --- a/src/events/equipping-items/server.ts +++ b/src/events/equipping-items/server.ts @@ -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 { getPlayersItems } from "../../server/items"; class EquipmentInSlotError extends Error { code: number; @@ -81,10 +82,12 @@ export const equipItem: SocketEvent = { } const inventory = await getInventory(api.player.id); - calcAp(inventory, api.socket); + const items = await getPlayersItems(api.player.id); 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 items = await getPlayersItems(api.player.id); 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 index 56a0da1..0000000 --- a/src/events/healer/client.ts +++ /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 index df8fb8a..0000000 --- a/src/events/healer/server.ts +++ /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; - -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 = { - [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(`

${service.name}

`); - text.push(`

"${getText('intro', service, city)}"

`); - - - if(api.player.hp === maxHp(api.player.constitution, api.player.level)) { - text.push(`

You're already at full health?

`); - } - else { - if(api.player.gold <= (healCost * 2)) { - text.push(`

You don't seem to have too much money... I guess I can do it for free this time...

`); - text.push(`

`); - } - else { - text.push(`

`); - } - - } - - 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(`

${service.name}

`); - - const cost = api.player.gold <= (healCost * 2) ? 0 : healCost; - - if(api.player.gold < cost) { - text.push(`

${getText('insufficient_money', service, city)}

`) - 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(`

${getText('heal_successful', service, city)}

`); - text.push('

'); - 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 index 0000000..0c9023d --- /dev/null +++ b/src/events/items/server.ts @@ -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 => { + 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; + } +} diff --git a/src/events/server.ts b/src/events/server.ts index 6ac3690..6f9811a 100644 --- a/src/events/server.ts +++ b/src/events/server.ts @@ -3,5 +3,5 @@ export * from './equipping-items/server'; export * from './travel/server'; export * from './explore/server'; export * from './stores/server'; -export * from './healer/server'; export * from './stat-points/server'; +export * from './items/server'; diff --git a/src/events/stores/server.ts b/src/events/stores/server.ts index 076cab4..1acbd8c 100644 --- a/src/events/stores/server.ts +++ b/src/events/stores/server.ts @@ -1,5 +1,6 @@ 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 = { @@ -11,15 +12,19 @@ export const stores: SocketEvent = { 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 { - logger.log(`Insufficient shop items: ${shopItems.length}`); + logger.log(`Insufficient shop items: ${shopEquipemnt.length}`); } } } diff --git a/src/server/api.ts b/src/server/api.ts index aed47d4..bd86f97 100644 --- a/src/server/api.ts +++ b/src/server/api.ts @@ -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 bodyParser from 'body-parser'; + 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 {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 {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 { 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 * 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'; +import { Item, PlayerItem, ShopItem } from 'shared/items'; +import { equip, unequip } from './equipment'; +import { HealthPotionSmall } from '../shared/items/health_potion'; dotenv(); @@ -37,6 +56,7 @@ const app = express(); 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); @@ -44,27 +64,10 @@ const io = new Server(server); const cache = new Map(); const chatHistory: Message[] = []; -function calcAp(inventoryItem: EquippedItemDetails[], socket: Socket) { - const ap: Record = {}; - 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']}`); @@ -90,479 +93,820 @@ io.on('connection', async socket => { // 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 = new Map(); + 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 = {}; + 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 { - 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 = new Map(); - 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 = {}; - 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 { - 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 { - 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 = ` + +
+
+ ${equipment.name} +
+
+ ${renderEquipmentDetails(equipment, player)} +
+
+
+ + +
+
+`; + + 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 = ` + +
+
+ ${item.name} +
+
+

${item.name}

+

${item.description}

+
+
+
+ + +
+
+`; + + res.send(html); +}); + +app.put('/item/:item_id', authEndpoint, async (req: Request, res: Response) => { + const authToken = req.headers['x-authtoken'].toString(); + const player: Player = await loadPlayer(authToken) + if(!player) { + logger.log(`Couldnt find player with id ${authToken}`); return res.sendStatus(400); } - const [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) - 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 = ` + +
+
+ ${item.name} +
+
+

${item.name}

+

${item.description}

+
+
+
+ + +
+
+`; + + 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); } - 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) => { @@ -585,6 +929,50 @@ app.post('/travel', authEndpoint, async (req: Request, res: Response) => { 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(); @@ -601,8 +989,7 @@ app.post('/fight', authEndpoint, async (req: Request, res: Response) => { } 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}`); @@ -623,6 +1010,7 @@ app.post('/fight', authEndpoint, async (req: Request, res: Response) => { const fight = await createFight(player.id, monster, fightTrigger); + 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 }; - 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']; @@ -691,6 +1186,14 @@ app.post('/login', async (req: Request, res: Response) => { } }); +app.get('/status', async (req: Request, res: Response) => { + res.send(` +
+ ${io.sockets.sockets.size} Online (v${version}) +
+`); +}) + server.listen(process.env.API_PORT, () => { logger.log(`Listening on port ${process.env.API_PORT}`); }); diff --git a/src/server/auth.ts b/src/server/auth.ts index 748c79d..d82d4b6 100644 --- a/src/server/auth.ts +++ b/src/server/auth.ts @@ -3,6 +3,7 @@ import bcrypt from 'bcrypt'; 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 { const salt = await bcrypt.genSalt(10); @@ -56,3 +57,14 @@ export async function login(username: string, password: string): Promise } } + +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() + } +} diff --git a/src/server/inventory.ts b/src/server/inventory.ts index 9a62bdf..c5c2b67 100644 --- a/src/server/inventory.ts +++ b/src/server/inventory.ts @@ -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"; -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(), diff --git a/src/server/items.ts b/src/server/items.ts new file mode 100644 index 0000000..1811923 --- /dev/null +++ b/src/server/items.ts @@ -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 { + 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 { + 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 { + 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 { + 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 index 0000000..bd3ba1c --- /dev/null +++ b/src/server/locations/healer/index.ts @@ -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; + +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 = { + [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(`

${service.name}

`); + text.push(`

"${getText('intro', service, city)}"

`); + + + if(player.hp === maxHp(player.constitution, player.level)) { + text.push(`

You're already at full health?

`); + } + else { + if(player.gold <= (healCost * 2)) { + text.push(`

You don't seem to have too much money... I guess I can do it for free this time...

`); + text.push(`

`); + } + else { + text.push(`

`); + } + + } + + res.send(`
${text.join("\n")}
`); +}); + + + +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(`

${service.name}

`); + + const cost = player.gold <= (healCost * 2) ? 0 : healCost; + + if(player.gold < cost) { + text.push(`

${getText('insufficient_money', service, city)}

`) + res.send(`
${text.join("\n")}
`); + } + else { + player.hp = maxHp(player.constitution, player.level); + player.gold -= cost; + + await updatePlayer(player); + const inventory = await getEquippedItems(player.id); + + text.push(`

${getText('heal_successful', service, city)}

`); + text.push('

'); + res.send(`
${text.join("\n")}
` + renderPlayerBar(player, inventory)); + } +}); diff --git a/src/server/map.ts b/src/server/map.ts index 67cd225..54f0de8 100644 --- a/src/server/map.ts +++ b/src/server/map.ts @@ -12,9 +12,9 @@ export async function getAllServices(city_id: number): Promise { .orderBy('display_order'); } -export async function getService(serverId: number): Promise { +export async function getService(location_id: number): Promise { return db.select('*').first().from('locations').where({ - id: serverId + id: location_id }); } @@ -85,7 +85,7 @@ export async function stepForward(player_id: string): Promise { } export async function clearTravelPlan(player_id: string): Promise { - return completeTravel(player_id); + return db('travel').where({player_id}).delete(); } export async function completeTravel(player_id: string): Promise { diff --git a/src/server/monster.ts b/src/server/monster.ts index 1d5f0fd..7565146 100644 --- a/src/server/monster.ts +++ b/src/server/monster.ts @@ -31,13 +31,13 @@ export async function loadMonster(id: number): Promise { }).first(); } -export async function loadMonsterFromFight(authToken: string): Promise { +export async function loadMonsterFromFight(player_id: string): Promise { return await db.first().select('*').from('fight').where({ - player_id: authToken, + player_id, }); } -export async function loadMonsterWithFaction(authToken: string): Promise { +export async function loadMonsterWithFaction(player_id: string): Promise { 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): Promise { + return db.select('*').from('shop_equipment') + .where(where) + .orderBy('type') + .orderBy('equipment_slot') + .orderByRaw(`requirements->>'level' asc`); +} + +export function getShopEquipment(item_id: number, location_id: number): Promise { + return db.select('*').from('shop_equipment').where({ + id: item_id, + location_id + }).first(); + +} + +export function getShopItem(id: number): Promise { + return db.select('*').from('shop_equipment').where({ + id + }).first(); +} diff --git a/src/server/shopItem.ts b/src/server/shopItem.ts deleted file mode 100644 index 69c55e6..0000000 --- a/src/server/shopItem.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { db } from './lib/db'; -import {ShopItem} from '../shared/inventory'; - -export function listShopItems(where: Partial): Promise { - return db.select('*').from('shop_items') - .where(where) - .orderBy('type') - .orderBy('equipment_slot') - .orderByRaw(`requirements->>'level' asc`); -} - -export function getShopItem(id: number): Promise { - return db.select('*').from('shop_items').where({ - id - }).first(); -} diff --git a/src/server/views/alert.ts b/src/server/views/alert.ts new file mode 100644 index 0000000..8f0fb32 --- /dev/null +++ b/src/server/views/alert.ts @@ -0,0 +1,16 @@ +import { v4 as uuid } from 'uuid'; + +export function Alert(type: 'error' | 'success', text: string): string { + return `
+
${text}
+
+` +} + +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 index 0000000..bca4f8c --- /dev/null +++ b/src/server/views/chat.ts @@ -0,0 +1,8 @@ +import {Message} from "../../shared/message"; + +export function renderChatMessage(msg: Message): string { + return `
+ ${msg.from} + ${msg.msg} +
`; +} diff --git a/src/server/views/fight.ts b/src/server/views/fight.ts new file mode 100644 index 0000000..fdd51b4 --- /dev/null +++ b/src/server/views/fight.ts @@ -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 => `
${d}
`); + + switch(roundData.winner) { + case 'player': + html.push(`
You defeated the ${roundData.monster.name}!
`); + if(roundData.rewards.gold) { + html.push(`
You gained ${roundData.rewards.gold} gold`); + } + if(roundData.rewards.exp) { + html.push(`
You gained ${roundData.rewards.exp} exp`); + } + if(roundData.rewards.levelIncrease) { + html.push(`
You gained a level! ${roundData.player.level}`); + } + break; + case 'monster': + // prompt to return to town and don't let them do anything + html.push(`

You were killed...

`); + html.push('

'); + 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 = `
+
+
+ +
+
+
${monster.name}
+
${hpPercent}% - ${monster.hp} / ${monster.maxHp}
+
+
+
+ ${displayFightActions ? ` +
+ + + + +
+ `: ''} +
+ +
${results}
+
`; + + return html; +} diff --git a/src/server/views/inventory.ts b/src/server/views/inventory.ts new file mode 100644 index 0000000..08fce8e --- /dev/null +++ b/src/server/views/inventory.ts @@ -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 = items.filter(item => item.is_equipped).reduce((acc, item) => { + acc[item.equipment_slot] = item; + return acc; + }, {}); + + const html = ` + + + + + + + + + + + + + + + + +
+ +${map.HEAD ? map.HEAD.name : 'HEAD'} + +${map.ARMS ? map.ARMS.name : 'ARMS'} +
+${map.LEFT_HAND ? map.LEFT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : 'L_HAND')} + +${map.CHEST ? map.CHEST.name : 'CHEST'} + +${map.RIGHT_HAND ? map.RIGHT_HAND.name : (map.TWO_HANDED ? map.TWO_HANDED.name : 'R_HAND')} +
+ +${map.LEGS ? map.LEGS.name : 'LEGS'} + +
+`; + + return html; +} + +function renderInventoryItems(items: PlayerItem[]): string { + return items.map(item => { + return ` +
+ +${item.amount.toLocaleString()} +
`; + }).join("
"); +} + + +function renderRequirement(name: string, val: number | string, currentVal?: number): string { + let colorIndicator = ''; + if(currentVal) { + colorIndicator = currentVal >= val ? 'success' : 'error'; + } + return `${name}: ${val.toLocaleString()}`; +} + +function renderStatBoost(name: string, val: number | string): string { + let valSign: string = ''; + if(typeof val === 'number') { + valSign = val > 0 ? '+' : '-'; + } + return `${name}: ${valSign}${val}`; +} + +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 `
${display}${current}/${max}
`; +} + +function renderInventoryItem(item: EquippedItemDetails , action: (item: EquippedItemDetails) => string): string { + return `
+
+ +
+
+
${item.name}
+
+ ${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)} +
+
+ ${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')} +
+ ${item.hasOwnProperty('id') ? `
${item.cost.toLocaleString()}G
` : ''} +
+
+ ${action(item)} +
+
`; +} + +function renderInventorySection(inventory: EquippedItemDetails[]): string { + return inventory.map(item => { + return renderInventoryItem(item, item => { + if(item.is_equipped) { + return ``; + } + else { + if(item.equipment_slot === 'ANY_HAND') { + return ` +`; + } + else if(item.equipment_slot === 'LEFT_HAND') { + return ``; + } + else if(item.equipment_slot === 'RIGHT_HAND') { + return ``; + } + else { + return ``; + } + } + }) + }).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 = ` +
+
+ ${renderEquipmentPlacementGrid(inventory)} +
+
+ + +
+ ${Object.keys(sectionedInventory).map((type) => { + return `
+ ${type === 'ITEMS' ? renderInventoryItems(sectionedInventory[type]) : renderInventorySection(sectionedInventory[type])} +
`; + }).join("")} +
+
+
+ `; + + return html; + +} diff --git a/src/server/views/map.ts b/src/server/views/map.ts new file mode 100644 index 0000000..6f53fea --- /dev/null +++ b/src/server/views/map.ts @@ -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 { + + if(!data) { + console.error('oh no.. this got triggered without any city data'); + } + + const servicesParsed: Record = { + 'SERVICES': [], + 'STORES': [], + 'EXPLORE': [] + }; + + data.locations.forEach(l => { + servicesParsed[l.type].push(`${l.name}`); + }); + + let html = ` +
+

${data.city.name}

+
`; + + if(servicesParsed.SERVICES.length) { + html += `

Services

${servicesParsed.SERVICES.join("
")}
` + } + if(servicesParsed.STORES.length) { + html += `

Stores

${servicesParsed.STORES.join("
")}
` + } + if(servicesParsed.EXPLORE.length) { + html += `

Explore

${servicesParsed.EXPLORE.join("
")}
` + } + html += ` +
+

Travel

+ ${data.paths.map(path => { + return `${path.ending_city_name}` + }).join("
")} +
+
+
+ `; + + return html; +}; diff --git a/src/server/views/monster-selector.ts b/src/server/views/monster-selector.ts new file mode 100644 index 0000000..8acb82f --- /dev/null +++ b/src/server/views/monster-selector.ts @@ -0,0 +1,13 @@ +import { Monster, MonsterForFight } from "../../shared/monsters"; + +export function renderMonsterSelector(monsters: Monster[] | MonsterForFight[], activeMonsterId: number = 0): string { + let html = `
+ +
`; + + return html; +} diff --git a/src/server/views/player-bar.ts b/src/server/views/player-bar.ts new file mode 100644 index 0000000..effbbdc --- /dev/null +++ b/src/server/views/player-bar.ts @@ -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 `
${display}${current}/${max}
`; +} + +function calcAp(inventoryItem: EquippedItemDetails[]): string { + const ap: Record = {}; + inventoryItem.forEach(item => { + if(item.is_equipped && item.type === 'ARMOUR') { + ap[item.equipment_slot] = { + currentAp: item.currentAp, + maxAp: item.maxAp + }; + } + }); + + return ` +
+ + ${generateProgressBar(ap.HEAD?.currentAp || 0, ap.HEAD?.maxAp || 0, '#7be67b')} +
+
+ + ${generateProgressBar(ap.ARMS?.currentAp || 0, ap.ARMS?.maxAp || 0, '#7be67b')} +
+
+ + ${generateProgressBar(ap.CHEST?.currentAp || 0, ap.CHEST?.maxAp || 0, '#7be67b')} +
+
+ + ${generateProgressBar(ap.LEGS?.currentAp || 0, ap.LEGS?.maxAp || 0, '#7be67b')} +
+`; +} + +function progressBar(current: number, max: number, id: string, color: string) { + let percent = 0; + if(max > 0) { + percent = Math.floor((current / max) * 100); + } + + return `
${current}/${max} - ${percent}
`; +} + +export function renderPlayerBar(player: Player, inventory: EquippedItemDetails[]): string { + return ` +
+
+
${player.username}, level ${player.level} ${player.profession}
+
${player.gold.toLocaleString()}
+
+
${calcAp(inventory)}
+ ${progressBar(player.hp, maxHp(player.constitution, player.level), 'hp-bar', '#ff7070')} + ${progressBar(player.exp, expToLevel(player.level + 1), 'exp-bar', '#5997f9')} +
+ `; + +} diff --git a/src/server/views/profile.ts b/src/server/views/profile.ts new file mode 100644 index 0000000..0d8468b --- /dev/null +++ b/src/server/views/profile.ts @@ -0,0 +1,27 @@ +import { Player, StatDef, StatDisplay } from "../../shared/player"; + +function statPointIncreaser(stat: StatDisplay) { + return ``; +} +export async function renderProfilePage(player: Player): Promise { + let statBreakdown = ''; + + StatDef.forEach(stat => { + statBreakdown += ` + ${stat.display} + + ${player[stat.id]} + ${player.stat_points ? statPointIncreaser(stat) : ''} + + `; + }); + + const html = `
+ + ${statBreakdown} + +
Stat Points${player.stat_points}
+
`; + + return html; +} diff --git a/src/server/views/skills.ts b/src/server/views/skills.ts new file mode 100644 index 0000000..0c11815 --- /dev/null +++ b/src/server/views/skills.ts @@ -0,0 +1,22 @@ +import { Skill, Skills } from "../../shared/skills"; + +export function renderSkills(skills: Skill[]): string { + let html = ` + ${skills.map((skill: Skill) => { + const definition = Skills.get(skill.id); + const percent = skill.exp / definition.expToLevel(skill.level + 1); + return ` + + + + + `; + }).join("\n")} +
${skill.level.toLocaleString()} + ${(percent * 100).toPrecision(2)}% to next level + ${definition.display} +

${definition.description}

+
`; + + return html; +} diff --git a/src/server/views/stores.ts b/src/server/views/stores.ts new file mode 100644 index 0000000..6c237d1 --- /dev/null +++ b/src/server/views/stores.ts @@ -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 `${name}: ${valSign}${val}`; +} + +function renderRequirement(name: string, val: number | string, currentVal?: number): string { + let colorIndicator = ''; + if(currentVal) { + colorIndicator = currentVal >= val ? 'success' : 'error'; + } + return `${name}: ${val.toLocaleString()}`; +} + +function renderShopItem(item: (ShopItem & Item), action: (item: (ShopItem & Item)) => string): string { + return `
+
+ +
+
+
${item.name}
+
+ ${item.description} +
+ ${item.hasOwnProperty('id') ? `
${item.price_per_unit.toLocaleString()}G
` : ''} +
+
+ ${action(item)} +
+
`; +} + +export function renderEquipmentDetails(item: ShopEquipment, player: Player): string { + return ` +
+
${item.name}${item.equipment_slot === 'TWO_HANDED' ? ' (2H)': ''}
+
+ ${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)} +
+
+ ${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())} +
+ ${item.hasOwnProperty('id') ? `
${item.cost.toLocaleString()}G
` : ''} +
+` + +} + +function renderShopEquipment(item: ShopEquipment, action: (item: ShopEquipment) => string, player: Player): string { + return `
+
+ +
+ ${renderEquipmentDetails(item, player)} +
+ ${action(item)} +
+
`; +} + + + +export async function renderStore(equipment: ShopEquipment[], items: (ShopItem & Item)[], player: Player): Promise { + const listing: Record = {}; + const listingTypes = new Set(); + + 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 `` + }, player); + + }); + + if(items && items.length) { + listingTypes.add('ITEMS'); + listing['ITEMS'] = ''; + items.forEach(item => { + listing['ITEMS'] += renderShopItem(item, i => { + return ``; + }); + }); + } + + let activeTab: string = listingTypes.keys().next().value; + + const nav: string[] = []; + const finalListing: string[] = []; + + listingTypes.forEach(type => { + nav.push(`${capitalize(type)}`); + finalListing.push(`
${listing[type]}
`); + }); + + let html = `
+
+ ${finalListing.join("\n")} +
+
`; + + return html; +} diff --git a/src/server/views/travel.ts b/src/server/views/travel.ts new file mode 100644 index 0000000..fc70860 --- /dev/null +++ b/src/server/views/travel.ts @@ -0,0 +1,39 @@ +import { TravelDTO } from "../../shared/map"; + +export function travelButton(blockTime: number): string { + return ``; +} + +export function renderTravel(data: TravelDTO): string { + + let promptText = data.walkingText; + const blockTime = data.nextAction || 0; + + /* + if(blockTime) { + updateStepButton(); + } + */ + + let html = `
+
`; + html += '
'; + 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 += `
+ + +
`; + } + + // end #travelling-actions + html += '
'; + html += `

${promptText}

`; + + html += '
'; + + return html; +} diff --git a/src/shared/inventory.ts b/src/shared/inventory.ts index c3b58b6..6c18807 100644 --- a/src/shared/inventory.ts +++ b/src/shared/inventory.ts @@ -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 -export type ShopItem = Omit & { +export type ShopEquipment = Omit & { id: number; location_id: number; }; diff --git a/src/shared/items/base.ts b/src/shared/items/base.ts new file mode 100644 index 0000000..948362b --- /dev/null +++ b/src/shared/items/base.ts @@ -0,0 +1,6 @@ +import { Player } from "../player" + +export type ItemEffect = { + 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 index 0000000..248e232 --- /dev/null +++ b/src/shared/items/health_potion.ts @@ -0,0 +1,12 @@ +import { ItemEffect } from "./base"; +import { maxHp, Player } from "../player"; + +export const HealthPotionSmall: ItemEffect = { + 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 index 0000000..eeb0aef --- /dev/null +++ b/src/shared/items/index.ts @@ -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> = new Map>(); + +ItemEffects.set(HealthPotionSmall.name, HealthPotionSmall); diff --git a/src/shared/map.ts b/src/shared/map.ts index 015771f..5fe8b40 100644 --- a/src/shared/map.ts +++ b/src/shared/map.ts @@ -21,3 +21,12 @@ export type Path = { ending_city_name: string; distance: number; } + +export type TravelDTO = { + things: any[], + nextAction: number, + walkingText: string, + closestTown: number; +} + +export const STEP_DELAY = 3000; diff --git a/src/shared/time.ts b/src/shared/time.ts index 8e40f12..0fb104f 100644 --- a/src/shared/time.ts +++ b/src/shared/time.ts @@ -75,7 +75,7 @@ export class TimeManager { const min = this.get24Hour(); return ( min >= 0 && min < 5 || - min >= 22 && min < 24 + min >= 21 && min < 24 ); } diff --git a/webpack.config.js b/webpack.config.js index df9ddbd..d55a9dc 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -8,7 +8,7 @@ module.exports = { mode: env, devtool: env === 'development' ? "inline-source-map" : false, entry: { - main: "./src/client/index.ts", + main: "./src/client/htmx.ts", }, module: { rules: [