diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..6d31f6f --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +node_modules +build +src/frontend/shims-vue.d.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..2080395 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,17 @@ +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + plugins: [ + '@typescript-eslint', + ], + parserOptions: { + ecmaVersion: 2020, + }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + ], + rules: { + '@typescript-eslint/no-inferrable-types': 'off' + } +}; diff --git a/build/public/assets/click.bb97cb07.mp3 b/build/public/assets/click.bb97cb07.mp3 new file mode 100644 index 0000000..8189619 Binary files /dev/null and b/build/public/assets/click.bb97cb07.mp3 differ diff --git a/build/public/assets/index.22dc307c.css b/build/public/assets/index.22dc307c.css new file mode 100644 index 0000000..b986684 --- /dev/null +++ b/build/public/assets/index.22dc307c.css @@ -0,0 +1 @@ +:root{--main-color:#c1b19f;--main-darker-color:#4f4e4c;--link-color:#808db0;--link-hover-color:#c5cfeb;--highlight-color:#dd7e7e;--positive-color:#64a756;--input-bg-color:#262523;--bg-color:rgba(0,0,0,.7)}body,html{margin:0;background:#2b2b2b;color:var(--main-color);height:100%}*{font-family:monospace;font-size:15px}h1,h2,h3,h4{font-size:20px}a{color:var(--link-color);text-decoration:none}a:hover{color:var(--link-hover-color)}td,th{vertical-align:top}.btn{display:inline-block;background:var(--input-bg-color);color:var(--link-color);border:solid 1px #000;padding:5px 10px;box-shadow:1px 1px 2px rgba(0,0,0,.5),0 0 1px rgba(150,150,150,.4) inset;border-radius:4px;user-select:none}.btn-big{font-size:1.5em;padding:10px 20px}.btn:hover{background:#2f2e2c;color:var(--link-hover-color);border:solid 1px #111;box-shadow:0 0 1px rgba(150,150,150,.4) inset;cursor:pointer}.btn:disabled{background:#2f2e2c;color:#8c4747!important;border:solid 1px #111;box-shadow:0 0 1px rgba(150,150,150,.4) inset;cursor:not-allowed}input{background:#333230;border-radius:4px;color:var(--main-color);padding:6px 10px;border:solid 1px #000;box-shadow:0 0 3px rgba(0,0,0,.3) inset}input:focus{border:solid 1px #686767;background:var(--input-bg-color)}.scores{position:absolute;right:0;top:0;background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7)}.timer{position:absolute;left:0;top:0;background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7)}.menu{position:absolute;top:0;left:50%;transform:translateX(-50%);background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7);z-index:2}.closed{display:none}.overlay{position:fixed;top:0;left:0;right:0;bottom:0;z-index:10;background:var(--bg-color)}.overlay.transparent{background:0 0}.overlay-content{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7);z-index:1}.connection-lost .overlay-content{padding:20px;text-align:center}.preview{position:absolute;top:20px;left:20px;bottom:20px;right:20px}.preview .img{height:100%;width:100%;position:absolute;background-repeat:no-repeat;background-position:center;background-size:contain}.menu .opener{display:inline-block;margin-right:10px;color:var(--link-color)}.menu .opener:last-child{margin-right:0}.menu .opener:hover{color:var(--link-hover-color);cursor:pointer}kbd{background-color:#eee;border-radius:3px;border:1px solid #b4b4b4;box-shadow:0 1px 1px rgba(0,0,0,.2),0 2px 0 0 rgba(255,255,255,.7) inset;color:#333;display:inline-block;font-size:.85em;font-weight:700;line-height:1;padding:2px 4px;white-space:nowrap}.hint{color:var(--main-darker-color)}.bit{background:#3b3737;border-radius:.5em;padding:.25em .5em;display:inline-block;margin:0 .25em .25em 0;cursor:pointer}.bit.on{color:var(--positive-color)}.upload-image-teaser{text-align:center}.upload-image-teaser .btn{margin-bottom:.5em}table label{line-height:32px}.nav{list-style:none;padding:0}.nav li{display:inline-block;margin-right:1em}.image-list{overflow:scroll}.image-list-inner{white-space:nowrap}.imageteaser{width:150px;height:100px;display:inline-block;margin:5px;background-size:contain;background-position:center;background-repeat:no-repeat;background-color:#222;cursor:pointer}.game-teaser-wrap{display:inline-block;width:20%;padding:5px;box-sizing:border-box}.game-teaser{display:block;background-repeat:no-repeat;background-position:center;background-size:contain;position:relative;padding-top:56.25%;width:100%;background-color:#222}.game-info{position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%}.game-info-text{position:absolute;top:0;background:var(--bg-color);padding:5px}.game-replay{position:absolute;top:0;right:0}html.view-game{overflow:hidden}html.view-game body{overflow:hidden}html.view-replay{overflow:hidden}html.view-replay body{overflow:hidden}.imageteaser{position:relative}.imageteaser .edit{display:none;position:absolute}.imageteaser:hover .edit{display:inline-block}.input[data-v-a4fa5e7e]{margin-bottom:.5em}.autocomplete[data-v-a4fa5e7e]{position:relative}.autocomplete ul[data-v-a4fa5e7e]{list-style:none;padding:0;margin:0;position:absolute;left:0;right:0;background:#333230;top:-.5em}.autocomplete ul li[data-v-a4fa5e7e]{position:relative;padding:.5em .5em .5em 1.5em;cursor:pointer}.autocomplete ul li.active[data-v-a4fa5e7e]{color:var(--link-hover-color);background:var(--input-bg-color)}.autocomplete ul li.active[data-v-a4fa5e7e]:before{content:'▶';display:block;position:absolute;left:.5em}.new-image-dialog .overlay-content{display:grid;grid-template-columns:auto 450px;grid-template-rows:auto;grid-template-areas:"image settings" "image buttons";height:90%;width:80%}@media (max-width:1400px) and (min-height:720px),(max-width:1000px){.new-image-dialog .overlay-content{grid-template-columns:auto;grid-template-rows:1fr min-content min-content;grid-template-areas:"image" "settings" "buttons"}.new-image-dialog .overlay-content .area-buttons .btn br{display:none}}.new-image-dialog .area-image{grid-area:image;margin:.5em;border:solid 6px transparent}.new-image-dialog .area-image.no-image{align-content:center;display:grid;text-align:center;border:solid 6px;position:relative}.new-image-dialog .area-image.droppable{border:dashed 6px}.new-image-dialog .area-image .has-image{position:relative;width:100%;height:100%}.new-image-dialog .area-image .has-image .remove{position:absolute;top:.5em;left:.5em}.new-image-dialog .area-settings{grid-area:settings}.new-image-dialog .area-settings table input[type=text]{width:100%;box-sizing:border-box}.new-image-dialog .area-buttons{align-self:end;grid-area:buttons}.new-image-dialog .area-buttons button{width:100%;margin-top:.5em}.new-image-dialog .upload{position:absolute;top:0;left:0;right:0;bottom:0;cursor:pointer}.new-image-dialog .upload .btn{position:absolute;top:50%;transform:translate(-50%,-50%)}.area-image .drop-target{display:none}.area-image.droppable .drop-target{pointer-events:none;position:absolute;top:0;left:0;right:0;bottom:0;z-index:3}.edit-image-dialog .overlay-content{display:grid;grid-template-columns:auto 450px;grid-template-rows:auto;grid-template-areas:"image settings" "image buttons";height:90%;width:80%}@media (max-width:1400px) and (min-height:720px),(max-width:1000px){.edit-image-dialog .overlay-content{grid-template-columns:auto;grid-template-rows:1fr min-content min-content;grid-template-areas:"image" "settings" "buttons"}}.edit-image-dialog .area-image{grid-area:image;margin:20px}.edit-image-dialog .area-image.no-image{align-content:center;display:grid;text-align:center;border:dashed 6px;position:relative}.edit-image-dialog .area-image .has-image{position:relative;width:100%;height:100%}.edit-image-dialog .area-image .has-image .remove{position:absolute;top:.5em;left:.5em}.edit-image-dialog .area-settings{grid-area:settings}.edit-image-dialog .area-settings table input[type=text]{width:100%;box-sizing:border-box}.edit-image-dialog .area-buttons{align-self:end;grid-area:buttons}.edit-image-dialog .area-buttons button{width:100%;margin-top:.5em}.new-game-dialog .overlay-content{display:grid;grid-template-columns:auto 450px;grid-template-rows:auto;grid-template-areas:"image settings" "image buttons";height:90%;width:80%}.new-game-dialog .area-image{grid-area:image;display:grid;grid-template-rows:1fr min-content;grid-template-areas:"image" "image-title";margin-right:1em}@media (max-width:1400px) and (min-height:720px),(max-width:1000px){.new-game-dialog .overlay-content{grid-template-columns:auto;grid-template-rows:1fr min-content min-content;grid-template-areas:"image" "settings" "buttons"}.new-game-dialog .area-image{margin-right:0}}.new-game-dialog .area-settings{grid-area:settings}.new-game-dialog .area-settings table input[type=text]{width:100%;box-sizing:border-box}.new-game-dialog .area-buttons{align-self:end;grid-area:buttons}.new-game-dialog .area-buttons button{width:100%}.new-game-dialog .has-image{box-sizing:border-box;grid-area:image;position:relative;width:100%;height:100%;border:solid 1px}.new-game-dialog .image-title{grid-area:image-title;text-align:center;padding:.5em 0;background:var(--main-color);color:#262523}.new-game-dialog .has-image .remove{position:absolute;top:.5em;left:.5em}.new-game-dialog .image-title>span{margin-right:.5em}.new-game-dialog .image-title>span:last-child{margin-right:0}.image-title-dim{display:inline-block;white-space:no-wrap}.sound-volume span[data-v-4d56fc17]{cursor:pointer;user-select:none}.sound-volume input[data-v-4d56fc17]{vertical-align:middle} \ No newline at end of file diff --git a/build/public/assets/index.50ee8245.js b/build/public/assets/index.50ee8245.js deleted file mode 100644 index ba9ec2e..0000000 --- a/build/public/assets/index.50ee8245.js +++ /dev/null @@ -1 +0,0 @@ -import{d as e,c as t,a as n,w as l,b as i,r as o,o as a,e as s,t as r,F as d,f as c,g as u,h as g,v as p,i as h,j as m,k as y,l as f,m as w,n as v,p as b,q as x,s as C}from"./vendor.b622ee49.js";var k=e({name:"app",computed:{showNav(){return!["game","replay"].includes(String(this.$route.name))}}});const A={id:"app"},T={key:0,class:"nav"},S=s("Index"),z=s("New game");k.render=function(e,s,r,d,c,u){const g=o("router-link"),p=o("router-view");return a(),t("div",A,[e.showNav?(a(),t("ul",T,[n("li",null,[n(g,{class:"btn",to:{name:"index"}},{default:l((()=>[S])),_:1})]),n("li",null,[n(g,{class:"btn",to:{name:"new-game"}},{default:l((()=>[z])),_:1})])])):i("",!0),n(p)])};const I=864e5,P=e=>{const t=Math.floor(e/I);e%=I;const n=Math.floor(e/36e5);e%=36e5;const l=Math.floor(e/6e4);e%=6e4;return`${t}d ${n}h ${l}m ${Math.floor(e/1e3)}s`};var _=1e3,D=()=>{const e=new Date;return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds(),e.getUTCMilliseconds())},B=(e,t)=>P(t-e),E=P,O=e({name:"game-teaser",props:{game:{type:Object,required:!0}},computed:{style(){return{"background-image":`url("${this.game.imageUrl.replace("uploads/","uploads/r/")+"-375x210.webp"}")`}}},methods:{time(e,t){const n=t?"🏁":"⏳",l=e,i=t||D();return`${n} ${B(l,i)}`}}});const U={class:"game-info-text"},N=n("br",null,null,-1),M=n("br",null,null,-1),G=n("br",null,null,-1);O.render=function(e,d,c,u,g,p){const h=o("router-link");return a(),t("div",{class:"game-teaser",style:e.style},[n(h,{class:"game-info",to:{name:"game",params:{id:e.game.id}}},{default:l((()=>[n("span",U,[s(" 🧩 "+r(e.game.tilesFinished)+"/"+r(e.game.tilesTotal),1),N,s(" 👥 "+r(e.game.players),1),M,s(" "+r(e.time(e.game.started,e.game.finished)),1),G])])),_:1},8,["to"]),i("",!0)],4)};var $=e({components:{GameTeaser:O},data:()=>({gamesRunning:[],gamesFinished:[]}),async created(){const e=await fetch("/api/index-data"),t=await e.json();this.gamesRunning=t.gamesRunning,this.gamesFinished=t.gamesFinished}});const R=n("h1",null,"Running games",-1),V=n("h1",null,"Finished games",-1);$.render=function(e,l,i,s,r,u){const g=o("game-teaser");return a(),t("div",null,[R,(a(!0),t(d,null,c(e.gamesRunning,((e,l)=>(a(),t("div",{class:"game-teaser-wrap",key:l},[n(g,{game:e},null,8,["game"])])))),128)),V,(a(!0),t(d,null,c(e.gamesFinished,((e,l)=>(a(),t("div",{class:"game-teaser-wrap",key:l},[n(g,{game:e},null,8,["game"])])))),128))])};var j=e({name:"image-teaser",props:{image:{type:Object,required:!0}},computed:{style(){return{backgroundImage:`url("${this.image.url.replace("uploads/","uploads/r/")+"-150x100.webp"}")`}}},emits:{click:null,editClick:null},methods:{onClick(){this.$emit("click")},onEditClick(){this.$emit("editClick")}}});j.render=function(e,l,i,o,s,r){return a(),t("div",{class:"imageteaser",style:e.style,onClick:l[2]||(l[2]=(...t)=>e.onClick&&e.onClick(...t))},[n("div",{class:"btn edit",onClick:l[1]||(l[1]=u(((...t)=>e.onEditClick&&e.onEditClick(...t)),["stop"]))},"✏️")],4)};var F=e({name:"image-library",components:{ImageTeaser:j},props:{images:{type:Array,required:!0}},emits:{imageClicked:null,imageEditClicked:null},methods:{imageClicked(e){this.$emit("imageClicked",e)},imageEditClicked(e){this.$emit("imageEditClicked",e)}}});F.render=function(e,n,l,i,s,r){const u=o("image-teaser");return a(),t("div",null,[(a(!0),t(d,null,c(e.images,((n,l)=>(a(),t(u,{image:n,onClick:t=>e.imageClicked(n),onEditClick:t=>e.imageEditClicked(n),key:l},null,8,["image","onClick","onEditClick"])))),128))])};const L={name:"responsive-image",props:{src:String,title:{type:String,default:""},height:{type:String,default:"100%"},width:{type:String,default:"100%"}},computed:{style(){return{display:"inline-block",verticalAlign:"text-bottom",backgroundImage:`url('${this.src}')`,backgroundRepeat:"no-repeat",backgroundSize:"contain",backgroundPosition:"center",width:this.width,height:this.height}}}};L.render=function(e,n,l,i,o,s){return a(),t("div",{style:s.style,title:l.title},null,12,["title"])};var W=e({name:"tags-input",props:{modelValue:{type:Array,required:!0}},emits:{"update:modelValue":null},data:()=>({input:"",values:[]}),created(){this.values=this.modelValue},methods:{onKeyUp(e){if(","===e.key)return this.add(),e.stopPropagation(),!1},add(){const e=this.input.replace(/,/g,"").trim();e&&(this.values.includes(e)||this.values.push(e),this.input="",this.$emit("update:modelValue",this.values))},rm(e){this.values=this.values.filter((t=>t!==e)),this.$emit("update:modelValue",this.values)}}});const H=m()(((e,l,i,o,s,u)=>(a(),t("div",null,[g(n("input",{class:"input",type:"text","onUpdate:modelValue":l[1]||(l[1]=t=>e.input=t),placeholder:"Plants, People",onKeydown:l[2]||(l[2]=h(((...t)=>e.add&&e.add(...t)),["enter"])),onKeyup:l[3]||(l[3]=(...t)=>e.onKeyUp&&e.onKeyUp(...t))},null,544),[[p,e.input]]),(a(!0),t(d,null,c(e.values,((n,l)=>(a(),t("span",{key:l,class:"bit",onClick:t=>e.rm(n)},r(n)+" ✖",9,["onClick"])))),128))]))));W.render=H,W.__scopeId="data-v-771460ae";var Q=e({name:"new-image-dialog",components:{ResponsiveImage:L,TagsInput:W},emits:{bgclick:null,setupGameClick:null,postToGalleryClick:null},data:()=>({previewUrl:"",file:null,title:"",tags:[]}),computed:{canPostToGallery(){return!(!this.previewUrl||!this.file)},canSetupGameClick(){return!(!this.previewUrl||!this.file)}},methods:{preview(e){const t=e.target;if(!t.files)return;const n=t.files[0];if(!n)return;const l=new FileReader;l.readAsDataURL(n),l.onload=e=>{this.previewUrl=e.target.result,this.file=n}},postToGallery(){this.$emit("postToGalleryClick",{file:this.file,title:this.title,tags:this.tags})},setupGameClick(){this.$emit("setupGameClick",{file:this.file,title:this.title,tags:this.tags})}}});const Y={key:0,class:"has-image"},q={key:1},K={class:"upload"},Z=n("span",{class:"btn"},"Upload File",-1),J={class:"area-settings"},X=n("td",null,[n("label",null,"Title")],-1),ee=n("tr",null,[n("td",{colspan:"2"},[n("div",{class:"hint"},"Feel free to leave a credit to the artist/photographer in the title :)")])],-1),te=n("td",null,[n("label",null,"Tags")],-1),ne={class:"area-buttons"},le=s("🧩 Post to gallery "),ie=n("br",null,null,-1),oe=s(" + set up game");Q.render=function(e,l,i,s,r,d){const c=o("responsive-image"),h=o("tags-input");return a(),t("div",{class:"overlay new-image-dialog",onClick:l[8]||(l[8]=t=>e.$emit("bgclick"))},[n("div",{class:"overlay-content",onClick:l[7]||(l[7]=u((()=>{}),["stop"]))},[n("div",{class:["area-image",{"has-image":!!e.previewUrl,"no-image":!e.previewUrl}]},[e.previewUrl?(a(),t("div",Y,[n("span",{class:"remove btn",onClick:l[1]||(l[1]=t=>e.previewUrl="")},"X"),n(c,{src:e.previewUrl},null,8,["src"])])):(a(),t("div",q,[n("label",K,[n("input",{type:"file",style:{display:"none"},onChange:l[2]||(l[2]=(...t)=>e.preview&&e.preview(...t)),accept:"image/*"},null,32),Z])]))],2),n("div",J,[n("table",null,[n("tr",null,[X,n("td",null,[g(n("input",{type:"text","onUpdate:modelValue":l[3]||(l[3]=t=>e.title=t),placeholder:"Flower by @artist"},null,512),[[p,e.title]])])]),ee,n("tr",null,[te,n("td",null,[n(h,{modelValue:e.tags,"onUpdate:modelValue":l[4]||(l[4]=t=>e.tags=t)},null,8,["modelValue"])])])])]),n("div",ne,[n("button",{class:"btn",disabled:!e.canPostToGallery,onClick:l[5]||(l[5]=(...t)=>e.postToGallery&&e.postToGallery(...t))},"🖼️ Post to gallery",8,["disabled"]),n("button",{class:"btn",disabled:!e.canSetupGameClick,onClick:l[6]||(l[6]=(...t)=>e.setupGameClick&&e.setupGameClick(...t))},[le,ie,oe],8,["disabled"])])])])};var ae=e({name:"edit-image-dialog",components:{ResponsiveImage:L,TagsInput:W},props:{image:{type:Object,required:!0}},emits:{bgclick:null,saveClick:null},data:()=>({title:"",tags:[]}),created(){this.title=this.image.title,this.tags=this.image.tags.map((e=>e.title))},methods:{saveImage(){this.$emit("saveClick",{id:this.image.id,title:this.title,tags:this.tags})}}});const se={class:"area-image"},re={class:"has-image"},de={class:"area-settings"},ce=n("td",null,[n("label",null,"Title")],-1),ue=n("tr",null,[n("td",{colspan:"2"},[n("div",{class:"hint"},"Feel free to leave a credit to the artist/photographer in the title :)")])],-1),ge=n("td",null,[n("label",null,"Tags")],-1),pe={class:"area-buttons"};function he(e,t){const n=e.x-t.x,l=e.y-t.y;return Math.sqrt(n*n+l*l)}function me(e){return{x:e.x+e.w/2,y:e.y+e.h/2}}ae.render=function(e,l,i,s,r,d){const c=o("responsive-image"),h=o("tags-input");return a(),t("div",{class:"overlay edit-image-dialog",onClick:l[5]||(l[5]=t=>e.$emit("bgclick"))},[n("div",{class:"overlay-content",onClick:l[4]||(l[4]=u((()=>{}),["stop"]))},[n("div",se,[n("div",re,[n(c,{src:e.image.url,title:e.image.title},null,8,["src","title"])])]),n("div",de,[n("table",null,[n("tr",null,[ce,n("td",null,[g(n("input",{type:"text","onUpdate:modelValue":l[1]||(l[1]=t=>e.title=t),placeholder:"Flower by @artist"},null,512),[[p,e.title]])])]),ue,n("tr",null,[ge,n("td",null,[n(h,{modelValue:e.tags,"onUpdate:modelValue":l[2]||(l[2]=t=>e.tags=t)},null,8,["modelValue"])])])])]),n("div",pe,[n("button",{class:"btn",onClick:l[3]||(l[3]=(...t)=>e.saveImage&&e.saveImage(...t))},"🖼️ Save image")])])])};var ye={pointSub:function(e,t){return{x:e.x-t.x,y:e.y-t.y}},pointAdd:function(e,t){return{x:e.x+t.x,y:e.y+t.y}},pointDistance:he,pointInBounds:function(e,t){return e.x>=t.x&&e.x<=t.x+t.w&&e.y>=t.y&&e.y<=t.y+t.h},rectCenter:me,rectMoved:function(e,t,n){return{x:e.x+t,y:e.y+n,w:e.w,h:e.h}},rectCenterDistance:function(e,t){return he(me(e),me(t))},rectsOverlap:function(e,t){return!(t.x>e.x+e.w||e.x>t.x+t.w||t.y>e.y+e.h||e.y>t.y+t.h)}};var fe=1,we=4,ve=5,be=2,xe=3,Ce=6,ke=2,Ae=4,Te=3,Se=9,ze=1,Ie=2,Pe=3,_e=4,De=5,Be=6,Ee=7,Oe=8,Ue=10,Ne=1,Me=2,Ge=3;class $e{constructor(e){this.rand_high=e||3735929054,this.rand_low=1231121986^e}random(e,t){return this.rand_high=(this.rand_high<<16)+(this.rand_high>>16)+this.rand_low&4294967295,this.rand_low=this.rand_low+this.rand_high&4294967295,e+(this.rand_high>>>0)/4294967295*(t-e+1)|0}choice(e){return e[this.random(0,e.length-1)]}shuffle(e){const t=e.slice();for(let n=0;n<=t.length-2;n++){const e=this.random(n,t.length-1),l=t[n];t[n]=t[e],t[e]=l}return t}static serialize(e){return{rand_high:e.rand_high,rand_low:e.rand_low}}static unserialize(e){const t=new $e(0);return t.rand_high=e.rand_high,t.rand_low=e.rand_low,t}}const Re=(e,t)=>{const n=`${e}`;return n.length>=t.length?n:t.substr(0,t.length-n.length)+n},Ve=(...e)=>{const t=t=>(...n)=>{const l=new Date,i=Re(l.getHours(),"00"),o=Re(l.getMinutes(),"00"),a=Re(l.getSeconds(),"00");console[t](`${i}:${o}:${a}`,...e,...n)};return{log:t("log"),error:t("error"),info:t("info")}};var je,Fe,Le,We,He={hash:e=>{let t=0;for(let n=0;n{let t=e.toLowerCase();return t=t.replace(/[^a-z0-9]+/g,"-"),t=t.replace(/^-|-$/,""),t},uniqId:()=>Date.now().toString(36)+Math.random().toString(36).substring(2),encodeShape:function(e){return e.top+1<<0|e.right+1<<2|e.bottom+1<<4|e.left+1<<6},decodeShape:function(e){return{top:(e>>0&3)-1,right:(e>>2&3)-1,bottom:(e>>4&3)-1,left:(e>>6&3)-1}},encodeTile:function(e){return[e.idx,e.pos.x,e.pos.y,e.z,e.owner,e.group]},decodeTile:function(e){return{idx:e[0],pos:{x:e[1],y:e[2]},z:e[3],owner:e[4],group:e[5]}},encodePlayer:function(e){return[e.id,e.x,e.y,e.d,e.name,e.color,e.bgcolor,e.points,e.ts]},decodePlayer:function(e){return{id:e[0],x:e[1],y:e[2],d:e[3],name:e[4],color:e[5],bgcolor:e[6],points:e[7],ts:e[8]}},encodeGame:function(e){return Array.isArray(e)?e:[e.id,e.rng.type,$e.serialize(e.rng.obj),e.puzzle,e.players,e.evtInfos,e.scoreMode]},decodeGame:function(e){return Array.isArray(e)?{id:e[0],rng:{type:e[1],obj:$e.unserialize(e[2])},puzzle:e[3],players:e[4],evtInfos:e[5],scoreMode:e[6]}:e},coordByTileIdx:function(e,t){const n=e.width/e.tileSize;return{x:t%n,y:Math.floor(t/n)}},asQueryArgs:function(e){const t=[];for(let n in e){const l=[n,e[n]].map(encodeURIComponent);t.push(l.join("="))}return 0===t.length?"":`?${t.join("&")}`}};(Fe=je||(je={}))[Fe.Flat=0]="Flat",Fe[Fe.Out=1]="Out",Fe[Fe.In=-1]="In",(We=Le||(Le={}))[We.FINAL=0]="FINAL",We[We.ANY=1]="ANY";const Qe={};function Ye(e,t){return{id:e,x:0,y:0,d:0,name:null,color:null,bgcolor:null,points:0,ts:t}}function qe(e,t){let n=0;for(let l of Qe[e].players){if(He.decodePlayer(l).id===t)return n;n++}return-1}function Ke(e,t){const n=qe(e,t);return He.decodePlayer(Qe[e].players[n])}function Ze(e,t,n){const l=qe(e,t);-1===l?Qe[e].players.push(He.encodePlayer(n)):Qe[e].players[l]=He.encodePlayer(n)}function Je(e,t){return-1!==qe(e,t)}function Xe(e){return Qe[e]?Qe[e].players.map(He.decodePlayer):[]}function et(e){return Qe[e].puzzle.tiles.length}function tt(e){return Qe[e].scoreMode||0}function nt(e){return lt(e)===et(e)}function lt(e){let t=0;for(let n of Qe[e].puzzle.tiles)-1===He.decodeTile(n).owner&&t++;return t}function it(e,t,n){const l=Ke(e,t);for(let i of Object.keys(n))l[i]=n[i];Ze(e,t,l)}function ot(e,t){for(let n of Object.keys(t))Qe[e].puzzle.data[n]=t[n]}function at(e,t,n){for(let l of Object.keys(n)){const i=He.decodeTile(Qe[e].puzzle.tiles[t]);i[l]=n[l],Qe[e].puzzle.tiles[t]=He.encodeTile(i)}}const st=(e,t)=>He.decodeTile(Qe[e].puzzle.tiles[t]),rt=(e,t)=>st(e,t).group,dt=(e,t)=>{const n=Qe[e].puzzle.info,l={x:(n.table.width-n.width)/2,y:(n.table.height-n.height)/2},i=function(e,t){const n=Qe[e].puzzle.info,l=He.coordByTileIdx(n,t),i=l.x*n.tileSize,o=l.y*n.tileSize;return{x:i,y:o}}(e,t);return ye.pointAdd(l,i)},ct=(e,t)=>st(e,t).pos,ut=e=>{const t=St(e),n=zt(e),l=Math.round(t/4),i=Math.round(n/4);return{x:0-l,y:0-i,w:t+2*l,h:n+2*i}},gt=(e,t)=>{const n=yt(e),l=st(e,t);return{x:l.pos.x,y:l.pos.y,w:n,h:n}},pt=(e,t)=>st(e,t).z,ht=(e,t)=>{for(let n of Qe[e].puzzle.tiles){const e=He.decodeTile(n);if(e.owner===t)return e.idx}return-1},mt=e=>Qe[e].puzzle.info.tileDrawSize,yt=e=>Qe[e].puzzle.info.tileSize,ft=e=>Qe[e].puzzle.data.maxGroup,wt=e=>Qe[e].puzzle.data.maxZ;function vt(e,t){const n=Qe[e].puzzle.info,l=He.coordByTileIdx(n,t);return[l.y>0?t-n.tilesX:-1,l.x0?t-1:-1]}const bt=(e,t,n)=>{for(let l of t)at(e,l,{z:n})},xt=(e,t,n)=>{const l=ct(e,t);at(e,t,{pos:ye.pointAdd(l,n)})},Ct=(e,t,n)=>{const l=mt(e),i=ut(e),o=n;for(let a of t){const t=st(e,a);t.pos.x+n.xi.x+i.w&&(o.x=Math.min(i.x+i.w-t.pos.x+l,o.x)),t.pos.y+n.yi.y+i.h&&(o.y=Math.min(i.y+i.h-t.pos.y+l,o.y))}for(let a of t)xt(e,a,o)},kt=(e,t,n)=>{for(let l of t)at(e,l,{owner:n})};function At(e,t){const n=Qe[e].puzzle.tiles,l=He.decodeTile(n[t]),i=[];if(l.group)for(let o of n){const e=He.decodeTile(o);e.group===l.group&&i.push(e.idx)}else i.push(l.idx);return i}const Tt=(e,t)=>{const n=Ke(e,t);return n?n.points:0},St=e=>Qe[e].puzzle.info.table.width,zt=e=>Qe[e].puzzle.info.table.height;var It={__createPlayerObject:Ye,setGame:function(e,t){Qe[e]=t},exists:function(e){return!!Qe[e]||!1},playerExists:Je,getActivePlayers:function(e,t){const n=t-30*_;return Xe(e).filter((e=>e.ts>=n))},getIdlePlayers:function(e,t){const n=t-30*_;return Xe(e).filter((e=>e.ts0))},addPlayer:function(e,t,n){Je(e,t)?it(e,t,{ts:n}):Ze(e,t,Ye(t,n))},getFinishedTileCount:lt,getTileCount:et,getImageUrl:function(e){return Qe[e].puzzle.info.imageUrl},setImageUrl:function(e,t){Qe[e].puzzle.info.imageUrl=t},get:function(e){return Qe[e]},getAllGames:function(){return Object.values(Qe).sort(((e,t)=>nt(e.id)===nt(t.id)?t.puzzle.data.started-e.puzzle.data.started:nt(e.id)?1:-1))},getPlayerBgColor:(e,t)=>{const n=Ke(e,t);return n?n.bgcolor:null},getPlayerColor:(e,t)=>{const n=Ke(e,t);return n?n.color:null},getPlayerName:(e,t)=>{const n=Ke(e,t);return n?n.name:null},getPlayerIndexById:qe,getPlayerIdByIndex:function(e,t){return Qe[e].players.length>t?He.decodePlayer(Qe[e].players[t]).id:null},changePlayer:it,setPlayer:Ze,setTile:function(e,t,n){Qe[e].puzzle.tiles[t]=He.encodeTile(n)},setPuzzleData:function(e,t){Qe[e].puzzle.data=t},getTableWidth:St,getTableHeight:zt,getPuzzle:e=>Qe[e].puzzle,getRng:e=>Qe[e].rng.obj,getPuzzleWidth:e=>Qe[e].puzzle.info.width,getPuzzleHeight:e=>Qe[e].puzzle.info.height,getTilesSortedByZIndex:function(e){return Qe[e].puzzle.tiles.map(He.decodeTile).sort(((e,t)=>e.z-t.z))},getFirstOwnedTile:(e,t)=>{const n=ht(e,t);return n<0?null:Qe[e].puzzle.tiles[n]},getTileDrawOffset:e=>Qe[e].puzzle.info.tileDrawOffset,getTileDrawSize:mt,getFinalTilePos:dt,getStartTs:e=>Qe[e].puzzle.data.started,getFinishTs:e=>Qe[e].puzzle.data.finished,handleInput:function(e,t,n,l){const i=Qe[e].puzzle,o=function(e,t){return t in Qe[e].evtInfos?Qe[e].evtInfos[t]:{_last_mouse:null,_last_mouse_down:null}}(e,t),a=[],s=()=>{a.push([Ne,i.data])},r=t=>{a.push([Me,He.encodeTile(st(e,t))])},d=e=>{for(const t of e)r(t)},c=()=>{a.push([Ge,He.encodePlayer(Ke(e,t))])},u=n[0];if(u===Be){const i=n[1];it(e,t,{bgcolor:i,ts:l}),c()}else if(u===Ee){const i=n[1];it(e,t,{color:i,ts:l}),c()}else if(u===Oe){const i=`${n[1]}`.substr(0,16);it(e,t,{name:i,ts:l}),c()}else if(u===ze){const i={x:n[1],y:n[2]};it(e,t,{d:1,ts:l}),c(),o._last_mouse_down=i;const a=((e,t)=>{let n=Qe[e].puzzle.info,l=Qe[e].puzzle.tiles,i=-1,o=-1;for(let a=0;ai)&&(i=e.z,o=a)}return o})(e,i);if(a>=0){let n=wt(e)+1;ot(e,{maxZ:n}),s();const l=At(e,a);bt(e,l,wt(e)),kt(e,l,t),d(l)}o._last_mouse=i}else if(u===Pe){const i=n[1],a=n[2],s={x:i,y:a};if(null===o._last_mouse_down)it(e,t,{x:i,y:a,ts:l}),c();else{let n=ht(e,t);if(n>=0){it(e,t,{x:i,y:a,ts:l}),c();const r=At(e,n);let u=ye.pointInBounds(s,ut(e))&&ye.pointInBounds(o._last_mouse_down,ut(e));for(let t of r){const n=gt(e,t);if(ye.pointInBounds(s,n)){u=!0;break}}if(u){const t=i-o._last_mouse_down.x,n=a-o._last_mouse_down.y;Ct(e,r,{x:t,y:n}),d(r)}}else it(e,t,{ts:l}),c();o._last_mouse_down=s}o._last_mouse=s}else if(u===Ie){const a={x:n[1],y:n[2]},u=0;o._last_mouse_down=null;let g=ht(e,t);if(g>=0){let n=At(e,g);kt(e,n,0),d(n);let o=ct(e,g),a=dt(e,g);if(ye.pointDistance(a,o){for(let n of t)at(e,n,{owner:-1,z:1})})(e,n),d(n);let r=Tt(e,t);0===tt(e)?r+=n.length:1===tt(e)&&(r+=1),it(e,t,{d:u,ts:l,points:r}),c(),lt(e)===et(e)&&(ot(e,{finished:l}),s())}else{const n=(e,t,n,l)=>{let i=Qe[e].puzzle.info;if(n<0)return!1;if(((e,t,n)=>{const l=rt(e,t),i=rt(e,n);return!(!l||l!==i)})(e,t,n))return!1;const o=ct(e,t),a=ye.pointAdd(ct(e,n),{x:l[0]*i.tileSize,y:l[1]*i.tileSize});if(ye.pointDistance(o,a){const l=Qe[e].puzzle.tiles,i=rt(e,t),o=rt(e,n);let a;const d=[];i&&d.push(i),o&&d.push(o),i?a=i:o?a=o:(ot(e,{maxGroup:ft(e)+1}),s(),a=ft(e));if(at(e,t,{group:a}),r(t),at(e,n,{group:a}),r(n),d.length>0)for(const s of l){const t=He.decodeTile(s);d.includes(t.group)&&(at(e,t.idx,{group:a}),r(t.idx))}})(e,t,n),i=At(e,t);const c=((e,t)=>{let n=0;for(let l of t){let t=pt(e,l);t>n&&(n=t)}return n})(e,i);return bt(e,i,c),d(i),!0}return!1};let i=!1;for(let t of At(e,g)){let l=vt(e,t);if(n(e,t,l[0],[0,1])||n(e,t,l[1],[-1,0])||n(e,t,l[2],[0,-1])||n(e,t,l[3],[1,0])){i=!0;break}}if(i&&1===tt(e)){const n=Tt(e,t)+1;it(e,t,{d:u,ts:l,points:n}),c()}else it(e,t,{d:u,ts:l}),c()}}else it(e,t,{d:u,ts:l}),c();o._last_mouse=a}else if(u===_e){const i=n[1],a=n[2];it(e,t,{x:i,y:a,ts:l}),c(),o._last_mouse={x:i,y:a}}else if(u===De){const i=n[1],a=n[2];it(e,t,{x:i,y:a,ts:l}),c(),o._last_mouse={x:i,y:a}}else it(e,t,{ts:l}),c();return function(e,t,n){Qe[e].evtInfos[t]=n}(e,t,o),a}},Pt=e({name:"new-game-dialog",components:{ResponsiveImage:L},props:{image:{type:Object,required:!0}},emits:{newGame:null,bgclick:null},data:()=>({tiles:1e3,scoreMode:Le.ANY}),methods:{onNewGameClick(){this.$emit("newGame",{tiles:this.tilesInt,image:this.image,scoreMode:this.scoreModeInt})}},computed:{canStartNewGame(){return!!(this.tilesInt&&this.image&&this.image.url&&[0,1].includes(this.scoreModeInt))},scoreModeInt(){return parseInt(`${this.scoreMode}`,10)},tilesInt(){return parseInt(`${this.tiles}`,10)}}});const _t={class:"area-image"},Dt={class:"has-image"},Bt={class:"area-settings"},Et=n("td",null,[n("label",null,"Pieces")],-1),Ot=n("td",null,[n("label",null,"Scoring: ")],-1),Ut=s(" Any (Score when pieces are connected to each other or on final location)"),Nt=n("br",null,null,-1),Mt=s(" Final (Score when pieces are put to their final location)"),Gt={class:"area-buttons"};Pt.render=function(e,l,i,s,r,d){const c=o("responsive-image");return a(),t("div",{class:"overlay new-game-dialog",onClick:l[6]||(l[6]=t=>e.$emit("bgclick"))},[n("div",{class:"overlay-content",onClick:l[5]||(l[5]=u((()=>{}),["stop"]))},[n("div",_t,[n("div",Dt,[n(c,{src:e.image.url,title:e.image.title},null,8,["src","title"])])]),n("div",Bt,[n("table",null,[n("tr",null,[Et,n("td",null,[g(n("input",{type:"text","onUpdate:modelValue":l[1]||(l[1]=t=>e.tiles=t)},null,512),[[p,e.tiles]])])]),n("tr",null,[Ot,n("td",null,[n("label",null,[g(n("input",{type:"radio","onUpdate:modelValue":l[2]||(l[2]=t=>e.scoreMode=t),value:"1"},null,512),[[y,e.scoreMode]]),Ut]),Nt,n("label",null,[g(n("input",{type:"radio","onUpdate:modelValue":l[3]||(l[3]=t=>e.scoreMode=t),value:"0"},null,512),[[y,e.scoreMode]]),Mt])])])])]),n("div",Gt,[n("button",{class:"btn",disabled:!e.canStartNewGame,onClick:l[4]||(l[4]=(...t)=>e.onNewGameClick&&e.onNewGameClick(...t))}," 🧩 Generate Puzzle ",8,["disabled"])])])])};var $t=e({components:{ImageLibrary:F,NewImageDialog:Q,EditImageDialog:ae,NewGameDialog:Pt},data:()=>({filters:{sort:"date_desc",tags:[]},images:[],tags:[],image:{id:0,filename:"",file:"",url:"",title:"",tags:[],created:0},dialog:""}),async created(){await this.loadImages()},methods:{toggleTag(e){this.filters.tags.includes(e.slug)?this.filters.tags=this.filters.tags.filter((t=>t!==e.slug)):this.filters.tags.push(e.slug),this.filtersChanged()},async loadImages(){const e=await fetch(`/api/newgame-data${He.asQueryArgs(this.filters)}`),t=await e.json();this.images=t.images,this.tags=t.tags},async filtersChanged(){await this.loadImages()},onImageClicked(e){this.image=e,this.dialog="new-game"},onImageEditClicked(e){this.image=e,this.dialog="edit-image"},async uploadImage(e){const t=new FormData;t.append("file",e.file,e.file.name),t.append("title",e.title),t.append("tags",e.tags);const n=await fetch("/api/upload",{method:"post",body:t});return await n.json()},async saveImage(e){const t=await fetch("/api/save-image",{method:"post",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({id:e.id,title:e.title,tags:e.tags})});return await t.json()},async onSaveImageClick(e){await this.saveImage(e),this.dialog="",await this.loadImages()},async postToGalleryClick(e){await this.uploadImage(e),this.dialog="",await this.loadImages()},async setupGameClick(e){const t=await this.uploadImage(e);this.loadImages(),this.image=t,this.dialog="new-game"},async onNewGame(e){const t=await fetch("/newgame",{method:"post",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(e)});if(200===t.status){const e=await t.json();this.$router.push({name:"game",params:{id:e.id}})}}}});const Rt={class:"upload-image-teaser"},Vt=n("div",{class:"hint"},"(The image you upload will be added to the public gallery.)",-1),jt={key:0},Ft=s(" Tags: "),Lt=s(" Sort by: "),Wt=n("option",{value:"date_desc"},"Newest first",-1),Ht=n("option",{value:"date_asc"},"Oldest first",-1),Qt=n("option",{value:"alpha_asc"},"A-Z",-1),Yt=n("option",{value:"alpha_desc"},"Z-A",-1);$t.render=function(e,l,s,u,p,h){const m=o("image-library"),y=o("new-image-dialog"),w=o("edit-image-dialog"),v=o("new-game-dialog");return a(),t("div",null,[n("div",Rt,[n("div",{class:"btn btn-big",onClick:l[1]||(l[1]=t=>e.dialog="new-image")},"Upload your image"),Vt]),n("div",null,[e.tags.length>0?(a(),t("label",jt,[Ft,(a(!0),t(d,null,c(e.tags,((n,l)=>(a(),t("span",{class:["bit",{on:e.filters.tags.includes(n.slug)}],key:l,onClick:t=>e.toggleTag(n)},r(n.title),11,["onClick"])))),128))])):i("",!0),n("label",null,[Lt,g(n("select",{"onUpdate:modelValue":l[2]||(l[2]=t=>e.filters.sort=t),onChange:l[3]||(l[3]=(...t)=>e.filtersChanged&&e.filtersChanged(...t))},[Wt,Ht,Qt,Yt],544),[[f,e.filters.sort]])])]),n(m,{images:e.images,onImageClicked:e.onImageClicked,onImageEditClicked:e.onImageEditClicked},null,8,["images","onImageClicked","onImageEditClicked"]),"new-image"===e.dialog?(a(),t(y,{key:0,onBgclick:l[4]||(l[4]=t=>e.dialog=""),onPostToGalleryClick:e.postToGalleryClick,onSetupGameClick:e.setupGameClick},null,8,["onPostToGalleryClick","onSetupGameClick"])):i("",!0),"edit-image"===e.dialog?(a(),t(w,{key:1,onBgclick:l[5]||(l[5]=t=>e.dialog=""),onSaveClick:e.onSaveImageClick,image:e.image},null,8,["onSaveClick","image"])):i("",!0),e.image&&"new-game"===e.dialog?(a(),t(v,{key:2,onBgclick:l[6]||(l[6]=t=>e.dialog=""),onNewGame:e.onNewGame,image:e.image},null,8,["onNewGame","image"])):i("",!0)])};var qt=e({name:"scores",props:{activePlayers:{type:Array,required:!0},idlePlayers:{type:Array,required:!0}},computed:{actives(){return this.activePlayers.sort(((e,t)=>t.points-e.points)),this.activePlayers},idles(){return this.idlePlayers.sort(((e,t)=>t.points-e.points)),this.idlePlayers}}});const Kt={class:"scores"},Zt=n("div",null,"Scores",-1),Jt=n("td",null,"⚡",-1),Xt=n("td",null,"💤",-1);qt.render=function(e,l,i,o,s,u){return a(),t("div",Kt,[Zt,n("table",null,[(a(!0),t(d,null,c(e.actives,((e,l)=>(a(),t("tr",{key:l,style:{color:e.color}},[Jt,n("td",null,r(e.name),1),n("td",null,r(e.points),1)],4)))),128)),(a(!0),t(d,null,c(e.idles,((e,l)=>(a(),t("tr",{key:l,style:{color:e.color}},[Xt,n("td",null,r(e.name),1),n("td",null,r(e.points),1)],4)))),128))])])};var en=e({name:"puzzle-status",props:{finished:{type:Boolean,required:!0},duration:{type:Number,required:!0},piecesDone:{type:Number,required:!0},piecesTotal:{type:Number,required:!0}},computed:{icon(){return this.finished?"🏁":"⏳"},durationStr(){return E(this.duration)}}});const tn={class:"timer"};en.render=function(e,l,i,o,s,d){return a(),t("div",tn,[n("div",null," 🧩 "+r(e.piecesDone)+"/"+r(e.piecesTotal),1),n("div",null,r(e.icon)+" "+r(e.durationStr),1),w(e.$slots,"default")])};var nn=e({name:"settings-overlay",emits:{bgclick:null,"update:modelValue":null},props:{modelValue:Object},created(){this.$watch("modelValue",(e=>{this.$emit("update:modelValue",e)}),{deep:!0})}});const ln=n("td",null,[n("label",null,"Background: ")],-1),on=n("td",null,[n("label",null,"Color: ")],-1),an=n("td",null,[n("label",null,"Name: ")],-1);nn.render=function(e,l,i,o,s,r){return a(),t("div",{class:"overlay transparent",onClick:l[5]||(l[5]=t=>e.$emit("bgclick"))},[n("table",{class:"overlay-content settings",onClick:l[4]||(l[4]=u((()=>{}),["stop"]))},[n("tr",null,[ln,n("td",null,[g(n("input",{type:"color","onUpdate:modelValue":l[1]||(l[1]=t=>e.modelValue.background=t)},null,512),[[p,e.modelValue.background]])])]),n("tr",null,[on,n("td",null,[g(n("input",{type:"color","onUpdate:modelValue":l[2]||(l[2]=t=>e.modelValue.color=t)},null,512),[[p,e.modelValue.color]])])]),n("tr",null,[an,n("td",null,[g(n("input",{type:"text",maxLength:"16","onUpdate:modelValue":l[3]||(l[3]=t=>e.modelValue.name=t)},null,512),[[p,e.modelValue.name]])])])])])};var sn=e({name:"preview-overlay",props:{img:String},emits:{bgclick:null},computed:{previewStyle(){return{backgroundImage:`url('${this.img}')`}}}});const rn={class:"preview"};sn.render=function(e,l,i,o,s,r){return a(),t("div",{class:"overlay",onClick:l[1]||(l[1]=t=>e.$emit("bgclick"))},[n("div",rn,[n("div",{class:"img",style:e.previewStyle},null,4)])])};const dn=Ve("Communication.js");let cn,un=e=>{},gn=e=>{};let pn=0;const hn=e=>{pn!==e&&(pn=e,gn(e))};function mn(e){if(2===pn)try{cn.send(JSON.stringify(e))}catch(t){dn.info("unable to send message.. maybe because ws is invalid?")}}let yn,fn;var wn={connect:function(e,t,n){return yn=0,fn={},hn(3),new Promise((l=>{cn=new WebSocket(e,n+"|"+t),cn.onopen=e=>{hn(2),mn([xe])},cn.onmessage=e=>{const t=JSON.parse(e.data),i=t[0];if(i===we){const e=t[1];l(e)}else{if(i!==fe)throw`[ 2021-05-09 invalid connect msgType ${i} ]`;{const e=t[1],l=t[2];if(e===n&&fn[l])return void delete fn[l];un(t)}}},cn.onerror=e=>{throw hn(1),"[ 2021-05-15 onerror ]"},cn.onclose=e=>{4e3===e.code||1001===e.code?hn(4):hn(1)}}))},connectReplay:function(e,t,n){return yn=0,fn={},hn(3),new Promise((l=>{cn=new WebSocket(e,n+"|"+t),cn.onopen=e=>{hn(2),mn([Ce])},cn.onmessage=e=>{const t=JSON.parse(e.data),n=t[0];if(n!==ve)throw`[ 2021-05-09 invalid connectReplay msgType ${n} ]`;{const e=t[1],n=t[2];l({game:e,log:n})}},cn.onerror=e=>{throw hn(1),"[ 2021-05-15 onerror ]"},cn.onclose=e=>{4e3===e.code||1001===e.code?hn(4):hn(1)}}))},disconnect:function(){cn&&cn.close(4e3),yn=0,fn={}},sendClientEvent:function(e){yn++,fn[yn]=e,mn([be,yn,fn[yn]])},onServerChange:function(e){un=e},onConnectionStateChange:function(e){gn=e},CODE_CUSTOM_DISCONNECT:4e3,CONN_STATE_NOT_CONNECTED:0,CONN_STATE_DISCONNECTED:1,CONN_STATE_CLOSED:4,CONN_STATE_CONNECTED:2,CONN_STATE_CONNECTING:3},vn=e({name:"connection-overlay",emits:{reconnect:null},props:{connectionState:Number},computed:{lostConnection(){return this.connectionState===wn.CONN_STATE_DISCONNECTED},connecting(){return this.connectionState===wn.CONN_STATE_CONNECTING},show(){return!(!this.lostConnection&&!this.connecting)}}});const bn={key:0,class:"overlay connection-lost"},xn={key:0,class:"overlay-content"},Cn=n("div",null,"⁉️ LOST CONNECTION ⁉️",-1),kn={key:1,class:"overlay-content"},An=n("div",null,"Connecting...",-1);vn.render=function(e,l,o,s,r,d){return e.show?(a(),t("div",bn,[e.lostConnection?(a(),t("div",xn,[Cn,n("span",{class:"btn",onClick:l[1]||(l[1]=t=>e.$emit("reconnect"))},"Reconnect")])):i("",!0),e.connecting?(a(),t("div",kn,[An])):i("",!0)])):i("",!0)};var Tn=e({name:"help-overlay",emits:{bgclick:null}});const Sn=n("tr",null,[n("td",null,"⬆️ Move up:"),n("td",null,[n("div",null,[n("kbd",null,"W"),s("/"),n("kbd",null,"↑"),s("/🖱️")])])],-1),zn=n("tr",null,[n("td",null,"⬇️ Move down:"),n("td",null,[n("div",null,[n("kbd",null,"S"),s("/"),n("kbd",null,"↓"),s("/🖱️")])])],-1),In=n("tr",null,[n("td",null,"⬅️ Move left:"),n("td",null,[n("div",null,[n("kbd",null,"A"),s("/"),n("kbd",null,"←"),s("/🖱️")])])],-1),Pn=n("tr",null,[n("td",null,"➡️ Move right:"),n("td",null,[n("div",null,[n("kbd",null,"D"),s("/"),n("kbd",null,"→"),s("/🖱️")])])],-1),_n=n("tr",null,[n("td"),n("td",null,[n("div",null,[s("Move faster by holding "),n("kbd",null,"Shift")])])],-1),Dn=n("tr",null,[n("td",null,"🔍+ Zoom in:"),n("td",null,[n("div",null,[n("kbd",null,"E"),s("/🖱️-Wheel")])])],-1),Bn=n("tr",null,[n("td",null,"🔍- Zoom out:"),n("td",null,[n("div",null,[n("kbd",null,"Q"),s("/🖱️-Wheel")])])],-1),En=n("tr",null,[n("td",null,"🖼️ Toggle preview:"),n("td",null,[n("div",null,[n("kbd",null,"Space")])])],-1),On=n("tr",null,[n("td",null,"🧩✔️ Toggle fixed pieces:"),n("td",null,[n("div",null,[n("kbd",null,"F")])])],-1),Un=n("tr",null,[n("td",null,"🧩❓ Toggle loose pieces:"),n("td",null,[n("div",null,[n("kbd",null,"G")])])],-1);Tn.render=function(e,l,i,o,s,r){return a(),t("div",{class:"overlay transparent",onClick:l[2]||(l[2]=t=>e.$emit("bgclick"))},[n("table",{class:"overlay-content help",onClick:l[1]||(l[1]=u((()=>{}),["stop"]))},[Sn,zn,In,Pn,_n,Dn,Bn,En,On,Un])])};var Nn=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAW0lEQVQ4je1RywrAIAxLxP//5exixRWlVgZelpOKeTQFfnDypgy3eLIkSLLL8mxGPoHsU2hPAgDHBLvRX6hZZw/fwT0BtlLSONqCbWAmEIqMZOCDDlaDR3N03gOyDCn+y4DWmAAAAABJRU5ErkJggg=="}),Mn=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAARElEQVQ4jWNgGAU0Af+hmBCbgYGBgYERhwHEAEYGBgYGJtIdiApYyLAZBVDsAqoagC1ACQJyY4ERg0GCISh6KA4DigEAou8LC+LnIJoAAAAASUVORK5CYII="}),Gn=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAcUlEQVQ4ja1TQQ7AIAgD///n7jCozA2Hbk00jbG1KIrcARszTugoBs49qioZj7r2kKACptkyAOCJsJuA+GzglwHjvMSSWFVaENWVASxh5eRLiq5fN/ASjI89VcP2K3hHpq1cEXNaMfnrL3TDZP2tDuoOA6MzCCXWr38AAAAASUVORK5CYII="}),$n=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAU0lEQVQ4jWNgoAH4D8X42HDARKlt5BoAd82AuQAOGLGIYQQUPv0wF5CiCQUge4EsQ5C9QI4BjMguwBYeBAElscCIy1ZivMKIwSDBEBQ9FCckigEAU3QOD7TGvY4AAAAASUVORK5CYII="});function Rn(){let e=0,t=0,n=1;const l=(l,i)=>{e+=l/n,t+=i/n},i=e=>{const t=n+.05*n*("in"===e?1:-1);return Math.min(Math.max(t,.1),6)},o=l=>({x:l.x/n-e,y:l.y/n-t}),a=l=>({x:(l.x+e)*n,y:(l.y+t)*n}),s=e=>({w:e.w*n,h:e.h*n});return{move:l,canZoom:e=>n!=i(e),zoom:(e,t)=>((e,t)=>{if(n==e)return!1;const i=1-n/e;return l(-t.x*i,-t.y*i),n=e,!0})(i(e),t),worldToViewport:e=>{const{x:t,y:n}=a(e);return{x:Math.round(t),y:Math.round(n)}},worldToViewportRaw:a,worldDimToViewport:e=>{const{w:t,h:n}=s(e);return{w:Math.round(t),h:Math.round(n)}},worldDimToViewportRaw:s,viewportToWorld:e=>{const{x:t,y:n}=o(e);return{x:Math.round(t),y:Math.round(n)}},viewportToWorldRaw:o}}function Vn(e=0,t=0){const n=document.createElement("canvas");return n.width=e,n.height=t,n}var jn={createCanvas:Vn,loadImageToBitmap:async function(e){return new Promise((t=>{const n=new Image;n.onload=()=>{createImageBitmap(n).then(t)},n.src=e}))},resizeBitmap:async function(e,t,n){const l=Vn(t,n);return l.getContext("2d").drawImage(e,0,0,e.width,e.height,0,0,t,n),await createImageBitmap(l)},colorizedCanvas:function(e,t,n){const l=Vn(e.width,e.height),i=l.getContext("2d");return i.save(),i.drawImage(t,0,0),i.fillStyle=n,i.globalCompositeOperation="source-in",i.fillRect(0,0,t.width,t.height),i.restore(),i.save(),i.globalCompositeOperation="destination-over",i.drawImage(e,0,0),i.restore(),l}};const Fn=Ve("Debug.js");let Ln=0,Wn=0;var Hn=e=>{Ln=performance.now(),Wn=e},Qn=e=>{const t=performance.now(),n=t-Ln;n>Wn&&Fn.log(e+": "+n),Ln=t};const Yn=Ve("PuzzleGraphics.js");function qn(e,t){const n=He.coordByTileIdx(e,t);return{x:n.x*e.tileSize,y:n.y*e.tileSize,w:e.tileSize,h:e.tileSize}}var Kn={loadPuzzleBitmaps:async function(e){const t=await jn.loadImageToBitmap(e.info.imageUrl),n=await jn.resizeBitmap(t,e.info.width,e.info.height);return await async function(e,t,n){Yn.log("start createPuzzleTileBitmaps");var l=n.tileSize,i=n.tileMarginWidth,o=n.tileDrawSize,a=l/100,s=[0,0,40,15,37,5,37,5,40,0,38,-5,38,-5,20,-20,50,-20,50,-20,80,-20,62,-5,62,-5,60,0,63,5,63,5,65,15,100,0];const r=new Array(t.length),d={};function c(e){const t=`${e.top}${e.right}${e.left}${e.bottom}`;if(d[t])return d[t];const n=new Path2D,o={x:i,y:i},r=ye.pointAdd(o,{x:l,y:0}),c=ye.pointAdd(r,{x:0,y:l}),u=ye.pointSub(c,{x:l,y:0});if(n.moveTo(o.x,o.y),0!==e.top)for(let l=0;l=0&&e&&this.explode(e),this.px+=this.vx,this.py+=this.vy}draw(e){e.beginPath(),e.arc(this.px,this.py,this.previousRadius,0,2*Math.PI,!1),this.hasExploded||(e.fillStyle=this.color,e.lineWidth=1,e.fill())}explode(e){this.hasExploded=!0;const t=3+Math.floor(3*Math.random());for(let n=0;n{this.resize()}))}setSpeedParams(){let e=0,t=0;for(;e=0;)t+=1,e+=t;Xn=t/2,el=t-Xn;const n=1/4*this.canvas.width/(t/2);Zn=-n,Jn=2*n}resize(){this.setSpeedParams()}init(){this.readyBombs=[],this.explodedBombs=[],this.particles=[];for(let e=0;e<1;e++)this.readyBombs.push(new tl(this.rng))}update(){100*Math.random()<5&&this.readyBombs.push(new tl(this.rng));const e=[];for(;this.explodedBombs.length>0;){const t=this.explodedBombs.shift();if(!t)break;t.update(),t.alive&&e.push(t)}this.explodedBombs=e;const t=[];for(;this.readyBombs.length>0;){const e=this.readyBombs.shift();if(!e)break;e.update(this.particles),e.hasExploded?this.explodedBombs.push(e):t.push(e)}this.readyBombs=t;const n=[];for(;this.particles.length>0;){const e=this.particles.shift();if(!e)break;e.update(),e.alive&&n.push(e)}this.particles=n}render(){this.ctx.beginPath(),this.ctx.fillStyle="rgba(0, 0, 0, 0.1)",this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height);for(let e=0;e{const t=e.color+" "+e.d;if(!h[t]){const n=e.d?a:s;if(e.color){const l=e.d?r:d;h[t]=await createImageBitmap(jn.colorizedCanvas(n,l,e.color))}else h[t]=n}return h[t]},y=function(e,t){return t.width=window.innerWidth,t.height=window.innerHeight,e.appendChild(t),window.addEventListener("resize",(()=>{t.width=window.innerWidth,t.height=window.innerHeight,sl=!0})),t}(i,jn.createCanvas()),f={log:[],logIdx:0,speeds:[.5,1,2,5,10,20,50],speedIdx:1,paused:!1,lastRealTs:0,lastGameTs:0,gameStartTs:0};wn.onConnectionStateChange((e=>{o.setConnectionState(e)}));let w=()=>0;const v=async()=>{if("play"===l){const l=await wn.connect(n,e,t),i=He.decodeGame(l);It.setGame(i.id,i),w=()=>D()}else{if("replay"!==l)throw"[ 2020-12-22 MODE invalid, must be play|replay ]";{const l=await wn.connectReplay(n,e,t),i=He.decodeGame(l.game);It.setGame(i.id,i),f.log=l.log,f.lastRealTs=D(),f.gameStartTs=parseInt(f.log[0][f.log[0].length-2],10),f.lastGameTs=f.gameStartTs,w=()=>f.lastGameTs}}sl=!0};await v();const b=It.getTileDrawOffset(e),x=It.getTileDrawSize(e),C=It.getPuzzleWidth(e),k=It.getPuzzleHeight(e),A=It.getTableWidth(e),T=It.getTableHeight(e),S={x:(A-C)/2,y:(T-k)/2},z={w:C,h:k},I={w:x,h:x},P=await Kn.loadPuzzleBitmaps(It.getPuzzle(e)),_=new ll(y,It.getRng(e));_.init();const B=y.getContext("2d");y.classList.add("loaded");const E=Rn();E.move(-(A-y.width)/2,-(T-y.height)/2);const O=function(e,t,n){let l=[],i=!0,o=!1,a=!1,s=!1,r=!1,d=!1,c=!1,u=!1;const g=(e,t)=>{const l=n.viewportToWorld({x:e,y:t});return[l.x,l.y]},p=e=>g(e.offsetX,e.offsetY),h=()=>g(e.width/2,e.height/2),m=(e,t)=>{i&&("Shift"===t.key?u=e:"ArrowUp"===t.key||"w"===t.key||"W"===t.key?s=e:"ArrowDown"===t.key||"s"===t.key||"S"===t.key?r=e:"ArrowLeft"===t.key||"a"===t.key||"A"===t.key?o=e:"ArrowRight"===t.key||"d"===t.key||"D"===t.key?a=e:"q"===t.key?c=e:"e"===t.key&&(d=e))};e.addEventListener("mousedown",(e=>{0===e.button&&y([ze,...p(e)])})),e.addEventListener("mouseup",(e=>{0===e.button&&y([Ie,...p(e)])})),e.addEventListener("mousemove",(e=>{y([Pe,...p(e)])})),e.addEventListener("wheel",(e=>{if(n.canZoom(e.deltaY<0?"in":"out")){const t=e.deltaY<0?_e:De;y([t,...p(e)])}})),t.addEventListener("keydown",(e=>m(!0,e))),t.addEventListener("keyup",(e=>m(!1,e))),t.addEventListener("keypress",(e=>{i&&(" "===e.key&&y([Ue]),"F"!==e.key&&"f"!==e.key||(ol=!ol,sl=!0),"G"!==e.key&&"g"!==e.key||(al=!al,sl=!0))}));const y=e=>{l.push(e)};return{addEvent:y,consumeAll:()=>{if(0===l.length)return[];const e=l.slice();return l=[],e},createKeyEvents:()=>{const e=u?20:10,t=(o?e:0)-(a?e:0),l=(s?e:0)-(r?e:0);0===t&&0===l||y([Se,t,l]),d&&c||(d?n.canZoom("in")&&y([_e,...h()]):c&&n.canZoom("out")&&y([De,...h()]))},setHotkeys:e=>{i=e}}}(y,window,E),U=It.getImageUrl(e),N=()=>{const t=It.getStartTs(e),n=It.getFinishTs(e),l=w();o.setFinished(!!n),o.setDuration((n||l)-t)};N(),o.setPiecesDone(It.getFinishedTileCount(e)),o.setPiecesTotal(It.getTileCount(e));const M=w();o.setActivePlayers(It.getActivePlayers(e,M)),o.setIdlePlayers(It.getIdlePlayers(e,M));const G=!!It.getFinishTs(e);let $=G;const R=()=>$&&!G,V=()=>It.getPlayerBgColor(e,t)||localStorage.getItem("bg_color")||"#222222",j=()=>It.getPlayerColor(e,t)||localStorage.getItem("player_color")||"#ffffff";let F="",L="",W=!1;const H=e=>{W=e;const[t,n]=e?[F,"grab"]:[L,"default"];y.style.cursor=`url('${t}') ${u} ${p}, ${n}`},Q=e=>{F=jn.colorizedCanvas(a,r,e).toDataURL(),L=jn.colorizedCanvas(s,d,e).toDataURL(),H(W)};Q(j());const Y=()=>{o.setReplaySpeed&&o.setReplaySpeed(f.speeds[f.speedIdx]),o.setReplayPaused&&o.setReplayPaused(f.paused)};if("play"===l?setInterval(N,1e3):"replay"===l&&Y(),"play"===l)wn.onServerChange((n=>{n[0],n[1],n[2];const l=n[3];for(const[i,o]of l)switch(i){case Ge:{const n=He.decodePlayer(o);n.id!==t&&(It.setPlayer(e,n.id,n),sl=!0)}break;case Me:{const t=He.decodeTile(o);It.setTile(e,t.idx,t),sl=!0}break;case Ne:It.setPuzzleData(e,o),sl=!0}$=!!It.getFinishTs(e)}));else if("replay"===l){let t=setInterval((()=>{const n=D();if(f.paused)return void(f.lastRealTs=n);const l=(n-f.lastRealTs)*f.speeds[f.speedIdx],i=f.lastGameTs+l;for(;;){if(f.paused)break;const n=f.logIdx+1;if(n>=f.log.length){clearInterval(t);break}const l=f.log[n],o=f.gameStartTs+l[l.length-1];if(o>i)break;const a=l.slice();if(a[0]===ke){const t=a[1];It.addPlayer(e,t,o),sl=!0}else if(a[0]===Ae){const t=It.getPlayerIdByIndex(e,a[1]);if(!t)throw"[ 2021-05-17 player not found (update player) ]";It.addPlayer(e,t,o),sl=!0}else if(a[0]===Te){const t=It.getPlayerIdByIndex(e,a[1]);if(!t)throw"[ 2021-05-17 player not found (handle input) ]";const n=a[2];It.handleInput(e,t,n,o),sl=!0}f.logIdx=n}f.lastRealTs=n,f.lastGameTs=i,N()}),50)}let q=null;return(e=>{const t=e.fps||60,n=e.slow||1,l=e.update,i=e.render,o=window.requestAnimationFrame,a=1/t,s=n*a;let r,d=0,c=window.performance.now();const u=()=>{for(r=window.performance.now(),d+=Math.min(1,(r-c)/1e3);d>s;)d-=s,l(a);i(d/n),c=r,o(u)};o(u)})({update:()=>{O.createKeyEvents();for(const n of O.consumeAll())if("play"===l){const l=n[0];if(l===Se){const e=n[1],t=n[2];sl=!0,E.move(e,t)}else if(l===Pe){if(q&&!It.getFirstOwnedTile(e,t)){const e={x:n[1],y:n[2]},t=E.worldToViewport(e),l=Math.round(t.x-q.x),i=Math.round(t.y-q.y);sl=!0,E.move(l,i),q=t}}else if(l===Ee)Q(n[1]);else if(l===ze){const e={x:n[1],y:n[2]};q=E.worldToViewport(e),H(!0)}else if(l===Ie)q=null,H(!1);else if(l===_e){const e={x:n[1],y:n[2]};sl=!0,E.zoom("in",E.worldToViewport(e))}else if(l===De){const e={x:n[1],y:n[2]};sl=!0,E.zoom("out",E.worldToViewport(e))}else l===Ue&&o.togglePreview();const i=w();It.handleInput(e,t,n,i).length>0&&(sl=!0),wn.sendClientEvent(n)}else if("replay"===l){const e=n[0];if(e===Se){const e=n[1],t=n[2];sl=!0,E.move(e,t)}else if(e===Pe){if(q){const e={x:n[1],y:n[2]},t=E.worldToViewport(e),l=Math.round(t.x-q.x),i=Math.round(t.y-q.y);sl=!0,E.move(l,i),q=t}}else if(e===ze){const e={x:n[1],y:n[2]};q=E.worldToViewport(e)}else if(e===Ie)q=null;else if(e===_e){const e={x:n[1],y:n[2]};sl=!0,E.zoom("in",E.worldToViewport(e))}else if(e===De){const e={x:n[1],y:n[2]};sl=!0,E.zoom("out",E.worldToViewport(e))}else e===Ue&&o.togglePreview()}$=!!It.getFinishTs(e),R()&&(_.update(),sl=!0)},render:async()=>{if(!sl)return;const n=w();let i,a,s;window.DEBUG&&Hn(0),B.fillStyle=V(),B.fillRect(0,0,y.width,y.height),window.DEBUG&&Qn("clear done"),i=E.worldToViewportRaw(S),a=E.worldDimToViewportRaw(z),B.fillStyle="rgba(255, 255, 255, .3)",B.fillRect(i.x,i.y,a.w,a.h),window.DEBUG&&Qn("board done");const r=It.getTilesSortedByZIndex(e);window.DEBUG&&Qn("get tiles done"),a=E.worldDimToViewportRaw(I);for(const e of r)(-1===e.owner?ol:al)&&(s=P[e.idx],i=E.worldToViewportRaw({x:b+e.pos.x,y:b+e.pos.y}),B.drawImage(s,0,0,s.width,s.height,i.x,i.y,a.w,a.h));window.DEBUG&&Qn("tiles done");const d=[];for(const o of It.getActivePlayers(e,n))c=o,("replay"===l||c.id!==t)&&(s=await m(o),i=E.worldToViewport(o),B.drawImage(s,i.x-u,i.y-p),d.push([`${o.name} (${o.points})`,i.x,i.y+g]));var c;B.fillStyle="white",B.textAlign="center";for(const[e,t,l]of d)B.fillText(e,t,l);window.DEBUG&&Qn("players done"),o.setActivePlayers(It.getActivePlayers(e,n)),o.setIdlePlayers(It.getIdlePlayers(e,n)),o.setPiecesDone(It.getFinishedTileCount(e)),window.DEBUG&&Qn("HUD done"),R()&&_.render(),sl=!1}}),{setHotkeys:e=>{O.setHotkeys(e)},onBgChange:e=>{localStorage.setItem("bg_color",e),O.addEvent([Be,e])},onColorChange:e=>{localStorage.setItem("player_color",e),O.addEvent([Ee,e])},onNameChange:e=>{localStorage.setItem("player_name",e),O.addEvent([Oe,e])},replayOnSpeedUp:()=>{f.speedIdx+1{f.speedIdx>=1&&(f.speedIdx--,Y())},replayOnPauseToggle:()=>{f.paused=!f.paused,Y()},previewImageUrl:U,player:{background:V(),color:j(),name:It.getPlayerName(e,t)||localStorage.getItem("player_name")||"anon"},disconnect:wn.disconnect,connect:v}}var dl=e({name:"game",components:{PuzzleStatus:en,Scores:qt,SettingsOverlay:nn,PreviewOverlay:sn,ConnectionOverlay:vn,HelpOverlay:Tn},data:()=>({activePlayers:[],idlePlayers:[],finished:!1,duration:0,piecesDone:0,piecesTotal:0,overlay:"",connectionState:0,g:{player:{background:"",color:"",name:""},previewImageUrl:"",setHotkeys:e=>{},onBgChange:e=>{},onColorChange:e=>{},onNameChange:e=>{},disconnect:()=>{},connect:()=>{}}}),async mounted(){this.$route.params.id&&(this.$watch((()=>this.g.player.background),(e=>{this.g.onBgChange(e)})),this.$watch((()=>this.g.player.color),(e=>{this.g.onColorChange(e)})),this.$watch((()=>this.g.player.name),(e=>{this.g.onNameChange(e)})),this.g=await rl(`${this.$route.params.id}`,this.$clientId,this.$config.WS_ADDRESS,"play",this.$el,{setActivePlayers:e=>{this.activePlayers=e},setIdlePlayers:e=>{this.idlePlayers=e},setFinished:e=>{this.finished=e},setDuration:e=>{this.duration=e},setPiecesDone:e=>{this.piecesDone=e},setPiecesTotal:e=>{this.piecesTotal=e},setConnectionState:e=>{this.connectionState=e},togglePreview:()=>{this.toggle("preview",!1)}}))},unmounted(){this.g.disconnect()},methods:{reconnect(){this.g.connect()},toggle(e,t){""===this.overlay?(this.overlay=e,t&&this.g.setHotkeys(!1)):(this.overlay="",t&&this.g.setHotkeys(!0))}}});const cl={id:"game"},ul={class:"menu"},gl={class:"tabs"},pl=s("🧩 Puzzles");dl.render=function(e,i,s,r,d,c){const u=o("settings-overlay"),p=o("preview-overlay"),h=o("help-overlay"),m=o("connection-overlay"),y=o("puzzle-status"),f=o("router-link"),w=o("scores");return a(),t("div",cl,[g(n(u,{onBgclick:i[1]||(i[1]=t=>e.toggle("settings",!0)),modelValue:e.g.player,"onUpdate:modelValue":i[2]||(i[2]=t=>e.g.player=t)},null,8,["modelValue"]),[[v,"settings"===e.overlay]]),g(n(p,{onBgclick:i[3]||(i[3]=t=>e.toggle("preview",!1)),img:e.g.previewImageUrl},null,8,["img"]),[[v,"preview"===e.overlay]]),g(n(h,{onBgclick:i[4]||(i[4]=t=>e.toggle("help",!0))},null,512),[[v,"help"===e.overlay]]),n(m,{connectionState:e.connectionState,onReconnect:e.reconnect},null,8,["connectionState","onReconnect"]),n(y,{finished:e.finished,duration:e.duration,piecesDone:e.piecesDone,piecesTotal:e.piecesTotal},null,8,["finished","duration","piecesDone","piecesTotal"]),n("div",ul,[n("div",gl,[n(f,{class:"opener",to:{name:"index"},target:"_blank"},{default:l((()=>[pl])),_:1}),n("div",{class:"opener",onClick:i[5]||(i[5]=t=>e.toggle("preview",!1))},"🖼️ Preview"),n("div",{class:"opener",onClick:i[6]||(i[6]=t=>e.toggle("settings",!0))},"🛠️ Settings"),n("div",{class:"opener",onClick:i[7]||(i[7]=t=>e.toggle("help",!0))},"ℹ️ Help")])]),n(w,{activePlayers:e.activePlayers,idlePlayers:e.idlePlayers},null,8,["activePlayers","idlePlayers"])])};var hl=e({name:"replay",components:{PuzzleStatus:en,Scores:qt,SettingsOverlay:nn,PreviewOverlay:sn,HelpOverlay:Tn},data:()=>({activePlayers:[],idlePlayers:[],finished:!1,duration:0,piecesDone:0,piecesTotal:0,overlay:"",connectionState:0,g:{player:{background:"",color:"",name:""},previewImageUrl:"",setHotkeys:e=>{},onBgChange:e=>{},onColorChange:e=>{},onNameChange:e=>{},replayOnSpeedUp:()=>{},replayOnSpeedDown:()=>{},replayOnPauseToggle:()=>{},disconnect:()=>{}},replay:{speed:1,paused:!1}}),async mounted(){this.$route.params.id&&(this.$watch((()=>this.g.player.background),(e=>{this.g.onBgChange(e)})),this.$watch((()=>this.g.player.color),(e=>{this.g.onColorChange(e)})),this.$watch((()=>this.g.player.name),(e=>{this.g.onNameChange(e)})),this.g=await rl(`${this.$route.params.id}`,this.$clientId,this.$config.WS_ADDRESS,"replay",this.$el,{setActivePlayers:e=>{this.activePlayers=e},setIdlePlayers:e=>{this.idlePlayers=e},setFinished:e=>{this.finished=e},setDuration:e=>{this.duration=e},setPiecesDone:e=>{this.piecesDone=e},setPiecesTotal:e=>{this.piecesTotal=e},togglePreview:()=>{this.toggle("preview",!1)},setConnectionState:e=>{this.connectionState=e},setReplaySpeed:e=>{this.replay.speed=e},setReplayPaused:e=>{this.replay.paused=e}}))},unmounted(){this.g.disconnect()},methods:{toggle(e,t){""===this.overlay?(this.overlay=e,t&&this.g.setHotkeys(!1)):(this.overlay="",t&&this.g.setHotkeys(!0))}},computed:{replayText(){return"Replay-Speed: "+this.replay.speed+"x"+(this.replay.paused?" Paused":"")}}});const ml={id:"replay"},yl={class:"menu"},fl={class:"tabs"},wl=s("🧩 Puzzles");hl.render=function(e,i,s,d,c,u){const p=o("settings-overlay"),h=o("preview-overlay"),m=o("help-overlay"),y=o("puzzle-status"),f=o("router-link"),w=o("scores");return a(),t("div",ml,[g(n(p,{onBgclick:i[1]||(i[1]=t=>e.toggle("settings",!0)),modelValue:e.g.player,"onUpdate:modelValue":i[2]||(i[2]=t=>e.g.player=t)},null,8,["modelValue"]),[[v,"settings"===e.overlay]]),g(n(h,{onBgclick:i[3]||(i[3]=t=>e.toggle("preview",!1)),img:e.g.previewImageUrl},null,8,["img"]),[[v,"preview"===e.overlay]]),g(n(m,{onBgclick:i[4]||(i[4]=t=>e.toggle("help",!0))},null,512),[[v,"help"===e.overlay]]),n(y,{finished:e.finished,duration:e.duration,piecesDone:e.piecesDone,piecesTotal:e.piecesTotal},{default:l((()=>[n("div",null,[n("div",null,r(e.replayText),1),n("button",{class:"btn",onClick:i[5]||(i[5]=t=>e.g.replayOnSpeedUp())},"⏫"),n("button",{class:"btn",onClick:i[6]||(i[6]=t=>e.g.replayOnSpeedDown())},"⏬"),n("button",{class:"btn",onClick:i[7]||(i[7]=t=>e.g.replayOnPauseToggle())},"⏸️")])])),_:1},8,["finished","duration","piecesDone","piecesTotal"]),n("div",yl,[n("div",fl,[n(f,{class:"opener",to:{name:"index"},target:"_blank"},{default:l((()=>[wl])),_:1}),n("div",{class:"opener",onClick:i[8]||(i[8]=t=>e.toggle("preview",!1))},"🖼️ Preview"),n("div",{class:"opener",onClick:i[9]||(i[9]=t=>e.toggle("settings",!0))},"🛠️ Settings"),n("div",{class:"opener",onClick:i[10]||(i[10]=t=>e.toggle("help",!0))},"ℹ️ Help")])]),n(w,{activePlayers:e.activePlayers,idlePlayers:e.idlePlayers},null,8,["activePlayers","idlePlayers"])])},(async()=>{const e=await fetch("/api/conf"),t=await e.json();const n=b({history:x(),routes:[{name:"index",path:"/",component:$},{name:"new-game",path:"/new-game",component:$t},{name:"game",path:"/g/:id",component:dl},{name:"replay",path:"/replay/:id",component:hl}]});n.beforeEach(((e,t)=>{t.name&&document.documentElement.classList.remove(`view-${String(t.name)}`),document.documentElement.classList.add(`view-${String(e.name)}`)}));const l=C(k);l.config.globalProperties.$config=t,l.config.globalProperties.$clientId=function(){let e=localStorage.getItem("ID");return e||(e=He.uniqId(),localStorage.setItem("ID",e)),e}(),l.use(n),l.mount("#app")})(); diff --git a/build/public/assets/index.63ff8630.js b/build/public/assets/index.63ff8630.js new file mode 100644 index 0000000..bb8b554 --- /dev/null +++ b/build/public/assets/index.63ff8630.js @@ -0,0 +1 @@ +import{d as e,c as t,a as n,w as o,b as l,r as a,o as s,e as i,t as r,F as d,f as c,g as u,h as p,v as g,i as h,j as m,p as y,k as f,l as v,m as w,n as b,q as C,s as x,u as k,x as P,y as A}from"./vendor.684f7bc8.js";var S=e({name:"app",computed:{showNav(){return!["game","replay"].includes(String(this.$route.name))}}});const z={id:"app"},T={key:0,class:"nav"},I=i("Games overview"),E=i("New game");S.render=function(e,i,r,d,c,u){const p=a("router-link"),g=a("router-view");return s(),t("div",z,[e.showNav?(s(),t("ul",T,[n("li",null,[n(p,{class:"btn",to:{name:"index"}},{default:o((()=>[I])),_:1})]),n("li",null,[n(p,{class:"btn",to:{name:"new-game"}},{default:o((()=>[E])),_:1})])])):l("",!0),n(g)])};let M="",D="";const N=async(e,t,n)=>new Promise(((o,l)=>{const a=new window.XMLHttpRequest;a.open(e,t,!0),a.withCredentials=!0;for(const e in n.headers||{})a.setRequestHeader(e,n.headers[e]);a.setRequestHeader("Client-Id",M),a.setRequestHeader("Client-Secret",D),a.addEventListener("load",(function(e){o({status:this.status,text:this.responseText,json:async()=>JSON.parse(this.responseText)})})),a.addEventListener("error",(function(e){l(new Error("xhr error"))})),a.upload&&n.onUploadProgress&&a.upload.addEventListener("progress",(function(e){n.onUploadProgress&&n.onUploadProgress(e)})),a.send(n.body||null)}));var _=(e,t)=>N("get",e,t),V=(e,t)=>N("post",e,t),O=e=>{M=e},B=e=>{D=e};const U=864e5,R=e=>{const t=Math.floor(e/U);e%=U;const n=Math.floor(e/36e5);e%=36e5;const o=Math.floor(e/6e4);e%=6e4;return`${t}d ${n}h ${o}m ${Math.floor(e/1e3)}s`};var $=1,G=1e3,L=()=>{const e=new Date;return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds(),e.getUTCMilliseconds())},F=(e,t)=>R(t-e),j=R,W=e({name:"game-teaser",props:{game:{type:Object,required:!0}},computed:{style(){return{"background-image":`url("${this.game.imageUrl.replace("uploads/","uploads/r/")+"-375x210.webp"}")`}}},methods:{time(e,t){const n=t?"🏁":"⏳",o=e,l=t||L();return`${n} ${F(o,l)}`}}});const H={class:"game-info-text"},K=n("br",null,null,-1),q=n("br",null,null,-1),Y=n("br",null,null,-1),Q=i(" ↪️ Watch replay ");W.render=function(e,d,c,u,p,g){const h=a("router-link");return s(),t("div",{class:"game-teaser",style:e.style},[n(h,{class:"game-info",to:{name:"game",params:{id:e.game.id}}},{default:o((()=>[n("span",H,[i(" 🧩 "+r(e.game.tilesFinished)+"/"+r(e.game.tilesTotal),1),K,i(" 👥 "+r(e.game.players),1),q,i(" "+r(e.time(e.game.started,e.game.finished)),1),Y])])),_:1},8,["to"]),e.game.hasReplay?(s(),t(h,{key:0,class:"game-replay",to:{name:"replay",params:{id:e.game.id}}},{default:o((()=>[Q])),_:1},8,["to"])):l("",!0)],4)};var Z=e({components:{GameTeaser:W},data:()=>({gamesRunning:[],gamesFinished:[]}),async created(){const e=await _("/api/index-data",{}),t=await e.json();this.gamesRunning=t.gamesRunning,this.gamesFinished=t.gamesFinished}});const X=n("h1",null,"Running games",-1),J=n("h1",null,"Finished games",-1);Z.render=function(e,o,l,i,r,u){const p=a("game-teaser");return s(),t("div",null,[X,(s(!0),t(d,null,c(e.gamesRunning,((e,o)=>(s(),t("div",{class:"game-teaser-wrap",key:o},[n(p,{game:e},null,8,["game"])])))),128)),J,(s(!0),t(d,null,c(e.gamesFinished,((e,o)=>(s(),t("div",{class:"game-teaser-wrap",key:o},[n(p,{game:e},null,8,["game"])])))),128))])};var ee=e({name:"image-teaser",props:{image:{type:Object,required:!0}},computed:{style(){return{backgroundImage:`url("${this.image.url.replace("uploads/","uploads/r/")+"-150x100.webp"}")`}},canEdit(){return!!this.$me.id&&this.$me.id===this.image.uploaderUserId}},emits:{click:null,editClick:null},methods:{onClick(){this.$emit("click")},onEditClick(){this.$emit("editClick")}}});ee.render=function(e,n,o,a,i,r){return s(),t("div",{class:"imageteaser",style:e.style,onClick:n[2]||(n[2]=(...t)=>e.onClick&&e.onClick(...t))},[e.canEdit?(s(),t("div",{key:0,class:"btn edit",onClick:n[1]||(n[1]=u(((...t)=>e.onEditClick&&e.onEditClick(...t)),["stop"]))},"✏️")):l("",!0)],4)};var te=e({name:"image-library",components:{ImageTeaser:ee},props:{images:{type:Array,required:!0}},emits:{imageClicked:null,imageEditClicked:null},methods:{imageClicked(e){this.$emit("imageClicked",e)},imageEditClicked(e){this.$emit("imageEditClicked",e)}}});te.render=function(e,n,o,l,i,r){const u=a("image-teaser");return s(),t("div",null,[(s(!0),t(d,null,c(e.images,((n,o)=>(s(),t(u,{image:n,onClick:t=>e.imageClicked(n),onEditClick:t=>e.imageEditClicked(n),key:o},null,8,["image","onClick","onEditClick"])))),128))])};class ne{constructor(e){this.rand_high=e||3735929054,this.rand_low=1231121986^e}random(e,t){this.rand_high=(this.rand_high<<16)+(this.rand_high>>16)+this.rand_low&4294967295,this.rand_low=this.rand_low+this.rand_high&4294967295;return e+(this.rand_high>>>0)/4294967295*(t-e+1)|0}choice(e){return e[this.random(0,e.length-1)]}shuffle(e){const t=e.slice();for(let n=0;n<=t.length-2;n++){const e=this.random(n,t.length-1),o=t[n];t[n]=t[e],t[e]=o}return t}static serialize(e){return{rand_high:e.rand_high,rand_low:e.rand_low}}static unserialize(e){const t=new ne(0);return t.rand_high=e.rand_high,t.rand_low=e.rand_low,t}}const oe=(e,t)=>{const n=`${e}`;return n.length>=t.length?n:t.substr(0,t.length-n.length)+n},le=(...e)=>{const t=t=>(...n)=>{const o=new Date,l=oe(o.getHours(),"00"),a=oe(o.getMinutes(),"00"),s=oe(o.getSeconds(),"00");console[t](`${l}:${a}:${s}`,...e,...n)};return{log:t("log"),error:t("error"),info:t("info")}};var ae={hash:e=>{let t=0;for(let n=0;n{let t=e.toLowerCase();return t=t.replace(/[^a-z0-9]+/g,"-"),t=t.replace(/^-|-$/,""),t},uniqId:()=>Date.now().toString(36)+Math.random().toString(36).substring(2),encodeShape:function(e){return e.top+1<<0|e.right+1<<2|e.bottom+1<<4|e.left+1<<6},decodeShape:function(e){return{top:(e>>0&3)-1,right:(e>>2&3)-1,bottom:(e>>4&3)-1,left:(e>>6&3)-1}},encodePiece:function(e){return[e.idx,e.pos.x,e.pos.y,e.z,e.owner,e.group]},decodePiece:function(e){return{idx:e[0],pos:{x:e[1],y:e[2]},z:e[3],owner:e[4],group:e[5]}},encodePlayer:function(e){return[e.id,e.x,e.y,e.d,e.name,e.color,e.bgcolor,e.points,e.ts]},decodePlayer:function(e){return{id:e[0],x:e[1],y:e[2],d:e[3],name:e[4],color:e[5],bgcolor:e[6],points:e[7],ts:e[8]}},encodeGame:function(e){return[e.id,e.rng.type||"",ne.serialize(e.rng.obj),e.puzzle,e.players,e.evtInfos,e.scoreMode,e.shapeMode,e.snapMode,e.creatorUserId]},decodeGame:function(e){return{id:e[0],rng:{type:e[1],obj:ne.unserialize(e[2])},puzzle:e[3],players:e[4],evtInfos:e[5],scoreMode:e[6],shapeMode:e[7],snapMode:e[8],creatorUserId:e[9]}},coordByPieceIdx:function(e,t){const n=e.width/e.tileSize;return{x:t%n,y:Math.floor(t/n)}},asQueryArgs:function(e){const t=[];for(const n in e){const o=[n,e[n]].map(encodeURIComponent);t.push(o.join("="))}return 0===t.length?"":`?${t.join("&")}`}};const se={name:"responsive-image",props:{src:String,title:{type:String,default:""},height:{type:String,default:"100%"},width:{type:String,default:"100%"}},computed:{style(){return{display:"inline-block",verticalAlign:"text-bottom",backgroundImage:`url('${this.src}')`,backgroundRepeat:"no-repeat",backgroundSize:"contain",backgroundPosition:"center",width:this.width,height:this.height}}}};se.render=function(e,n,o,l,a,i){return s(),t("div",{style:i.style,title:o.title},null,12,["title"])};var ie=e({name:"tags-input",props:{modelValue:{type:Array,required:!0},autocompleteTags:{type:Function}},emits:{"update:modelValue":null},data:()=>({input:"",values:[],autocomplete:{idx:-1,values:[]}}),created(){this.values=this.modelValue},methods:{onKeyUp(e){return"ArrowDown"===e.code&&this.autocomplete.values.length>0?(this.autocomplete.idx0?(this.autocomplete.idx>0&&this.autocomplete.idx--,e.stopPropagation(),!1):","===e.key?(this.add(),e.stopPropagation(),!1):void(this.input&&this.autocompleteTags?(this.autocomplete.values=this.autocompleteTags(this.input,this.values),this.autocomplete.idx=-1):(this.autocomplete.values=[],this.autocomplete.idx=-1))},addVal(e){const t=e.replace(/,/g,"").trim();t&&(this.values.includes(t)||this.values.push(t),this.input="",this.autocomplete.values=[],this.autocomplete.idx=-1,this.$emit("update:modelValue",this.values),this.$refs.input.focus())},add(){const e=this.autocomplete.idx>=0?this.autocomplete.values[this.autocomplete.idx]:this.input;this.addVal(e)},rm(e){this.values=this.values.filter((t=>t!==e)),this.$emit("update:modelValue",this.values)}}});const re=m();y("data-v-a4fa5e7e");const de={key:0,class:"autocomplete"};f();const ce=re(((e,o,a,i,u,m)=>(s(),t("div",null,[p(n("input",{ref:"input",class:"input",type:"text","onUpdate:modelValue":o[1]||(o[1]=t=>e.input=t),placeholder:"Plants, People",onChange:o[2]||(o[2]=(...t)=>e.onChange&&e.onChange(...t)),onKeydown:o[3]||(o[3]=h(((...t)=>e.add&&e.add(...t)),["enter"])),onKeyup:o[4]||(o[4]=(...t)=>e.onKeyUp&&e.onKeyUp(...t))},null,544),[[g,e.input]]),e.autocomplete.values?(s(),t("div",de,[n("ul",null,[(s(!0),t(d,null,c(e.autocomplete.values,((n,o)=>(s(),t("li",{key:o,class:{active:o===e.autocomplete.idx},onClick:t=>e.addVal(n)},r(n),11,["onClick"])))),128))])])):l("",!0),(s(!0),t(d,null,c(e.values,((n,o)=>(s(),t("span",{key:o,class:"bit",onClick:t=>e.rm(n)},r(n)+" ✖",9,["onClick"])))),128))]))));ie.render=ce,ie.__scopeId="data-v-a4fa5e7e";const ue=le("NewImageDialog.vue");var pe=e({name:"new-image-dialog",components:{ResponsiveImage:se,TagsInput:ie},props:{autocompleteTags:{type:Function},uploadProgress:{type:Number},uploading:{type:String}},emits:{bgclick:null,setupGameClick:null,postToGalleryClick:null},data:()=>({previewUrl:"",file:null,title:"",tags:[],droppable:!1}),computed:{uploadProgressPercent(){return this.uploadProgress?Math.round(100*this.uploadProgress):0},canPostToGallery(){return!this.uploading&&!(!this.previewUrl||!this.file)},canSetupGameClick(){return!this.uploading&&!(!this.previewUrl||!this.file)}},methods:{imageFromDragEvt(e){var t;const n=null==(t=e.dataTransfer)?void 0:t.items;if(!n||0===n.length)return null;const o=n[0];return o.type.startsWith("image/")?o:null},onFileSelect(e){const t=e.target;if(!t.files)return;const n=t.files[0];n&&this.preview(n)},preview(e){const t=new FileReader;t.readAsDataURL(e),t.onload=t=>{this.previewUrl=t.target.result,this.file=e}},postToGallery(){this.$emit("postToGalleryClick",{file:this.file,title:this.title,tags:this.tags})},setupGameClick(){this.$emit("setupGameClick",{file:this.file,title:this.title,tags:this.tags})},onDrop(e){this.droppable=!1;const t=this.imageFromDragEvt(e);if(!t)return!1;const n=t.getAsFile();return!!n&&(this.file=n,this.preview(n),e.preventDefault(),!1)},onDragover(e){return!!this.imageFromDragEvt(e)&&(this.droppable=!0,e.preventDefault(),!1)},onDragleave(){ue.info("onDragleave"),this.droppable=!1}}});const ge=n("div",{class:"drop-target"},null,-1),he={key:0,class:"has-image"},me={key:1},ye={class:"upload"},fe=n("span",{class:"btn"},"Upload File",-1),ve={class:"area-settings"},we=n("td",null,[n("label",null,"Title")],-1),be=n("tr",null,[n("td",{colspan:"2"},[n("div",{class:"hint"},"Feel free to leave a credit to the artist/photographer in the title :)")])],-1),Ce=n("td",null,[n("label",null,"Tags")],-1),xe={class:"area-buttons"},ke=i("🖼️ Post to gallery"),Pe=i("🧩 Post to gallery "),Ae=n("br",null,null,-1),Se=i(" + set up game");pe.render=function(e,o,l,c,h,m){const y=a("responsive-image"),f=a("tags-input");return s(),t("div",{class:"overlay new-image-dialog",onClick:o[11]||(o[11]=t=>e.$emit("bgclick"))},[n("div",{class:"overlay-content",onClick:o[10]||(o[10]=u((()=>{}),["stop"]))},[n("div",{class:["area-image",{"has-image":!!e.previewUrl,"no-image":!e.previewUrl,droppable:e.droppable}],onDrop:o[3]||(o[3]=(...t)=>e.onDrop&&e.onDrop(...t)),onDragover:o[4]||(o[4]=(...t)=>e.onDragover&&e.onDragover(...t)),onDragleave:o[5]||(o[5]=(...t)=>e.onDragleave&&e.onDragleave(...t))},[ge,e.previewUrl?(s(),t("div",he,[n("span",{class:"remove btn",onClick:o[1]||(o[1]=t=>e.previewUrl="")},"X"),n(y,{src:e.previewUrl},null,8,["src"])])):(s(),t("div",me,[n("label",ye,[n("input",{type:"file",style:{display:"none"},onChange:o[2]||(o[2]=(...t)=>e.onFileSelect&&e.onFileSelect(...t)),accept:"image/*"},null,32),fe])]))],34),n("div",ve,[n("table",null,[n("tr",null,[we,n("td",null,[p(n("input",{type:"text","onUpdate:modelValue":o[6]||(o[6]=t=>e.title=t),placeholder:"Flower by @artist"},null,512),[[g,e.title]])])]),be,n("tr",null,[Ce,n("td",null,[n(f,{modelValue:e.tags,"onUpdate:modelValue":o[7]||(o[7]=t=>e.tags=t),autocompleteTags:e.autocompleteTags},null,8,["modelValue","autocompleteTags"])])])])]),n("div",xe,[n("button",{class:"btn",disabled:!e.canPostToGallery,onClick:o[8]||(o[8]=(...t)=>e.postToGallery&&e.postToGallery(...t))},["postToGallery"===e.uploading?(s(),t(d,{key:0},[i("Uploading ("+r(e.uploadProgressPercent)+"%)",1)],64)):(s(),t(d,{key:1},[ke],64))],8,["disabled"]),n("button",{class:"btn",disabled:!e.canSetupGameClick,onClick:o[9]||(o[9]=(...t)=>e.setupGameClick&&e.setupGameClick(...t))},["setupGame"===e.uploading?(s(),t(d,{key:0},[i("Uploading ("+r(e.uploadProgressPercent)+"%)",1)],64)):(s(),t(d,{key:1},[Pe,Ae,Se],64))],8,["disabled"])])])])};var ze=e({name:"edit-image-dialog",components:{ResponsiveImage:se,TagsInput:ie},props:{image:{type:Object,required:!0},autocompleteTags:{type:Function}},emits:{bgclick:null,saveClick:null},data:()=>({title:"",tags:[]}),created(){this.title=this.image.title,this.tags=this.image.tags.map((e=>e.title))},methods:{saveImage(){this.$emit("saveClick",{id:this.image.id,title:this.title,tags:this.tags})}}});const Te={class:"area-image"},Ie={class:"has-image"},Ee={class:"area-settings"},Me=n("td",null,[n("label",null,"Title")],-1),De=n("tr",null,[n("td",{colspan:"2"},[n("div",{class:"hint"},"Feel free to leave a credit to the artist/photographer in the title :)")])],-1),Ne=n("td",null,[n("label",null,"Tags")],-1),_e={class:"area-buttons"};var Ve,Oe,Be,Ue,Re,$e,Ge,Le;ze.render=function(e,o,l,i,r,d){const c=a("responsive-image"),h=a("tags-input");return s(),t("div",{class:"overlay edit-image-dialog",onClick:o[5]||(o[5]=t=>e.$emit("bgclick"))},[n("div",{class:"overlay-content",onClick:o[4]||(o[4]=u((()=>{}),["stop"]))},[n("div",Te,[n("div",Ie,[n(c,{src:e.image.url,title:e.image.title},null,8,["src","title"])])]),n("div",Ee,[n("table",null,[n("tr",null,[Me,n("td",null,[p(n("input",{type:"text","onUpdate:modelValue":o[1]||(o[1]=t=>e.title=t),placeholder:"Flower by @artist"},null,512),[[g,e.title]])])]),De,n("tr",null,[Ne,n("td",null,[n(h,{modelValue:e.tags,"onUpdate:modelValue":o[2]||(o[2]=t=>e.tags=t),autocompleteTags:e.autocompleteTags},null,8,["modelValue","autocompleteTags"])])])])]),n("div",_e,[n("button",{class:"btn",onClick:o[3]||(o[3]=(...t)=>e.saveImage&&e.saveImage(...t))},"🖼️ Save image")])])])},(Oe=Ve||(Ve={}))[Oe.Flat=0]="Flat",Oe[Oe.Out=1]="Out",Oe[Oe.In=-1]="In",(Ue=Be||(Be={}))[Ue.FINAL=0]="FINAL",Ue[Ue.ANY=1]="ANY",($e=Re||(Re={}))[$e.NORMAL=0]="NORMAL",$e[$e.ANY=1]="ANY",$e[$e.FLAT=2]="FLAT",(Le=Ge||(Ge={}))[Le.NORMAL=0]="NORMAL",Le[Le.REAL=1]="REAL";var Fe=e({name:"new-game-dialog",components:{ResponsiveImage:se},props:{image:{type:Object,required:!0}},emits:{newGame:null,bgclick:null},data:()=>({tiles:1e3,scoreMode:Be.ANY,shapeMode:Re.NORMAL,snapMode:Ge.NORMAL}),methods:{onNewGameClick(){this.$emit("newGame",{tiles:this.tilesInt,image:this.image,scoreMode:this.scoreModeInt,shapeMode:this.shapeModeInt,snapMode:this.snapModeInt})}},computed:{canStartNewGame(){return!!(this.tilesInt&&this.image&&this.image.url&&[0,1].includes(this.scoreModeInt))},scoreModeInt(){return parseInt(`${this.scoreMode}`,10)},shapeModeInt(){return parseInt(`${this.shapeMode}`,10)},snapModeInt(){return parseInt(`${this.snapMode}`,10)},tilesInt(){return parseInt(`${this.tiles}`,10)}}});const je={class:"area-image"},We={class:"has-image"},He={key:0,class:"image-title"},Ke={key:0,class:"image-title-title"},qe={key:1,class:"image-title-dim"},Ye={class:"area-settings"},Qe=n("td",null,[n("label",null,"Pieces")],-1),Ze=n("td",null,[n("label",null,"Scoring: ")],-1),Xe=i(" Any (Score when pieces are connected to each other or on final location)"),Je=n("br",null,null,-1),et=i(" Final (Score when pieces are put to their final location)"),tt=n("td",null,[n("label",null,"Shapes: ")],-1),nt=i(" Normal"),ot=n("br",null,null,-1),lt=i(" Any (flat pieces can occur anywhere)"),at=n("br",null,null,-1),st=i(" Flat (all pieces flat on all sides)"),it=n("td",null,[n("label",null,"Snapping: ")],-1),rt=i(" Normal (pieces snap to final destination and to each other)"),dt=n("br",null,null,-1),ct=i(" Real (pieces snap only to corners, already snapped pieces and to each other)"),ut={class:"area-buttons"};Fe.render=function(e,o,i,d,c,h){const m=a("responsive-image");return s(),t("div",{class:"overlay new-game-dialog",onClick:o[11]||(o[11]=t=>e.$emit("bgclick"))},[n("div",{class:"overlay-content",onClick:o[10]||(o[10]=u((()=>{}),["stop"]))},[n("div",je,[n("div",We,[n(m,{src:e.image.url,title:e.image.title},null,8,["src","title"])]),e.image.title||e.image.width||e.image.height?(s(),t("div",He,[e.image.title?(s(),t("span",Ke,'"'+r(e.image.title)+'"',1)):l("",!0),e.image.width||e.image.height?(s(),t("span",qe,"("+r(e.image.width)+" ✕ "+r(e.image.height)+")",1)):l("",!0)])):l("",!0)]),n("div",Ye,[n("table",null,[n("tr",null,[Qe,n("td",null,[p(n("input",{type:"text","onUpdate:modelValue":o[1]||(o[1]=t=>e.tiles=t)},null,512),[[g,e.tiles]])])]),n("tr",null,[Ze,n("td",null,[n("label",null,[p(n("input",{type:"radio","onUpdate:modelValue":o[2]||(o[2]=t=>e.scoreMode=t),value:"1"},null,512),[[v,e.scoreMode]]),Xe]),Je,n("label",null,[p(n("input",{type:"radio","onUpdate:modelValue":o[3]||(o[3]=t=>e.scoreMode=t),value:"0"},null,512),[[v,e.scoreMode]]),et])])]),n("tr",null,[tt,n("td",null,[n("label",null,[p(n("input",{type:"radio","onUpdate:modelValue":o[4]||(o[4]=t=>e.shapeMode=t),value:"0"},null,512),[[v,e.shapeMode]]),nt]),ot,n("label",null,[p(n("input",{type:"radio","onUpdate:modelValue":o[5]||(o[5]=t=>e.shapeMode=t),value:"1"},null,512),[[v,e.shapeMode]]),lt]),at,n("label",null,[p(n("input",{type:"radio","onUpdate:modelValue":o[6]||(o[6]=t=>e.shapeMode=t),value:"2"},null,512),[[v,e.shapeMode]]),st])])]),n("tr",null,[it,n("td",null,[n("label",null,[p(n("input",{type:"radio","onUpdate:modelValue":o[7]||(o[7]=t=>e.snapMode=t),value:"0"},null,512),[[v,e.snapMode]]),rt]),dt,n("label",null,[p(n("input",{type:"radio","onUpdate:modelValue":o[8]||(o[8]=t=>e.snapMode=t),value:"1"},null,512),[[v,e.snapMode]]),ct])])])])]),n("div",ut,[n("button",{class:"btn",disabled:!e.canStartNewGame,onClick:o[9]||(o[9]=(...t)=>e.onNewGameClick&&e.onNewGameClick(...t))}," 🧩 Generate Puzzle ",8,["disabled"])])])])};var pt=e({components:{ImageLibrary:te,NewImageDialog:pe,EditImageDialog:ze,NewGameDialog:Fe},data:()=>({filters:{sort:"date_desc",tags:[]},images:[],tags:[],image:{id:0,filename:"",file:"",url:"",title:"",tags:[],created:0},dialog:"",uploading:"",uploadProgress:0}),async created(){await this.loadImages()},computed:{relevantTags(){return this.tags.filter((e=>e.total>0))}},methods:{autocompleteTags(e,t){return this.tags.filter((n=>!t.includes(n.title)&&n.title.toLowerCase().startsWith(e.toLowerCase()))).slice(0,10).map((e=>e.title))},toggleTag(e){this.filters.tags.includes(e.slug)?this.filters.tags=this.filters.tags.filter((t=>t!==e.slug)):this.filters.tags.push(e.slug),this.filtersChanged()},async loadImages(){const e=await _(`/api/newgame-data${ae.asQueryArgs(this.filters)}`,{}),t=await e.json();this.images=t.images,this.tags=t.tags},async filtersChanged(){await this.loadImages()},onImageClicked(e){this.image=e,this.dialog="new-game"},onImageEditClicked(e){this.image=e,this.dialog="edit-image"},async uploadImage(e){this.uploadProgress=0;const t=new FormData;t.append("file",e.file,e.file.name),t.append("title",e.title),t.append("tags",e.tags);const n=await V("/api/upload",{body:t,onUploadProgress:e=>{this.uploadProgress=e.loaded/e.total}});return this.uploadProgress=1,await n.json()},async saveImage(e){const t=await V("/api/save-image",{headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify({id:e.id,title:e.title,tags:e.tags})});return await t.json()},async onSaveImageClick(e){const t=await this.saveImage(e);t.ok?(this.dialog="",await this.loadImages()):alert(t.error)},async postToGalleryClick(e){this.uploading="postToGallery",await this.uploadImage(e),this.uploading="",this.dialog="",await this.loadImages()},async setupGameClick(e){this.uploading="setupGame";const t=await this.uploadImage(e);this.uploading="",this.loadImages(),this.image=t,this.dialog="new-game"},async onNewGame(e){const t=await V("/api/newgame",{headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(e)});if(200===t.status){const e=await t.json();this.$router.push({name:"game",params:{id:e.id}})}}}});const gt={class:"upload-image-teaser"},ht=n("div",{class:"hint"},"(The image you upload will be added to the public gallery.)",-1),mt={key:0},yt=i(" Tags: "),ft=i(" Sort by: "),vt=n("option",{value:"date_desc"},"Newest first",-1),wt=n("option",{value:"date_asc"},"Oldest first",-1),bt=n("option",{value:"alpha_asc"},"A-Z",-1),Ct=n("option",{value:"alpha_desc"},"Z-A",-1);pt.render=function(e,o,i,u,g,h){const m=a("image-library"),y=a("new-image-dialog"),f=a("edit-image-dialog"),v=a("new-game-dialog");return s(),t("div",null,[n("div",gt,[n("div",{class:"btn btn-big",onClick:o[1]||(o[1]=t=>e.dialog="new-image")},"Upload your image"),ht]),n("div",null,[e.tags.length>0?(s(),t("label",mt,[yt,(s(!0),t(d,null,c(e.relevantTags,((n,o)=>(s(),t("span",{class:["bit",{on:e.filters.tags.includes(n.slug)}],key:o,onClick:t=>e.toggleTag(n)},r(n.title)+" ("+r(n.total)+")",11,["onClick"])))),128))])):l("",!0),n("label",null,[ft,p(n("select",{"onUpdate:modelValue":o[2]||(o[2]=t=>e.filters.sort=t),onChange:o[3]||(o[3]=(...t)=>e.filtersChanged&&e.filtersChanged(...t))},[vt,wt,bt,Ct],544),[[w,e.filters.sort]])])]),n(m,{images:e.images,onImageClicked:e.onImageClicked,onImageEditClicked:e.onImageEditClicked},null,8,["images","onImageClicked","onImageEditClicked"]),"new-image"===e.dialog?(s(),t(y,{key:0,autocompleteTags:e.autocompleteTags,onBgclick:o[4]||(o[4]=t=>e.dialog=""),uploadProgress:e.uploadProgress,uploading:e.uploading,onPostToGalleryClick:e.postToGalleryClick,onSetupGameClick:e.setupGameClick},null,8,["autocompleteTags","uploadProgress","uploading","onPostToGalleryClick","onSetupGameClick"])):l("",!0),"edit-image"===e.dialog?(s(),t(f,{key:1,autocompleteTags:e.autocompleteTags,onBgclick:o[5]||(o[5]=t=>e.dialog=""),onSaveClick:e.onSaveImageClick,image:e.image},null,8,["autocompleteTags","onSaveClick","image"])):l("",!0),e.image&&"new-game"===e.dialog?(s(),t(v,{key:2,onBgclick:o[6]||(o[6]=t=>e.dialog=""),onNewGame:e.onNewGame,image:e.image},null,8,["onNewGame","image"])):l("",!0)])};var xt=e({name:"scores",props:{activePlayers:{type:Array,required:!0},idlePlayers:{type:Array,required:!0}},computed:{actives(){return this.activePlayers.sort(((e,t)=>t.points-e.points)),this.activePlayers},idles(){return this.idlePlayers.sort(((e,t)=>t.points-e.points)),this.idlePlayers}}});const kt={class:"scores"},Pt=n("div",null,"Scores",-1),At=n("td",null,"⚡",-1),St=n("td",null,"💤",-1);xt.render=function(e,o,l,a,i,u){return s(),t("div",kt,[Pt,n("table",null,[(s(!0),t(d,null,c(e.actives,((e,o)=>(s(),t("tr",{key:o,style:{color:e.color}},[At,n("td",null,r(e.name),1),n("td",null,r(e.points),1)],4)))),128)),(s(!0),t(d,null,c(e.idles,((e,o)=>(s(),t("tr",{key:o,style:{color:e.color}},[St,n("td",null,r(e.name),1),n("td",null,r(e.points),1)],4)))),128))])])};var zt=e({name:"puzzle-status",props:{finished:{type:Boolean,required:!0},duration:{type:Number,required:!0},piecesDone:{type:Number,required:!0},piecesTotal:{type:Number,required:!0}},computed:{icon(){return this.finished?"🏁":"⏳"},durationStr(){return j(this.duration)}}});const Tt={class:"timer"};zt.render=function(e,o,l,a,i,d){return s(),t("div",Tt,[n("div",null," 🧩 "+r(e.piecesDone)+"/"+r(e.piecesTotal),1),n("div",null,r(e.icon)+" "+r(e.durationStr),1),b(e.$slots,"default")])};var It=e({name:"settings-overlay",emits:{bgclick:null,"update:modelValue":null},props:{modelValue:{type:Object,required:!0}},methods:{updateVolume(e){this.modelValue.soundsVolume=e.target.value},decreaseVolume(){const e=parseInt(this.modelValue.soundsVolume,10)-5;this.modelValue.soundsVolume=Math.max(0,e)},increaseVolume(){const e=parseInt(this.modelValue.soundsVolume,10)+5;this.modelValue.soundsVolume=Math.min(100,e)}},created(){this.$watch("modelValue",(e=>{this.$emit("update:modelValue",e)}),{deep:!0})}});const Et=m();y("data-v-4d56fc17");const Mt=n("td",null,[n("label",null,"Background: ")],-1),Dt=n("td",null,[n("label",null,"Color: ")],-1),Nt=n("td",null,[n("label",null,"Name: ")],-1),_t=n("td",null,[n("label",null,"Sounds: ")],-1),Vt=n("td",null,[n("label",null,"Sounds Volume: ")],-1),Ot={class:"sound-volume"},Bt=n("td",null,[n("label",null,"Show player names: ")],-1);f();const Ut=Et(((e,o,l,a,i,r)=>(s(),t("div",{class:"overlay transparent",onClick:o[10]||(o[10]=t=>e.$emit("bgclick"))},[n("table",{class:"overlay-content settings",onClick:o[9]||(o[9]=u((()=>{}),["stop"]))},[n("tr",null,[Mt,n("td",null,[p(n("input",{type:"color","onUpdate:modelValue":o[1]||(o[1]=t=>e.modelValue.background=t)},null,512),[[g,e.modelValue.background]])])]),n("tr",null,[Dt,n("td",null,[p(n("input",{type:"color","onUpdate:modelValue":o[2]||(o[2]=t=>e.modelValue.color=t)},null,512),[[g,e.modelValue.color]])])]),n("tr",null,[Nt,n("td",null,[p(n("input",{type:"text",maxLength:"16","onUpdate:modelValue":o[3]||(o[3]=t=>e.modelValue.name=t)},null,512),[[g,e.modelValue.name]])])]),n("tr",null,[_t,n("td",null,[p(n("input",{type:"checkbox","onUpdate:modelValue":o[4]||(o[4]=t=>e.modelValue.soundsEnabled=t)},null,512),[[C,e.modelValue.soundsEnabled]])])]),n("tr",null,[Vt,n("td",Ot,[n("span",{onClick:o[5]||(o[5]=(...t)=>e.decreaseVolume&&e.decreaseVolume(...t))},"🔉"),n("input",{type:"range",min:"0",max:"100",value:e.modelValue.soundsVolume,onChange:o[6]||(o[6]=(...t)=>e.updateVolume&&e.updateVolume(...t))},null,40,["value"]),n("span",{onClick:o[7]||(o[7]=(...t)=>e.increaseVolume&&e.increaseVolume(...t))},"🔊")])]),n("tr",null,[Bt,n("td",null,[p(n("input",{type:"checkbox","onUpdate:modelValue":o[8]||(o[8]=t=>e.modelValue.showPlayerNames=t)},null,512),[[C,e.modelValue.showPlayerNames]])])])])]))));It.render=Ut,It.__scopeId="data-v-4d56fc17";var Rt=e({name:"preview-overlay",props:{img:String},emits:{bgclick:null},computed:{previewStyle(){return{backgroundImage:`url('${this.img}')`}}}});const $t={class:"preview"};Rt.render=function(e,o,l,a,i,r){return s(),t("div",{class:"overlay",onClick:o[1]||(o[1]=t=>e.$emit("bgclick"))},[n("div",$t,[n("div",{class:"img",style:e.previewStyle},null,4)])])};var Gt=e({name:"help-overlay",emits:{bgclick:null},props:{game:{type:Object,required:!0}},computed:{scoreMode(){switch(this.game.scoreMode){case Be.ANY:return["Any","Score when pieces are connected to each other or on final location"];case Be.FINAL:default:return["Final","Score when pieces are put to their final location"]}},shapeMode(){switch(this.game.shapeMode){case Re.FLAT:return["Flat","All pieces flat on all sides"];case Re.ANY:return["Any","Flat pieces can occur anywhere"];case Re.NORMAL:default:return["Normal",""]}},snapMode(){switch(this.game.snapMode){case Ge.REAL:return["Real","Pieces snap only to corners, already snapped pieces and to each other"];case Ge.NORMAL:default:return["Normal","Pieces snap to final destination and to each other"]}}}});const Lt=n("tr",null,[n("td",{colspan:"2"},"Info about this puzzle")],-1),Ft=n("td",null,"Image Title: ",-1),jt=n("td",null,"Scoring: ",-1),Wt=n("td",null,"Shapes: ",-1),Ht=n("td",null,"Snapping: ",-1);Gt.render=function(e,o,l,a,i,d){return s(),t("div",{class:"overlay transparent",onClick:o[2]||(o[2]=t=>e.$emit("bgclick"))},[n("table",{class:"overlay-content help",onClick:o[1]||(o[1]=u((()=>{}),["stop"]))},[Lt,n("tr",null,[Ft,n("td",null,r(e.game.puzzle.info.image.title),1)]),n("tr",null,[jt,n("td",null,[n("span",{title:e.snapMode[1]},r(e.scoreMode[0]),9,["title"])])]),n("tr",null,[Wt,n("td",null,[n("span",{title:e.snapMode[1]},r(e.shapeMode[0]),9,["title"])])]),n("tr",null,[Ht,n("td",null,[n("span",{title:e.snapMode[1]},r(e.snapMode[0]),9,["title"])])])])])};var Kt=1,qt=4,Yt=2,Qt=3,Zt=2,Xt=4,Jt=3,en=9,tn=1,nn=2,on=3,ln=4,an=5,sn=6,rn=7,dn=8,cn=10,un=11,pn=12,gn=13,hn=14,mn=15,yn=16,fn=17,vn=18,wn=1,bn=2,Cn=3;const xn=le("Communication.js");let kn,Pn=[],An=e=>{Pn.push(e)},Sn=[],zn=e=>{Sn.push(e)};let Tn=0;const In=e=>{Tn!==e&&(Tn=e,zn(e))};function En(e){if(2===Tn)try{kn.send(JSON.stringify(e))}catch(t){xn.info("unable to send message.. maybe because ws is invalid?")}}let Mn,Dn;var Nn={connect:function(e,t,n){return Mn=0,Dn={},In(3),new Promise((o=>{kn=new WebSocket(e,n+"|"+t),kn.onopen=()=>{In(2),En([Qt])},kn.onmessage=e=>{const t=JSON.parse(e.data),l=t[0];if(l===qt){const e=t[1];o(e)}else{if(l!==Kt)throw`[ 2021-05-09 invalid connect msgType ${l} ]`;{const e=t[1],o=t[2];if(e===n&&Dn[o])return void delete Dn[o];An(t)}}},kn.onerror=()=>{throw In(1),"[ 2021-05-15 onerror ]"},kn.onclose=e=>{4e3===e.code||1001===e.code?In(4):In(1)}}))},requestReplayData:async function(e,t){const n={gameId:e,offset:t},o=await _(`/api/replay-data${ae.asQueryArgs(n)}`,{});return await o.json()},disconnect:function(){kn&&kn.close(4e3),Mn=0,Dn={}},sendClientEvent:function(e){Mn++,Dn[Mn]=e,En([Yt,Mn,Dn[Mn]])},onServerChange:function(e){An=e;for(const t of Pn)An(t);Pn=[]},onConnectionStateChange:function(e){zn=e;for(const t of Sn)zn(t);Sn=[]},CODE_CUSTOM_DISCONNECT:4e3,CONN_STATE_NOT_CONNECTED:0,CONN_STATE_DISCONNECTED:1,CONN_STATE_CLOSED:4,CONN_STATE_CONNECTED:2,CONN_STATE_CONNECTING:3},_n=e({name:"connection-overlay",emits:{reconnect:null},props:{connectionState:Number},computed:{lostConnection(){return this.connectionState===Nn.CONN_STATE_DISCONNECTED},connecting(){return this.connectionState===Nn.CONN_STATE_CONNECTING},show(){return!(!this.lostConnection&&!this.connecting)}}});const Vn={key:0,class:"overlay connection-lost"},On={key:0,class:"overlay-content"},Bn=n("div",null,"⁉️ LOST CONNECTION ⁉️",-1),Un={key:1,class:"overlay-content"},Rn=n("div",null,"Connecting...",-1);_n.render=function(e,o,a,i,r,d){return e.show?(s(),t("div",Vn,[e.lostConnection?(s(),t("div",On,[Bn,n("span",{class:"btn",onClick:o[1]||(o[1]=t=>e.$emit("reconnect"))},"Reconnect")])):l("",!0),e.connecting?(s(),t("div",Un,[Rn])):l("",!0)])):l("",!0)};var $n=e({name:"help-overlay",emits:{bgclick:null}});const Gn=n("tr",null,[n("td",null,"⬆️ Move up:"),n("td",null,[n("div",null,[n("kbd",null,"W"),i("/"),n("kbd",null,"↑"),i("/🖱️")])])],-1),Ln=n("tr",null,[n("td",null,"⬇️ Move down:"),n("td",null,[n("div",null,[n("kbd",null,"S"),i("/"),n("kbd",null,"↓"),i("/🖱️")])])],-1),Fn=n("tr",null,[n("td",null,"⬅️ Move left:"),n("td",null,[n("div",null,[n("kbd",null,"A"),i("/"),n("kbd",null,"←"),i("/🖱️")])])],-1),jn=n("tr",null,[n("td",null,"➡️ Move right:"),n("td",null,[n("div",null,[n("kbd",null,"D"),i("/"),n("kbd",null,"→"),i("/🖱️")])])],-1),Wn=n("tr",null,[n("td"),n("td",null,[n("div",null,[i("Move faster by holding "),n("kbd",null,"Shift")])])],-1),Hn=n("tr",null,[n("td",null,"🔍+ Zoom in:"),n("td",null,[n("div",null,[n("kbd",null,"E"),i("/🖱️-Wheel")])])],-1),Kn=n("tr",null,[n("td",null,"🔍- Zoom out:"),n("td",null,[n("div",null,[n("kbd",null,"Q"),i("/🖱️-Wheel")])])],-1),qn=n("tr",null,[n("td",null,"🖼️ Toggle preview:"),n("td",null,[n("div",null,[n("kbd",null,"Space")])])],-1),Yn=n("tr",null,[n("td",null,"🎯 Center puzzle in screen:"),n("td",null,[n("div",null,[n("kbd",null,"C")])])],-1),Qn=n("tr",null,[n("td",null,"🧩✔️ Toggle fixed pieces:"),n("td",null,[n("div",null,[n("kbd",null,"F")])])],-1),Zn=n("tr",null,[n("td",null,"🧩❓ Toggle loose pieces:"),n("td",null,[n("div",null,[n("kbd",null,"G")])])],-1),Xn=n("tr",null,[n("td",null,"👤 Toggle player names:"),n("td",null,[n("div",null,[n("kbd",null,"N")])])],-1),Jn=n("tr",null,[n("td",null,"🔉 Toggle sounds:"),n("td",null,[n("div",null,[n("kbd",null,"M")])])],-1),eo=n("tr",null,[n("td",null,"⏫ Speed up (replay):"),n("td",null,[n("div",null,[n("kbd",null,"I")])])],-1),to=n("tr",null,[n("td",null,"⏬ Speed down (replay):"),n("td",null,[n("div",null,[n("kbd",null,"O")])])],-1),no=n("tr",null,[n("td",null,"⏸️ Pause (replay):"),n("td",null,[n("div",null,[n("kbd",null,"P")])])],-1);$n.render=function(e,o,l,a,i,r){return s(),t("div",{class:"overlay transparent",onClick:o[2]||(o[2]=t=>e.$emit("bgclick"))},[n("table",{class:"overlay-content help",onClick:o[1]||(o[1]=u((()=>{}),["stop"]))},[Gn,Ln,Fn,jn,Wn,Hn,Kn,qn,Yn,Qn,Zn,Xn,Jn,eo,to,no])])};var oo=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"/assets/click.bb97cb07.mp3"}),lo=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAW0lEQVQ4je1RywrAIAxLxP//5exixRWlVgZelpOKeTQFfnDypgy3eLIkSLLL8mxGPoHsU2hPAgDHBLvRX6hZZw/fwT0BtlLSONqCbWAmEIqMZOCDDlaDR3N03gOyDCn+y4DWmAAAAABJRU5ErkJggg=="}),ao=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAARElEQVQ4jWNgGAU0Af+hmBCbgYGBgYERhwHEAEYGBgYGJtIdiApYyLAZBVDsAqoagC1ACQJyY4ERg0GCISh6KA4DigEAou8LC+LnIJoAAAAASUVORK5CYII="}),so=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAcUlEQVQ4ja1TQQ7AIAgD///n7jCozA2Hbk00jbG1KIrcARszTugoBs49qioZj7r2kKACptkyAOCJsJuA+GzglwHjvMSSWFVaENWVASxh5eRLiq5fN/ASjI89VcP2K3hHpq1cEXNaMfnrL3TDZP2tDuoOA6MzCCXWr38AAAAASUVORK5CYII="}),io=Object.freeze({__proto__:null,[Symbol.toStringTag]:"Module",default:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAU0lEQVQ4jWNgoAH4D8X42HDARKlt5BoAd82AuQAOGLGIYQQUPv0wF5CiCQUge4EsQ5C9QI4BjMguwBYeBAElscCIy1ZivMKIwSDBEBQ9FCckigEAU3QOD7TGvY4AAAAASUVORK5CYII="});function ro(e=0,t=0){const n=document.createElement("canvas");return n.width=e,n.height=t,n}var co={createCanvas:ro,loadImageToBitmap:async function(e){return new Promise((t=>{const n=new Image;n.onload=()=>{createImageBitmap(n).then(t)},n.src=e}))},resizeBitmap:async function(e,t,n){const o=ro(t,n);return o.getContext("2d").drawImage(e,0,0,e.width,e.height,0,0,t,n),await createImageBitmap(o)},colorizedCanvas:function(e,t,n){const o=ro(e.width,e.height),l=o.getContext("2d");return l.save(),l.drawImage(t,0,0),l.fillStyle=n,l.globalCompositeOperation="source-in",l.fillRect(0,0,t.width,t.height),l.restore(),l.save(),l.globalCompositeOperation="destination-over",l.drawImage(e,0,0),l.restore(),o}};const uo=le("Debug.js");let po=0,go=0;var ho=e=>{po=performance.now(),go=e},mo=e=>{const t=performance.now(),n=t-po;n>go&&uo.log(e+": "+n),po=t};function yo(e,t){const n=e.x-t.x,o=e.y-t.y;return Math.sqrt(n*n+o*o)}function fo(e){return{x:e.x+e.w/2,y:e.y+e.h/2}}var vo={pointSub:function(e,t){return{x:e.x-t.x,y:e.y-t.y}},pointAdd:function(e,t){return{x:e.x+t.x,y:e.y+t.y}},pointDistance:yo,pointInBounds:function(e,t){return e.x>=t.x&&e.x<=t.x+t.w&&e.y>=t.y&&e.y<=t.y+t.h},rectCenter:fo,rectMoved:function(e,t,n){return{x:e.x+t,y:e.y+n,w:e.w,h:e.h}},rectCenterDistance:function(e,t){return yo(fo(e),fo(t))},rectsOverlap:function(e,t){return!(t.x>e.x+e.w||e.x>t.x+t.w||t.y>e.y+e.h||e.y>t.y+t.h)}};const wo=le("PuzzleGraphics.js");function bo(e,t){const n=ae.coordByPieceIdx(e,t);return{x:n.x*e.tileSize,y:n.y*e.tileSize,w:e.tileSize,h:e.tileSize}}var Co={loadPuzzleBitmaps:async function(e){const t=await co.loadImageToBitmap(e.info.imageUrl),n=await co.resizeBitmap(t,e.info.width,e.info.height);return await async function(e,t,n){wo.log("start createPuzzleTileBitmaps");const o=n.tileSize,l=n.tileMarginWidth,a=n.tileDrawSize,s=o/100,i=[0,0,40,15,37,5,37,5,40,0,38,-5,38,-5,20,-20,50,-20,50,-20,80,-20,62,-5,62,-5,60,0,63,5,63,5,65,15,100,0],r=new Array(t.length),d={};function c(e){const t=`${e.top}${e.right}${e.left}${e.bottom}`;if(d[t])return d[t];const n=new Path2D,a={x:l,y:l},r=vo.pointAdd(a,{x:o,y:0}),c=vo.pointAdd(r,{x:0,y:o}),u=vo.pointSub(c,{x:o,y:0});if(n.moveTo(a.x,a.y),0!==e.top)for(let o=0;oae.decodePiece(xo[e].puzzle.tiles[t]),Bo=(e,t)=>Oo(e,t).group,Uo=(e,t)=>{const n=xo[e].puzzle.info;return 0===t||t===n.tilesX-1||t===n.tiles-n.tilesX||t===n.tiles-1},Ro=(e,t)=>{const n=xo[e].puzzle.info,o={x:(n.table.width-n.width)/2,y:(n.table.height-n.height)/2},l=function(e,t){const n=xo[e].puzzle.info,o=ae.coordByPieceIdx(n,t),l=o.x*n.tileSize,a=o.y*n.tileSize;return{x:l,y:a}}(e,t);return vo.pointAdd(o,l)},$o=(e,t)=>Oo(e,t).pos,Go=e=>{const t=ll(e),n=al(e),o=Math.round(t/4),l=Math.round(n/4);return{x:0-o,y:0-l,w:t+2*o,h:n+2*l}},Lo=(e,t)=>{const n=Ho(e),o=Oo(e,t);return{x:o.pos.x,y:o.pos.y,w:n,h:n}},Fo=(e,t)=>Oo(e,t).z,jo=(e,t)=>{for(const n of xo[e].puzzle.tiles){const e=ae.decodePiece(n);if(e.owner===t)return e.idx}return-1},Wo=e=>xo[e].puzzle.info.tileDrawSize,Ho=e=>xo[e].puzzle.info.tileSize,Ko=e=>xo[e].puzzle.data.maxGroup,qo=e=>xo[e].puzzle.data.maxZ;function Yo(e,t){const n=xo[e].puzzle.info,o=ae.coordByPieceIdx(n,t);return[o.y>0?t-n.tilesX:-1,o.x0?t-1:-1]}const Qo=(e,t,n)=>{for(const o of t)Vo(e,o,{z:n})},Zo=(e,t,n)=>{const o=$o(e,t);Vo(e,t,{pos:vo.pointAdd(o,n)})},Xo=(e,t,n)=>{const o=Wo(e),l=Go(e),a=n;for(const s of t){const t=Oo(e,s);t.pos.x+n.xl.x+l.w&&(a.x=Math.min(l.x+l.w-t.pos.x+o,a.x)),t.pos.y+n.yl.y+l.h&&(a.y=Math.min(l.y+l.h-t.pos.y+o,a.y))}for(const s of t)Zo(e,s,a)},Jo=(e,t)=>Oo(e,t).owner,el=(e,t)=>{for(const n of t)Vo(e,n,{owner:-1,z:1})},tl=(e,t,n)=>{for(const o of t)Vo(e,o,{owner:n})};function nl(e,t){const n=xo[e].puzzle.tiles,o=ae.decodePiece(n[t]),l=[];if(o.group)for(const a of n){const e=ae.decodePiece(a);e.group===o.group&&l.push(e.idx)}else l.push(o.idx);return l}const ol=(e,t)=>{const n=Po(e,t);return n?n.points:0},ll=e=>xo[e].puzzle.info.table.width,al=e=>xo[e].puzzle.info.table.height;var sl={setGame:function(e,t){xo[e]=t},exists:function(e){return!!xo[e]||!1},playerExists:So,getActivePlayers:function(e,t){const n=t-30*G;return zo(e).filter((e=>e.ts>=n))},getIdlePlayers:function(e,t){const n=t-30*G;return zo(e).filter((e=>e.ts0))},addPlayer:function(e,t,n){So(e,t)?No(e,t,{ts:n}):Ao(e,t,function(e,t){return{id:e,x:0,y:0,d:0,name:null,color:null,bgcolor:null,points:0,ts:t}}(t,n))},getFinishedPiecesCount:Do,getPieceCount:To,getImageUrl:function(e){var t;const n=(null==(t=xo[e].puzzle.info.image)?void 0:t.url)||xo[e].puzzle.info.imageUrl;if(!n)throw new Error("[2021-07-11] no image url set");return n},get:function(e){return xo[e]||null},getAllGames:function(){return Object.values(xo).sort(((e,t)=>{const n=Mo(e.id);return n===Mo(t.id)?n?t.puzzle.data.finished-e.puzzle.data.finished:t.puzzle.data.started-e.puzzle.data.started:n?1:-1}))},getPlayerBgColor:(e,t)=>{const n=Po(e,t);return n?n.bgcolor:null},getPlayerColor:(e,t)=>{const n=Po(e,t);return n?n.color:null},getPlayerName:(e,t)=>{const n=Po(e,t);return n?n.name:null},getPlayerIndexById:ko,getPlayerIdByIndex:function(e,t){return xo[e].players.length>t?ae.decodePlayer(xo[e].players[t]).id:null},changePlayer:No,setPlayer:Ao,setPiece:function(e,t,n){xo[e].puzzle.tiles[t]=ae.encodePiece(n)},setPuzzleData:function(e,t){xo[e].puzzle.data=t},getTableWidth:ll,getTableHeight:al,getPuzzle:e=>xo[e].puzzle,getRng:e=>xo[e].rng.obj,getPuzzleWidth:e=>xo[e].puzzle.info.width,getPuzzleHeight:e=>xo[e].puzzle.info.height,getPiecesSortedByZIndex:function(e){return xo[e].puzzle.tiles.map(ae.decodePiece).sort(((e,t)=>e.z-t.z))},getFirstOwnedPiece:(e,t)=>{const n=jo(e,t);return n<0?null:xo[e].puzzle.tiles[n]},getPieceDrawOffset:e=>xo[e].puzzle.info.tileDrawOffset,getPieceDrawSize:Wo,getFinalPiecePos:Ro,getStartTs:e=>xo[e].puzzle.data.started,getFinishTs:e=>xo[e].puzzle.data.finished,handleInput:function(e,t,n,o,l){const a=xo[e].puzzle,s=function(e,t){return t in xo[e].evtInfos?xo[e].evtInfos[t]:{_last_mouse:null,_last_mouse_down:null}}(e,t),i=[],r=()=>{i.push([wn,a.data])},d=t=>{i.push([bn,ae.encodePiece(Oo(e,t))])},c=e=>{for(const t of e)d(t)},u=()=>{const n=Po(e,t);n&&i.push([Cn,ae.encodePlayer(n)])},p=n[0];if(p===sn){const l=n[1];No(e,t,{bgcolor:l,ts:o}),u()}else if(p===rn){const l=n[1];No(e,t,{color:l,ts:o}),u()}else if(p===dn){const l=`${n[1]}`.substr(0,16);No(e,t,{name:l,ts:o}),u()}else if(p===en){const l=n[1],a=n[2],s=Po(e,t);if(s){const n=s.x-l,i=s.y-a;No(e,t,{ts:o,x:n,y:i}),u()}}else if(p===tn){const l={x:n[1],y:n[2]};No(e,t,{d:1,ts:o}),u(),s._last_mouse_down=l;const a=((e,t)=>{const n=xo[e].puzzle.info,o=xo[e].puzzle.tiles;let l=-1,a=-1;for(let s=0;sl)&&(l=e.z,a=s)}return a})(e,l);if(a>=0){const n=qo(e)+1;_o(e,{maxZ:n}),r();const o=nl(e,a);Qo(e,o,qo(e)),tl(e,o,t),c(o)}s._last_mouse=l}else if(p===on){const l=n[1],a=n[2],i={x:l,y:a};if(null===s._last_mouse_down)No(e,t,{x:l,y:a,ts:o}),u();else{const n=jo(e,t);if(n>=0){No(e,t,{x:l,y:a,ts:o}),u();const r=nl(e,n);let d=vo.pointInBounds(i,Go(e))&&vo.pointInBounds(s._last_mouse_down,Go(e));for(const t of r){const n=Lo(e,t);if(vo.pointInBounds(i,n)){d=!0;break}}if(d){const t=l-s._last_mouse_down.x,n=a-s._last_mouse_down.y;Xo(e,r,{x:t,y:n}),c(r)}}else No(e,t,{ts:o}),u();s._last_mouse_down=i}s._last_mouse=i}else if(p===nn){const i={x:n[1],y:n[2]},p=0;s._last_mouse_down=null;const g=jo(e,t);if(g>=0){const n=nl(e,g);tl(e,n,0),c(n);const s=$o(e,g),i=Ro(e,g);let h=!1;if(Eo(e)===Ge.REAL){for(const t of n)if(Uo(e,t)){h=!0;break}}else h=!0;if(h&&vo.pointDistance(i,s){const l=xo[e].puzzle.info;if(n<0)return!1;if(((e,t,n)=>{const o=Bo(e,t),l=Bo(e,n);return!(!o||o!==l)})(e,t,n))return!1;const a=$o(e,t),s=vo.pointAdd($o(e,n),{x:o[0]*l.tileSize,y:o[1]*l.tileSize});if(vo.pointDistance(a,s){const o=xo[e].puzzle.tiles,l=Bo(e,t),a=Bo(e,n);let s;const i=[];l&&i.push(l),a&&i.push(a),l?s=l:a?s=a:(_o(e,{maxGroup:Ko(e)+1}),r(),s=Ko(e));if(Vo(e,t,{group:s}),d(t),Vo(e,n,{group:s}),d(n),i.length>0)for(const r of o){const t=ae.decodePiece(r);i.includes(t.group)&&(Vo(e,t.idx,{group:s}),d(t.idx))}})(e,t,n),l=nl(e,t),((e,t)=>-1===Jo(e,t))(e,n))el(e,l);else{const t=((e,t)=>{let n=0;for(const o of t){const t=Fo(e,o);t>n&&(n=t)}return n})(e,l);Qo(e,l,t)}return c(l),!0}return!1};let a=!1;for(const t of nl(e,g)){const o=Yo(e,t);if(n(e,t,o[0],[0,1])||n(e,t,o[1],[-1,0])||n(e,t,o[2],[0,-1])||n(e,t,o[3],[1,0])){a=!0;break}}if(a&&Io(e)===Be.ANY){const n=ol(e,t)+1;No(e,t,{d:p,ts:o,points:n}),u()}else No(e,t,{d:p,ts:o}),u();a&&Eo(e)===Ge.REAL&&Do(e)===To(e)&&(_o(e,{finished:o}),r()),a&&l&&l(t)}}else No(e,t,{d:p,ts:o}),u();s._last_mouse=i}else if(p===ln){const l=n[1],a=n[2];No(e,t,{x:l,y:a,ts:o}),u(),s._last_mouse={x:l,y:a}}else if(p===an){const l=n[1],a=n[2];No(e,t,{x:l,y:a,ts:o}),u(),s._last_mouse={x:l,y:a}}else No(e,t,{ts:o}),u();return function(e,t,n){xo[e].evtInfos[t]=n}(e,t,s),i}};let il=-10,rl=20,dl=2,cl=15;class ul{constructor(e){this.radius=10,this.previousRadius=10,this.explodingDuration=100,this.hasExploded=!1,this.alive=!0,this.color=function(e){return"rgba("+e.random(0,255)+","+e.random(0,255)+","+e.random(0,255)+", 0.8)"}(e),this.px=window.innerWidth/4+Math.random()*window.innerWidth/2,this.py=window.innerHeight,this.vx=il+Math.random()*rl,this.vy=-1*(dl+Math.random()*cl),this.duration=0}update(e){if(this.hasExploded){const e=200-this.radius;this.previousRadius=this.radius,this.radius+=e/10,this.explodingDuration--,0==this.explodingDuration&&(this.alive=!1)}else this.vx+=0,this.vy+=1,this.vy>=0&&e&&this.explode(e),this.px+=this.vx,this.py+=this.vy}draw(e){e.beginPath(),e.arc(this.px,this.py,this.previousRadius,0,2*Math.PI,!1),this.hasExploded||(e.fillStyle=this.color,e.lineWidth=1,e.fill())}explode(e){this.hasExploded=!0;const t=3+Math.floor(3*Math.random());for(let n=0;n{this.resize()}))}setSpeedParams(){let e=0,t=0;for(;e=0;)t+=1,e+=t;dl=t/2,cl=t-dl;const n=1/4*this.canvas.width/(t/2);il=-n,rl=2*n}resize(){this.setSpeedParams()}init(){this.readyBombs=[],this.explodedBombs=[],this.particles=[];for(let e=0;e<1;e++)this.readyBombs.push(new ul(this.rng))}update(){100*Math.random()<5&&this.readyBombs.push(new ul(this.rng));const e=[];for(;this.explodedBombs.length>0;){const t=this.explodedBombs.shift();if(!t)break;t.update(),t.alive&&e.push(t)}this.explodedBombs=e;const t=[];for(;this.readyBombs.length>0;){const e=this.readyBombs.shift();if(!e)break;e.update(this.particles),e.hasExploded?this.explodedBombs.push(e):t.push(e)}this.readyBombs=t;const n=[];for(;this.particles.length>0;){const e=this.particles.shift();if(!e)break;e.update(),e.alive&&n.push(e)}this.particles=n}render(){this.ctx.beginPath(),this.ctx.fillStyle="rgba(0, 0, 0, 0.1)",this.ctx.fillRect(0,0,this.canvas.width,this.canvas.height);for(let e=0;e{localStorage.setItem(e,t)},Cl=e=>localStorage.getItem(e);var xl=(e,t)=>{bl(e,`${t}`)},kl=(e,t)=>{const n=Cl(e);if(null===n)return t;const o=parseInt(n,10);return isNaN(o)?t:o},Pl=(e,t)=>{bl(e,t?"1":"0")},Al=(e,t)=>{const n=Cl(e);return null===n?t:"1"===n},Sl=(e,t)=>{bl(e,t)},zl=(e,t)=>{const n=Cl(e);return null===n?t:n};const Tl={"./grab.png":lo,"./grab_mask.png":ao,"./hand.png":so,"./hand_mask.png":io},Il={"./click.mp3":oo},El="replay";let Ml=!0,Dl=!0;let Nl=!0;async function _l(e,t,n,o,l,a){void 0===window.DEBUG&&(window.DEBUG=!1);const s=Il["./click.mp3"].default,i=new Audio(s),r=await co.loadImageToBitmap(Tl["./grab.png"].default),d=await co.loadImageToBitmap(Tl["./hand.png"].default),c=await co.loadImageToBitmap(Tl["./grab_mask.png"].default),u=await co.loadImageToBitmap(Tl["./hand_mask.png"].default),p=r.width,g=Math.round(p/2),h=r.height,m=Math.round(h/2),y={},f=async e=>{const t=e.color+" "+e.d;if(!y[t]){const n=e.d?r:d;if(e.color){const o=e.d?c:u;y[t]=await createImageBitmap(co.colorizedCanvas(n,o,e.color))}else y[t]=n}return y[t]},v=function(e,t){return t.width=window.innerWidth,t.height=window.innerHeight,e.appendChild(t),window.addEventListener("resize",(()=>{t.width=window.innerWidth,t.height=window.innerHeight,Nl=!0})),t}(l,co.createCanvas()),w={final:!1,log:[],logPointer:0,speeds:[.5,1,2,5,10,20,50,100,250,500],speedIdx:1,paused:!1,lastRealTs:0,lastGameTs:0,gameStartTs:0,skipNonActionPhases:!0,dataOffset:0};Nn.onConnectionStateChange((e=>{a.setConnectionState(e)}));const b=async e=>{const t=w.dataOffset;w.dataOffset+=1e4;const n=await Nn.requestReplayData(e,t);return w.log=w.log.slice(w.logPointer),w.logPointer=0,w.log.push(...n.log),0===n.log.length&&(w.final=!0),n};let C=()=>0;const x=async()=>{if("play"===o){const o=await Nn.connect(n,e,t),l=ae.decodeGame(o);sl.setGame(l.id,l),C=()=>L()}else{if(o!==El)throw"[ 2020-12-22 MODE invalid, must be play|replay ]";{const t=await b(e);if(!t.game)throw"[ 2021-05-29 no game received ]";const n=ae.decodeGame(t.game);sl.setGame(n.id,n),w.lastRealTs=L(),w.gameStartTs=parseInt(t.log[0][4],10),w.lastGameTs=w.gameStartTs,C=()=>w.lastGameTs}}Nl=!0};await x();const k=sl.getPieceDrawOffset(e),P=sl.getPieceDrawSize(e),A=sl.getPuzzleWidth(e),S=sl.getPuzzleHeight(e),z=sl.getTableWidth(e),T=sl.getTableHeight(e),I={x:(z-A)/2,y:(T-S)/2},E={w:A,h:S},M={w:P,h:P},D=await Co.loadPuzzleBitmaps(sl.getPuzzle(e)),N=new gl(v,sl.getRng(e));N.init();const _=v.getContext("2d");v.classList.add("loaded"),a.setPuzzleCut();const V=function(){let e=0,t=0,n=1;const o=(o,l)=>{e+=o/n,t+=l/n},l=e=>{const t=n+.05*n*("in"===e?1:-1);return Math.min(Math.max(t,.1),6)},a=(e,t)=>{if(n==e)return!1;const l=1-n/e;return o(-t.x*l,-t.y*l),n=e,!0},s=o=>({x:o.x/n-e,y:o.y/n-t}),i=o=>({x:(o.x+e)*n,y:(o.y+t)*n}),r=e=>({w:e.w*n,h:e.h*n}),d=e=>({w:e.w/n,h:e.h/n});return{getCurrentZoom:()=>n,reset:()=>{e=0,t=0,n=1},move:o,canZoom:e=>n!=l(e),zoom:(e,t)=>a(l(e),t),setZoom:a,worldToViewport:e=>{const{x:t,y:n}=i(e);return{x:Math.round(t),y:Math.round(n)}},worldToViewportRaw:i,worldDimToViewport:e=>{const{w:t,h:n}=r(e);return{w:Math.round(t),h:Math.round(n)}},worldDimToViewportRaw:r,viewportToWorld:e=>{const{x:t,y:n}=s(e);return{x:Math.round(t),y:Math.round(n)}},viewportToWorldRaw:s,viewportDimToWorld:e=>{const{w:t,h:n}=d(e);return{w:Math.round(t),h:Math.round(n)}},viewportDimToWorldRaw:d}}(),O=()=>{V.reset(),V.move(-(z-v.width)/2,-(T-v.height)/2);const e=V.worldDimToViewport(E),t=v.width-40,n=v.height-40;if(e.w>t||e.h>n||e.w{const o=n.viewportToWorld({x:e,y:t});return[o.x,o.y]},h=e=>g(e.offsetX,e.offsetY),m=()=>g(e.width/2,e.height/2),y=(e,t)=>{a&&("ShiftLeft"===t.code||"ShiftRight"===t.code?p=e:"ArrowUp"===t.code||"KeyW"===t.code?r=e:"ArrowDown"===t.code||"KeyS"===t.code?d=e:"ArrowLeft"===t.code||"KeyA"===t.code?s=e:"ArrowRight"===t.code||"KeyD"===t.code?i=e:"KeyQ"===t.code?u=e:"KeyE"===t.code&&(c=e))};let f=null;e.addEventListener("mousedown",(e=>{f=h(e),0===e.button&&v([tn,...f])})),e.addEventListener("mouseup",(e=>{f=h(e),0===e.button&&v([nn,...f])})),e.addEventListener("mousemove",(e=>{f=h(e),v([on,...f])})),e.addEventListener("wheel",(e=>{if(f=h(e),n.canZoom(e.deltaY<0?"in":"out")){const t=e.deltaY<0?ln:an;v([t,...f])}})),t.addEventListener("keydown",(e=>y(!0,e))),t.addEventListener("keyup",(e=>y(!1,e))),t.addEventListener("keypress",(e=>{a&&("Space"===e.code&&v([cn]),o===El&&("KeyI"===e.code&&v([gn]),"KeyO"===e.code&&v([hn]),"KeyP"===e.code&&v([pn])),"KeyF"===e.code&&v([fn]),"KeyG"===e.code&&v([vn]),"KeyM"===e.code&&v([un]),"KeyN"===e.code&&v([mn]),"KeyC"===e.code&&v([yn]))}));const v=e=>{l.push(e)};return{addEvent:v,consumeAll:()=>{if(0===l.length)return[];const e=l.slice();return l=[],e},createKeyEvents:()=>{const e=(s?1:0)-(i?1:0),t=(r?1:0)-(d?1:0);if(0!==e||0!==t){const o=(p?24:12)*Math.sqrt(n.getCurrentZoom()),l=n.viewportDimToWorld({w:e*o,h:t*o});v([en,l.w,l.h]),f&&(f[0]-=l.w,f[1]-=l.h)}if(c&&u);else if(c){if(n.canZoom("in")){const e=f||m();v([ln,...e])}}else if(u&&n.canZoom("out")){const e=f||m();v([an,...e])}},setHotkeys:e=>{a=e}}}(v,window,V,o),U=sl.getImageUrl(e),R=()=>{const t=sl.getStartTs(e),n=sl.getFinishTs(e),o=C();a.setFinished(!!n),a.setDuration((n||o)-t)};R(),a.setPiecesDone(sl.getFinishedPiecesCount(e)),a.setPiecesTotal(sl.getPieceCount(e));const G=C();a.setActivePlayers(sl.getActivePlayers(e,G)),a.setIdlePlayers(sl.getIdlePlayers(e,G));const F=!!sl.getFinishTs(e);let j=F;const W=()=>j&&!F,H=()=>kl(hl,100),K=()=>Al(ml,!1),q=()=>Al(wl,!0),Y=()=>{const e=H();i.volume=e/100,i.play()},Q=()=>o===El?zl(yl,"#222222"):sl.getPlayerBgColor(e,t)||zl(yl,"#222222"),Z=()=>o===El?zl(fl,"#ffffff"):sl.getPlayerColor(e,t)||zl(fl,"#ffffff");let X="",J="",ee=!1;const te=e=>{ee=e;const[t,n]=e?[X,"grab"]:[J,"default"];v.style.cursor=`url('${t}') ${g} ${m}, ${n}`},ne=e=>{X=co.colorizedCanvas(r,c,e).toDataURL(),J=co.colorizedCanvas(d,u,e).toDataURL(),te(ee)};ne(Z());const oe=()=>{a.setReplaySpeed&&a.setReplaySpeed(w.speeds[w.speedIdx]),a.setReplayPaused&&a.setReplayPaused(w.paused)},le=()=>{w.speedIdx+1{w.speedIdx>=1&&(w.speedIdx--,oe())},ie=()=>{w.paused=!w.paused,oe()},re=[];let de;let ce;if("play"===o?re.push(setInterval((()=>{R()}),1e3)):o===El&&oe(),"play"===o)Nn.onServerChange((n=>{n[0],n[1],n[2];const o=n[3];for(const[l,a]of o)switch(l){case Cn:{const n=ae.decodePlayer(a);n.id!==t&&(sl.setPlayer(e,n.id,n),Nl=!0)}break;case bn:{const t=ae.decodePiece(a);sl.setPiece(e,t.idx,t),Nl=!0}break;case wn:sl.setPuzzleData(e,a),Nl=!0}j=!!sl.getFinishTs(e)}));else if(o===El){const t=(t,n)=>{const o=t;if(o[0]===Zt){const t=o[1];return sl.addPlayer(e,t,n),!0}if(o[0]===Xt){const t=sl.getPlayerIdByIndex(e,o[1]);if(!t)throw"[ 2021-05-17 player not found (update player) ]";return sl.addPlayer(e,t,n),!0}if(o[0]===Jt){const t=sl.getPlayerIdByIndex(e,o[1]);if(!t)throw"[ 2021-05-17 player not found (handle input) ]";const l=o[2];return sl.handleInput(e,t,l,n),!0}return!1};let n=w.lastGameTs;const o=async()=>{w.logPointer+1>=w.log.length&&await b(e);const l=L();if(w.paused)return w.lastRealTs=l,void(de=setTimeout(o,50));const a=(l-w.lastRealTs)*w.speeds[w.speedIdx];let s=w.lastGameTs+a;for(;;){if(w.paused)break;const e=w.logPointer+1;if(e>=w.log.length)break;const o=w.log[w.logPointer],l=n+o[o.length-1],a=w.log[e],i=a[a.length-1],r=l+i;if(r>s){s+500*${let t=!1;const n=e.fps||60,o=e.slow||1,l=e.update,a=e.render,s=window.requestAnimationFrame,i=1/n,r=o*i;let d,c=0,u=window.performance.now();const p=()=>{for(d=window.performance.now(),c+=Math.min(1,(d-u)/1e3);c>r;)c-=r,l(i);a(c/o),u=d,t||s(p)};return s(p),{stop:()=>{t=!0}}})({update:()=>{B.createKeyEvents();for(const n of B.consumeAll())if("play"===o){const o=n[0];if(o===en){const e=n[1],t=n[2],o=V.worldDimToViewport({w:e,h:t});Nl=!0,V.move(o.w,o.h)}else if(o===on){if(ue&&!sl.getFirstOwnedPiece(e,t)){const e={x:n[1],y:n[2]},t=V.worldToViewport(e),o=Math.round(t.x-ue.x),l=Math.round(t.y-ue.y);Nl=!0,V.move(o,l),ue=t}}else if(o===rn)ne(n[1]);else if(o===tn){const e={x:n[1],y:n[2]};ue=V.worldToViewport(e),te(!0)}else if(o===nn)ue=null,te(!1);else if(o===ln){const e={x:n[1],y:n[2]};Nl=!0,V.zoom("in",V.worldToViewport(e))}else if(o===an){const e={x:n[1],y:n[2]};Nl=!0,V.zoom("out",V.worldToViewport(e))}else o===cn?a.togglePreview():o===un?a.toggleSoundsEnabled():o===mn?a.togglePlayerNames():o===yn?O():o===fn?(Ml=!Ml,Nl=!0):o===vn&&(Dl=!Dl,Nl=!0);const l=C();sl.handleInput(e,t,n,l,(e=>{K()&&Y()})).length>0&&(Nl=!0),Nn.sendClientEvent(n)}else if(o===El){const e=n[0];if(e===pn)ie();else if(e===hn)se();else if(e===gn)le();else if(e===en){const e=n[1],t=n[2];Nl=!0,V.move(e,t)}else if(e===on){if(ue){const e={x:n[1],y:n[2]},t=V.worldToViewport(e),o=Math.round(t.x-ue.x),l=Math.round(t.y-ue.y);Nl=!0,V.move(o,l),ue=t}}else if(e===rn)ne(n[1]);else if(e===tn){const e={x:n[1],y:n[2]};ue=V.worldToViewport(e),te(!0)}else if(e===nn)ue=null,te(!1);else if(e===ln){const e={x:n[1],y:n[2]};Nl=!0,V.zoom("in",V.worldToViewport(e))}else if(e===an){const e={x:n[1],y:n[2]};Nl=!0,V.zoom("out",V.worldToViewport(e))}else e===cn?a.togglePreview():e===un?a.toggleSoundsEnabled():e===mn?a.togglePlayerNames():e===yn?O():e===fn?(Ml=!Ml,Nl=!0):e===vn&&(Dl=!Dl,Nl=!0)}j=!!sl.getFinishTs(e),W()&&(N.update(),Nl=!0)},render:async()=>{if(!Nl)return;const n=C();let l,s,i;window.DEBUG&&ho(0),_.fillStyle=Q(),_.fillRect(0,0,v.width,v.height),window.DEBUG&&mo("clear done"),l=V.worldToViewportRaw(I),s=V.worldDimToViewportRaw(E),_.fillStyle="rgba(255, 255, 255, .3)",_.fillRect(l.x,l.y,s.w,s.h),window.DEBUG&&mo("board done");const r=sl.getPiecesSortedByZIndex(e);window.DEBUG&&mo("get tiles done"),s=V.worldDimToViewportRaw(M);for(const e of r)(-1===e.owner?Ml:Dl)&&(i=D[e.idx],l=V.worldToViewportRaw({x:k+e.pos.x,y:k+e.pos.y}),_.drawImage(i,0,0,i.width,i.height,l.x,l.y,s.w,s.h));window.DEBUG&&mo("tiles done");const d=[];for(const a of sl.getActivePlayers(e,n))c=a,(o===El||c.id!==t)&&(i=await f(a),l=V.worldToViewport(a),_.drawImage(i,l.x-g,l.y-m),q()&&d.push([`${a.name} (${a.points})`,l.x,l.y+h]));var c;_.fillStyle="white",_.textAlign="center";for(const[e,t,o]of d)_.fillText(e,t,o);window.DEBUG&&mo("players done"),a.setActivePlayers(sl.getActivePlayers(e,n)),a.setIdlePlayers(sl.getIdlePlayers(e,n)),a.setPiecesDone(sl.getFinishedPiecesCount(e)),window.DEBUG&&mo("HUD done"),W()&&N.render(),Nl=!1}}),{setHotkeys:e=>{B.setHotkeys(e)},onBgChange:e=>{Sl(yl,e),B.addEvent([sn,e])},onColorChange:e=>{Sl(fl,e),B.addEvent([rn,e])},onNameChange:e=>{Sl(vl,e),B.addEvent([dn,e])},onSoundsEnabledChange:e=>{Pl(ml,e)},onSoundsVolumeChange:e=>{xl(hl,e),Y()},onShowPlayerNamesChange:e=>{Pl(wl,e)},replayOnSpeedUp:le,replayOnSpeedDown:se,replayOnPauseToggle:ie,previewImageUrl:U,player:{background:Q(),color:Z(),name:o===El?zl(vl,"anon"):sl.getPlayerName(e,t)||zl(vl,"anon"),soundsEnabled:K(),soundsVolume:H(),showPlayerNames:q()},game:sl.get(e),disconnect:Nn.disconnect,connect:x,unload:()=>{re.forEach((e=>{clearInterval(e)})),de&&clearTimeout(de),ce&&ce.stop()}}}var Vl=e({name:"game",components:{PuzzleStatus:zt,Scores:xt,SettingsOverlay:It,PreviewOverlay:Rt,InfoOverlay:Gt,ConnectionOverlay:_n,HelpOverlay:$n},data:()=>({activePlayers:[],idlePlayers:[],finished:!1,duration:0,piecesDone:0,piecesTotal:0,overlay:"",connectionState:0,cuttingPuzzle:!0,g:{player:{background:"",color:"",name:"",soundsEnabled:!1,soundsVolume:100,showPlayerNames:!0},game:null,previewImageUrl:"",setHotkeys:e=>{},onBgChange:e=>{},onColorChange:e=>{},onNameChange:e=>{},onSoundsEnabledChange:e=>{},onSoundsVolumeChange:e=>{},onShowPlayerNamesChange:e=>{},connect:()=>{},disconnect:()=>{},unload:()=>{}}}),async mounted(){this.$route.params.id&&(this.$watch((()=>this.g.player.background),(e=>{this.g.onBgChange(e)})),this.$watch((()=>this.g.player.color),(e=>{this.g.onColorChange(e)})),this.$watch((()=>this.g.player.name),(e=>{this.g.onNameChange(e)})),this.$watch((()=>this.g.player.soundsEnabled),(e=>{this.g.onSoundsEnabledChange(e)})),this.$watch((()=>this.g.player.soundsVolume),(e=>{this.g.onSoundsVolumeChange(e)})),this.$watch((()=>this.g.player.showPlayerNames),(e=>{this.g.onShowPlayerNamesChange(e)})),this.g=await _l(`${this.$route.params.id}`,this.$clientId,this.$config.WS_ADDRESS,"play",this.$el,{setPuzzleCut:()=>{this.cuttingPuzzle=!1},setActivePlayers:e=>{this.activePlayers=e},setIdlePlayers:e=>{this.idlePlayers=e},setFinished:e=>{this.finished=e},setDuration:e=>{this.duration=e},setPiecesDone:e=>{this.piecesDone=e},setPiecesTotal:e=>{this.piecesTotal=e},togglePreview:()=>{this.toggle("preview",!1)},setConnectionState:e=>{this.connectionState=e},toggleSoundsEnabled:()=>{this.g.player.soundsEnabled=!this.g.player.soundsEnabled},togglePlayerNames:()=>{this.g.player.showPlayerNames=!this.g.player.showPlayerNames}}))},unmounted(){this.g.unload(),this.g.disconnect()},methods:{reconnect(){this.g.connect()},toggle(e,t){""===this.overlay?(this.overlay=e,t&&this.g.setHotkeys(!1)):(this.overlay="",t&&this.g.setHotkeys(!0))}}});const Ol={id:"game"},Bl={key:1,class:"overlay"},Ul=n("div",{class:"overlay-content"},[n("div",null,"⏳ Cutting puzzle, please wait... ⏳")],-1),Rl={class:"menu"},$l={class:"tabs"},Gl=i("🧩 Puzzles");Vl.render=function(e,i,r,d,c,u){const g=a("settings-overlay"),h=a("preview-overlay"),m=a("info-overlay"),y=a("help-overlay"),f=a("connection-overlay"),v=a("puzzle-status"),w=a("router-link"),b=a("scores");return s(),t("div",Ol,[p(n(g,{onBgclick:i[1]||(i[1]=t=>e.toggle("settings",!0)),modelValue:e.g.player,"onUpdate:modelValue":i[2]||(i[2]=t=>e.g.player=t)},null,8,["modelValue"]),[[x,"settings"===e.overlay]]),p(n(h,{onBgclick:i[3]||(i[3]=t=>e.toggle("preview",!1)),img:e.g.previewImageUrl},null,8,["img"]),[[x,"preview"===e.overlay]]),e.g.game?p((s(),t(m,{key:0,onBgclick:i[4]||(i[4]=t=>e.toggle("info",!0)),game:e.g.game},null,8,["game"])),[[x,"info"===e.overlay]]):l("",!0),p(n(y,{onBgclick:i[5]||(i[5]=t=>e.toggle("help",!0))},null,512),[[x,"help"===e.overlay]]),e.cuttingPuzzle?(s(),t("div",Bl,[Ul])):l("",!0),n(f,{connectionState:e.connectionState,onReconnect:e.reconnect},null,8,["connectionState","onReconnect"]),n(v,{finished:e.finished,duration:e.duration,piecesDone:e.piecesDone,piecesTotal:e.piecesTotal},null,8,["finished","duration","piecesDone","piecesTotal"]),n("div",Rl,[n("div",$l,[n(w,{class:"opener",to:{name:"index"},target:"_blank"},{default:o((()=>[Gl])),_:1}),n("div",{class:"opener",onClick:i[6]||(i[6]=t=>e.toggle("preview",!1))},"🖼️ Preview"),n("div",{class:"opener",onClick:i[7]||(i[7]=t=>e.toggle("settings",!0))},"🛠️ Settings"),n("div",{class:"opener",onClick:i[8]||(i[8]=t=>e.toggle("info",!0))},"ℹ️ Info"),n("div",{class:"opener",onClick:i[9]||(i[9]=t=>e.toggle("help",!0))},"⌨️ Hotkeys")])]),n(b,{activePlayers:e.activePlayers,idlePlayers:e.idlePlayers},null,8,["activePlayers","idlePlayers"])])};var Ll=e({name:"replay",components:{PuzzleStatus:zt,Scores:xt,SettingsOverlay:It,PreviewOverlay:Rt,InfoOverlay:Gt,HelpOverlay:$n},data:()=>({activePlayers:[],idlePlayers:[],finished:!1,duration:0,piecesDone:0,piecesTotal:0,overlay:"",connectionState:0,cuttingPuzzle:!0,g:{player:{background:"",color:"",name:"",soundsEnabled:!1,soundsVolume:100,showPlayerNames:!0},game:null,previewImageUrl:"",setHotkeys:e=>{},onBgChange:e=>{},onColorChange:e=>{},onNameChange:e=>{},onSoundsEnabledChange:e=>{},onSoundsVolumeChange:e=>{},onShowPlayerNamesChange:e=>{},replayOnSpeedUp:()=>{},replayOnSpeedDown:()=>{},replayOnPauseToggle:()=>{},connect:()=>{},disconnect:()=>{},unload:()=>{}},replay:{speed:1,paused:!1}}),async mounted(){this.$route.params.id&&(this.$watch((()=>this.g.player.background),(e=>{this.g.onBgChange(e)})),this.$watch((()=>this.g.player.color),(e=>{this.g.onColorChange(e)})),this.$watch((()=>this.g.player.name),(e=>{this.g.onNameChange(e)})),this.$watch((()=>this.g.player.soundsEnabled),(e=>{this.g.onSoundsEnabledChange(e)})),this.$watch((()=>this.g.player.soundsVolume),(e=>{this.g.onSoundsVolumeChange(e)})),this.$watch((()=>this.g.player.showPlayerNames),(e=>{this.g.onShowPlayerNamesChange(e)})),this.g=await _l(`${this.$route.params.id}`,this.$clientId,this.$config.WS_ADDRESS,El,this.$el,{setPuzzleCut:()=>{this.cuttingPuzzle=!1},setActivePlayers:e=>{this.activePlayers=e},setIdlePlayers:e=>{this.idlePlayers=e},setFinished:e=>{this.finished=e},setDuration:e=>{this.duration=e},setPiecesDone:e=>{this.piecesDone=e},setPiecesTotal:e=>{this.piecesTotal=e},togglePreview:()=>{this.toggle("preview",!1)},setConnectionState:e=>{this.connectionState=e},setReplaySpeed:e=>{this.replay.speed=e},setReplayPaused:e=>{this.replay.paused=e},toggleSoundsEnabled:()=>{this.g.player.soundsEnabled=!this.g.player.soundsEnabled},togglePlayerNames:()=>{this.g.player.showPlayerNames=!this.g.player.showPlayerNames}}))},unmounted(){this.g.unload(),this.g.disconnect()},methods:{toggle(e,t){""===this.overlay?(this.overlay=e,t&&this.g.setHotkeys(!1)):(this.overlay="",t&&this.g.setHotkeys(!0))}},computed:{replayText(){return"Replay-Speed: "+this.replay.speed+"x"+(this.replay.paused?" Paused":"")}}});const Fl={id:"replay"},jl={key:1,class:"overlay"},Wl=n("div",{class:"overlay-content"},[n("div",null,"⏳ Cutting puzzle, please wait... ⏳")],-1),Hl={class:"menu"},Kl={class:"tabs"},ql=i("🧩 Puzzles");Ll.render=function(e,i,d,c,u,g){const h=a("settings-overlay"),m=a("preview-overlay"),y=a("info-overlay"),f=a("help-overlay"),v=a("puzzle-status"),w=a("router-link"),b=a("scores");return s(),t("div",Fl,[p(n(h,{onBgclick:i[1]||(i[1]=t=>e.toggle("settings",!0)),modelValue:e.g.player,"onUpdate:modelValue":i[2]||(i[2]=t=>e.g.player=t)},null,8,["modelValue"]),[[x,"settings"===e.overlay]]),p(n(m,{onBgclick:i[3]||(i[3]=t=>e.toggle("preview",!1)),img:e.g.previewImageUrl},null,8,["img"]),[[x,"preview"===e.overlay]]),e.g.game?p((s(),t(y,{key:0,onBgclick:i[4]||(i[4]=t=>e.toggle("info",!0)),game:e.g.game},null,8,["game"])),[[x,"info"===e.overlay]]):l("",!0),p(n(f,{onBgclick:i[5]||(i[5]=t=>e.toggle("help",!0))},null,512),[[x,"help"===e.overlay]]),e.cuttingPuzzle?(s(),t("div",jl,[Wl])):l("",!0),n(v,{finished:e.finished,duration:e.duration,piecesDone:e.piecesDone,piecesTotal:e.piecesTotal},{default:o((()=>[n("div",null,[n("div",null,r(e.replayText),1),n("button",{class:"btn",onClick:i[6]||(i[6]=t=>e.g.replayOnSpeedUp())},"⏫"),n("button",{class:"btn",onClick:i[7]||(i[7]=t=>e.g.replayOnSpeedDown())},"⏬"),n("button",{class:"btn",onClick:i[8]||(i[8]=t=>e.g.replayOnPauseToggle())},"⏸️")])])),_:1},8,["finished","duration","piecesDone","piecesTotal"]),n("div",Hl,[n("div",Kl,[n(w,{class:"opener",to:{name:"index"},target:"_blank"},{default:o((()=>[ql])),_:1}),n("div",{class:"opener",onClick:i[9]||(i[9]=t=>e.toggle("preview",!1))},"🖼️ Preview"),n("div",{class:"opener",onClick:i[10]||(i[10]=t=>e.toggle("settings",!0))},"🛠️ Settings"),n("div",{class:"opener",onClick:i[11]||(i[11]=t=>e.toggle("info",!0))},"ℹ️ Info"),n("div",{class:"opener",onClick:i[12]||(i[12]=t=>e.toggle("help",!0))},"⌨️ Hotkeys")])]),n(b,{activePlayers:e.activePlayers,idlePlayers:e.idlePlayers},null,8,["activePlayers","idlePlayers"])])},(async()=>{const e=function(){let e=zl("ID","");return e||(e=ae.uniqId(),Sl("ID",e)),e}(),t=function(){let e=zl("SECRET","");return e||(e=ae.uniqId(),Sl("SECRET",e)),e}();O(e),B(t);const n=await _("/api/me",{}),o=await n.json(),l=await _("/api/conf",{}),a=await l.json(),s=k({history:P(),routes:[{name:"index",path:"/",component:Z},{name:"new-game",path:"/new-game",component:pt},{name:"game",path:"/g/:id",component:Vl},{name:"replay",path:"/replay/:id",component:Ll}]});s.beforeEach(((e,t)=>{t.name&&document.documentElement.classList.remove(`view-${String(t.name)}`),document.documentElement.classList.add(`view-${String(e.name)}`)}));const i=A(S);i.config.globalProperties.$me=o,i.config.globalProperties.$config=a,i.config.globalProperties.$clientId=e,i.use(s),i.mount("#app")})(); diff --git a/build/public/assets/index.f7304069.css b/build/public/assets/index.f7304069.css deleted file mode 100644 index c494a4e..0000000 --- a/build/public/assets/index.f7304069.css +++ /dev/null @@ -1 +0,0 @@ -:root{--main-color:#c1b19f;--main-darker-color:#4f4e4c;--link-color:#808db0;--link-hover-color:#c5cfeb;--highlight-color:#dd7e7e;--positive-color:#64a756;--input-bg-color:#262523;--bg-color:rgba(0,0,0,.7)}body,html{margin:0;background:#2b2b2b;color:var(--main-color);height:100%}*{font-family:monospace;font-size:15px}h1,h2,h3,h4{font-size:20px}a{color:var(--link-color);text-decoration:none}a:hover{color:var(--link-hover-color)}td,th{vertical-align:top}.btn{display:inline-block;background:var(--input-bg-color);color:var(--link-color);border:solid 1px #000;padding:5px 10px;box-shadow:1px 1px 2px rgba(0,0,0,.5),0 0 1px rgba(150,150,150,.4) inset;border-radius:4px;user-select:none}.btn-big{font-size:1.5em;padding:10px 20px}.btn:hover{background:#2f2e2c;color:var(--link-hover-color);border:solid 1px #111;box-shadow:0 0 1px rgba(150,150,150,.4) inset;cursor:pointer}.btn:disabled{background:#2f2e2c;color:#8c4747!important;border:solid 1px #111;box-shadow:0 0 1px rgba(150,150,150,.4) inset;cursor:not-allowed}input{background:#333230;border-radius:4px;color:var(--main-color);padding:6px 10px;border:solid 1px #000;box-shadow:0 0 3px rgba(0,0,0,.3) inset}input:focus{border:solid 1px #686767;background:var(--input-bg-color)}.scores{position:absolute;right:0;top:0;background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7)}.timer{position:absolute;left:0;top:0;background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7)}.menu{position:absolute;top:0;left:50%;transform:translateX(-50%);background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7);z-index:2}.closed{display:none}.overlay{position:absolute;top:0;left:0;right:0;bottom:0;z-index:10;background:var(--bg-color)}.overlay.transparent{background:0 0}.overlay-content{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);background:var(--bg-color);padding:5px;border:solid 1px #000;box-shadow:0 0 10px 0 rgba(0,0,0,.7);z-index:1}.connection-lost .overlay-content{padding:20px;text-align:center}.preview{position:absolute;top:20px;left:20px;bottom:20px;right:20px}.preview .img{height:100%;width:100%;position:absolute;background-repeat:no-repeat;background-position:center;background-size:contain}.menu .opener{display:inline-block;margin-right:10px;color:var(--link-color)}.menu .opener:last-child{margin-right:0}.menu .opener:hover{color:var(--link-hover-color);cursor:pointer}kbd{background-color:#eee;border-radius:3px;border:1px solid #b4b4b4;box-shadow:0 1px 1px rgba(0,0,0,.2),0 2px 0 0 rgba(255,255,255,.7) inset;color:#333;display:inline-block;font-size:.85em;font-weight:700;line-height:1;padding:2px 4px;white-space:nowrap}.hint{color:var(--main-darker-color)}.bit{background:#3b3737;border-radius:.5em;padding:.25em .5em;display:inline-block;margin:0 .25em .25em 0;cursor:pointer}.bit.on{color:var(--positive-color)}.upload-image-teaser{text-align:center}.upload-image-teaser .btn{margin-bottom:.5em}table label{line-height:32px}.nav{list-style:none;padding:0}.nav li{display:inline-block;margin-right:1em}.image-list{overflow:scroll}.image-list-inner{white-space:nowrap}.imageteaser{width:150px;height:100px;display:inline-block;margin:5px;background-size:contain;background-position:center;background-repeat:no-repeat;background-color:#222;cursor:pointer}.game-teaser-wrap{display:inline-block;width:20%;padding:5px;box-sizing:border-box}.game-teaser{display:block;background-repeat:no-repeat;background-position:center;background-size:contain;position:relative;padding-top:56.25%;width:100%;background-color:#222}.game-info{position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%}.game-info-text{position:absolute;top:0;background:var(--bg-color);padding:5px}.game-replay{position:absolute;top:0;right:0}html.view-game{overflow:hidden}html.view-game body{overflow:hidden}html.view-replay{overflow:hidden}html.view-replay body{overflow:hidden}.imageteaser{position:relative}.imageteaser .edit{display:none;position:absolute}.imageteaser:hover .edit{display:inline-block}.input[data-v-771460ae]{margin-bottom:.5em}.new-image-dialog .overlay-content{display:grid;grid-template-columns:auto 450px;grid-template-rows:auto;grid-template-areas:"image settings" "image buttons";height:90%;width:80%}.new-image-dialog .area-image{grid-area:image;margin:20px}.new-image-dialog .area-image.no-image{align-content:center;display:grid;text-align:center;border:dashed 6px;position:relative}.new-image-dialog .area-image .has-image{position:relative;width:100%;height:100%}.new-image-dialog .area-image .has-image .remove{position:absolute;top:.5em;left:.5em}.new-image-dialog .area-settings{grid-area:settings}.new-image-dialog .area-settings table input[type=text]{width:100%;box-sizing:border-box}.new-image-dialog .area-buttons{align-self:end;grid-area:buttons}.new-image-dialog .area-buttons button{width:100%;margin-top:.5em}.new-image-dialog .upload{position:absolute;top:0;left:0;right:0;bottom:0;cursor:pointer}.new-image-dialog .upload .btn{position:absolute;top:50%;transform:translate(-50%,-50%)}.edit-image-dialog .overlay-content{display:grid;grid-template-columns:auto 450px;grid-template-rows:auto;grid-template-areas:"image settings" "image buttons";height:90%;width:80%}.edit-image-dialog .area-image{grid-area:image;margin:20px}.edit-image-dialog .area-image.no-image{align-content:center;display:grid;text-align:center;border:dashed 6px;position:relative}.edit-image-dialog .area-image .has-image{position:relative;width:100%;height:100%}.edit-image-dialog .area-image .has-image .remove{position:absolute;top:.5em;left:.5em}.edit-image-dialog .area-settings{grid-area:settings}.edit-image-dialog .area-settings table input[type=text]{width:100%;box-sizing:border-box}.edit-image-dialog .area-buttons{align-self:end;grid-area:buttons}.edit-image-dialog .area-buttons button{width:100%;margin-top:.5em}.new-game-dialog .overlay-content{display:grid;grid-template-columns:auto 450px;grid-template-rows:auto;grid-template-areas:"image settings" "image buttons";height:90%;width:80%}.new-game-dialog .area-image{grid-area:image;margin:20px}.new-game-dialog .area-settings{grid-area:settings}.new-game-dialog .area-settings table input[type=text]{width:100%;box-sizing:border-box}.new-game-dialog .area-buttons{align-self:end;grid-area:buttons}.new-game-dialog .area-buttons button{width:100%}.new-game-dialog .has-image{position:relative;width:100%;height:100%}.new-game-dialog .has-image .remove{position:absolute;top:.5em;left:.5em} \ No newline at end of file diff --git a/build/public/assets/vendor.684f7bc8.js b/build/public/assets/vendor.684f7bc8.js new file mode 100644 index 0000000..ab0bce8 --- /dev/null +++ b/build/public/assets/vendor.684f7bc8.js @@ -0,0 +1,6 @@ +function e(e,t){const n=Object.create(null),r=e.split(",");for(let o=0;o!!n[e.toLowerCase()]:e=>!!n[e]}const t=e("Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt"),n=e("itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly");function r(e){if(E(e)){const t={};for(let n=0;n{if(e){const n=e.split(s);n.length>1&&(t[n[0].trim()]=n[1].trim())}})),t}function i(e){let t="";if(R(e))t=e;else if(E(e))for(let n=0;nc(e,t)))}const u=e=>null==e?"":P(e)?JSON.stringify(e,f,2):String(e),f=(e,t)=>k(t)?{[`Map(${t.size})`]:[...t.entries()].reduce(((e,[t,n])=>(e[`${t} =>`]=n,e)),{})}:S(t)?{[`Set(${t.size})`]:[...t.values()]}:!P(t)||E(t)||M(t)?t:String(t),p={},d=[],h=()=>{},m=()=>!1,g=/^on[^a-z]/,v=e=>g.test(e),y=e=>e.startsWith("onUpdate:"),b=Object.assign,_=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},w=Object.prototype.hasOwnProperty,x=(e,t)=>w.call(e,t),E=Array.isArray,k=e=>"[object Map]"===$(e),S=e=>"[object Set]"===$(e),O=e=>e instanceof Date,C=e=>"function"==typeof e,R=e=>"string"==typeof e,A=e=>"symbol"==typeof e,P=e=>null!==e&&"object"==typeof e,F=e=>P(e)&&C(e.then)&&C(e.catch),j=Object.prototype.toString,$=e=>j.call(e),M=e=>"[object Object]"===$(e),I=e=>R(e)&&"NaN"!==e&&"-"!==e[0]&&""+parseInt(e,10)===e,T=e(",key,ref,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),V=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},U=/-(\w)/g,N=V((e=>e.replace(U,((e,t)=>t?t.toUpperCase():"")))),L=/\B([A-Z])/g,B=V((e=>e.replace(L,"-$1").toLowerCase())),D=V((e=>e.charAt(0).toUpperCase()+e.slice(1))),q=V((e=>e?`on${D(e)}`:"")),z=(e,t)=>e!==t&&(e==e||t==t),W=(e,t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},G=e=>{const t=parseFloat(e);return isNaN(t)?e:t},H=new WeakMap,X=[];let J;const Q=Symbol(""),Y=Symbol("");function Z(e,t=p){(function(e){return e&&!0===e._isEffect})(e)&&(e=e.raw);const n=function(e,t){const n=function(){if(!n.active)return t.scheduler?void 0:e();if(!X.includes(n)){ne(n);try{return oe.push(re),re=!0,X.push(n),J=n,e()}finally{X.pop(),le(),J=X[X.length-1]}}};return n.id=te++,n.allowRecurse=!!t.allowRecurse,n._isEffect=!0,n.active=!0,n.raw=e,n.deps=[],n.options=t,n}(e,t);return t.lazy||n(),n}function ee(e){e.active&&(ne(e),e.options.onStop&&e.options.onStop(),e.active=!1)}let te=0;function ne(e){const{deps:t}=e;if(t.length){for(let n=0;n{e&&e.forEach((e=>{(e!==J||e.allowRecurse)&&i.add(e)}))};if("clear"===t)l.forEach(c);else if("length"===n&&E(e))l.forEach(((e,t)=>{("length"===t||t>=r)&&c(e)}));else switch(void 0!==n&&c(l.get(n)),t){case"add":E(e)?I(n)&&c(l.get("length")):(c(l.get(Q)),k(e)&&c(l.get(Y)));break;case"delete":E(e)||(c(l.get(Q)),k(e)&&c(l.get(Y)));break;case"set":k(e)&&c(l.get(Q))}i.forEach((e=>{e.options.scheduler?e.options.scheduler(e):e()}))}const ae=e("__proto__,__v_isRef,__isVue"),ue=new Set(Object.getOwnPropertyNames(Symbol).map((e=>Symbol[e])).filter(A)),fe=ge(),pe=ge(!1,!0),de=ge(!0),he=ge(!0,!0),me={};function ge(e=!1,t=!1){return function(n,r,o){if("__v_isReactive"===r)return!e;if("__v_isReadonly"===r)return e;if("__v_raw"===r&&o===(e?t?Ke:We:t?ze:qe).get(n))return n;const s=E(n);if(!e&&s&&x(me,r))return Reflect.get(me,r,o);const l=Reflect.get(n,r,o);if(A(r)?ue.has(r):ae(r))return l;if(e||ie(n,0,r),t)return l;if(nt(l)){return!s||!I(r)?l.value:l}return P(l)?e?Xe(l):He(l):l}}["includes","indexOf","lastIndexOf"].forEach((e=>{const t=Array.prototype[e];me[e]=function(...e){const n=et(this);for(let t=0,o=this.length;t{const t=Array.prototype[e];me[e]=function(...e){se();const n=t.apply(this,e);return le(),n}}));function ve(e=!1){return function(t,n,r,o){let s=t[n];if(!e&&(r=et(r),s=et(s),!E(t)&&nt(s)&&!nt(r)))return s.value=r,!0;const l=E(t)&&I(n)?Number(n)!0,deleteProperty:(e,t)=>!0},_e=b({},ye,{get:pe,set:ve(!0)});b({},be,{get:he});const we=e=>P(e)?He(e):e,xe=e=>P(e)?Xe(e):e,Ee=e=>e,ke=e=>Reflect.getPrototypeOf(e);function Se(e,t,n=!1,r=!1){const o=et(e=e.__v_raw),s=et(t);t!==s&&!n&&ie(o,0,t),!n&&ie(o,0,s);const{has:l}=ke(o),i=r?Ee:n?xe:we;return l.call(o,t)?i(e.get(t)):l.call(o,s)?i(e.get(s)):void 0}function Oe(e,t=!1){const n=this.__v_raw,r=et(n),o=et(e);return e!==o&&!t&&ie(r,0,e),!t&&ie(r,0,o),e===o?n.has(e):n.has(e)||n.has(o)}function Ce(e,t=!1){return e=e.__v_raw,!t&&ie(et(e),0,Q),Reflect.get(e,"size",e)}function Re(e){e=et(e);const t=et(this);return ke(t).has.call(t,e)||(t.add(e),ce(t,"add",e,e)),this}function Ae(e,t){t=et(t);const n=et(this),{has:r,get:o}=ke(n);let s=r.call(n,e);s||(e=et(e),s=r.call(n,e));const l=o.call(n,e);return n.set(e,t),s?z(t,l)&&ce(n,"set",e,t):ce(n,"add",e,t),this}function Pe(e){const t=et(this),{has:n,get:r}=ke(t);let o=n.call(t,e);o||(e=et(e),o=n.call(t,e)),r&&r.call(t,e);const s=t.delete(e);return o&&ce(t,"delete",e,void 0),s}function Fe(){const e=et(this),t=0!==e.size,n=e.clear();return t&&ce(e,"clear",void 0,void 0),n}function je(e,t){return function(n,r){const o=this,s=o.__v_raw,l=et(s),i=t?Ee:e?xe:we;return!e&&ie(l,0,Q),s.forEach(((e,t)=>n.call(r,i(e),i(t),o)))}}function $e(e,t,n){return function(...r){const o=this.__v_raw,s=et(o),l=k(s),i="entries"===e||e===Symbol.iterator&&l,c="keys"===e&&l,a=o[e](...r),u=n?Ee:t?xe:we;return!t&&ie(s,0,c?Y:Q),{next(){const{value:e,done:t}=a.next();return t?{value:e,done:t}:{value:i?[u(e[0]),u(e[1])]:u(e),done:t}},[Symbol.iterator](){return this}}}}function Me(e){return function(...t){return"delete"!==e&&this}}const Ie={get(e){return Se(this,e)},get size(){return Ce(this)},has:Oe,add:Re,set:Ae,delete:Pe,clear:Fe,forEach:je(!1,!1)},Te={get(e){return Se(this,e,!1,!0)},get size(){return Ce(this)},has:Oe,add:Re,set:Ae,delete:Pe,clear:Fe,forEach:je(!1,!0)},Ve={get(e){return Se(this,e,!0)},get size(){return Ce(this,!0)},has(e){return Oe.call(this,e,!0)},add:Me("add"),set:Me("set"),delete:Me("delete"),clear:Me("clear"),forEach:je(!0,!1)},Ue={get(e){return Se(this,e,!0,!0)},get size(){return Ce(this,!0)},has(e){return Oe.call(this,e,!0)},add:Me("add"),set:Me("set"),delete:Me("delete"),clear:Me("clear"),forEach:je(!0,!0)};function Ne(e,t){const n=t?e?Ue:Te:e?Ve:Ie;return(t,r,o)=>"__v_isReactive"===r?!e:"__v_isReadonly"===r?e:"__v_raw"===r?t:Reflect.get(x(n,r)&&r in t?n:t,r,o)}["keys","values","entries",Symbol.iterator].forEach((e=>{Ie[e]=$e(e,!1,!1),Ve[e]=$e(e,!0,!1),Te[e]=$e(e,!1,!0),Ue[e]=$e(e,!0,!0)}));const Le={get:Ne(!1,!1)},Be={get:Ne(!1,!0)},De={get:Ne(!0,!1)},qe=new WeakMap,ze=new WeakMap,We=new WeakMap,Ke=new WeakMap;function Ge(e){return e.__v_skip||!Object.isExtensible(e)?0:function(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}((e=>$(e).slice(8,-1))(e))}function He(e){return e&&e.__v_isReadonly?e:Je(e,!1,ye,Le,qe)}function Xe(e){return Je(e,!0,be,De,We)}function Je(e,t,n,r,o){if(!P(e))return e;if(e.__v_raw&&(!t||!e.__v_isReactive))return e;const s=o.get(e);if(s)return s;const l=Ge(e);if(0===l)return e;const i=new Proxy(e,2===l?r:n);return o.set(e,i),i}function Qe(e){return Ye(e)?Qe(e.__v_raw):!(!e||!e.__v_isReactive)}function Ye(e){return!(!e||!e.__v_isReadonly)}function Ze(e){return Qe(e)||Ye(e)}function et(e){return e&&et(e.__v_raw)||e}const tt=e=>P(e)?He(e):e;function nt(e){return Boolean(e&&!0===e.__v_isRef)}class rt{constructor(e,t=!1){this._rawValue=e,this._shallow=t,this.__v_isRef=!0,this._value=t?e:tt(e)}get value(){return ie(et(this),0,"value"),this._value}set value(e){z(et(e),this._rawValue)&&(this._rawValue=e,this._value=this._shallow?e:tt(e),ce(et(this),"set","value",e))}}function ot(e,t=!1){return nt(e)?e:new rt(e,t)}function st(e){return nt(e)?e.value:e}const lt={get:(e,t,n)=>st(Reflect.get(e,t,n)),set:(e,t,n,r)=>{const o=e[t];return nt(o)&&!nt(n)?(o.value=n,!0):Reflect.set(e,t,n,r)}};function it(e){return Qe(e)?e:new Proxy(e,lt)}class ct{constructor(e,t){this._object=e,this._key=t,this.__v_isRef=!0}get value(){return this._object[this._key]}set value(e){this._object[this._key]=e}}class at{constructor(e,t,n){this._setter=t,this._dirty=!0,this.__v_isRef=!0,this.effect=Z(e,{lazy:!0,scheduler:()=>{this._dirty||(this._dirty=!0,ce(et(this),"set","value"))}}),this.__v_isReadonly=n}get value(){const e=et(this);return e._dirty&&(e._value=this.effect(),e._dirty=!1),ie(e,0,"value"),e._value}set value(e){this._setter(e)}}function ut(e,t,n,r){let o;try{o=r?e(...r):e()}catch(s){pt(s,t,n)}return o}function ft(e,t,n,r){if(C(e)){const o=ut(e,t,n,r);return o&&F(o)&&o.catch((e=>{pt(e,t,n)})),o}const o=[];for(let s=0;s>>1;jt(mt[e])-1?mt.splice(t,0,e):mt.push(e),Rt()}}function Rt(){dt||ht||(ht=!0,kt=Et.then($t))}function At(e,t,n,r){E(e)?n.push(...e):t&&t.includes(e,e.allowRecurse?r+1:r)||n.push(e),Rt()}function Pt(e,t=null){if(vt.length){for(St=t,yt=[...new Set(vt)],vt.length=0,bt=0;btjt(e)-jt(t))),xt=0;xtnull==e.id?1/0:e.id;function $t(e){ht=!1,dt=!0,Pt(e),mt.sort(((e,t)=>jt(e)-jt(t)));try{for(gt=0;gte.trim())):t&&(o=n.map(G))}let i,c=r[i=q(t)]||r[i=q(N(t))];!c&&s&&(c=r[i=q(B(t))]),c&&ft(c,e,6,o);const a=r[i+"Once"];if(a){if(e.emitted){if(e.emitted[i])return}else(e.emitted={})[i]=!0;ft(a,e,6,o)}}function It(e,t,n=!1){if(!t.deopt&&void 0!==e.__emits)return e.__emits;const r=e.emits;let o={},s=!1;if(!C(e)){const r=e=>{const n=It(e,t,!0);n&&(s=!0,b(o,n))};!n&&t.mixins.length&&t.mixins.forEach(r),e.extends&&r(e.extends),e.mixins&&e.mixins.forEach(r)}return r||s?(E(r)?r.forEach((e=>o[e]=null)):b(o,r),e.__emits=o):e.__emits=null}function Tt(e,t){return!(!e||!v(t))&&(t=t.slice(2).replace(/Once$/,""),x(e,t[0].toLowerCase()+t.slice(1))||x(e,B(t))||x(e,t))}let Vt=0;const Ut=e=>Vt+=e;function Nt(e,t,n={},r,o){let s=e[t];Vt++,Zn();const l=s&&Lt(s(n)),i=tr(Gn,{key:n.key||`_${t}`},l||(r?r():[]),l&&1===e._?64:-2);return!o&&i.scopeId&&(i.slotScopeIds=[i.scopeId+"-s"]),Vt--,i}function Lt(e){return e.some((e=>!nr(e)||e.type!==Xn&&!(e.type===Gn&&!Lt(e.children))))?e:null}let Bt=null,Dt=null;function qt(e){const t=Bt;return Bt=e,Dt=e&&e.type.__scopeId||null,t}function zt(e){Dt=e}function Wt(){Dt=null}const Kt=e=>Gt;function Gt(e,t=Bt){if(!t)return e;const n=(...n)=>{Vt||Zn(!0);const r=qt(t),o=e(...n);return qt(r),Vt||er(),o};return n._c=!0,n}function Ht(e){const{type:t,vnode:n,proxy:r,withProxy:o,props:s,propsOptions:[l],slots:i,attrs:c,emit:a,render:u,renderCache:f,data:p,setupState:d,ctx:h}=e;let m;const g=qt(e);try{let e;if(4&n.shapeFlag){const t=o||r;m=fr(u.call(t,t,f,s,d,p,h)),e=c}else{const n=t;0,m=fr(n.length>1?n(s,{attrs:c,slots:i,emit:a}):n(s,null)),e=t.props?c:Jt(c)}let g=m;if(!1!==t.inheritAttrs&&e){const t=Object.keys(e),{shapeFlag:n}=g;t.length&&(1&n||6&n)&&(l&&t.some(y)&&(e=Qt(e,l)),g=cr(g,e))}n.dirs&&(g.dirs=g.dirs?g.dirs.concat(n.dirs):n.dirs),n.transition&&(g.transition=n.transition),m=g}catch(v){Qn.length=0,pt(v,e,1),m=ir(Xn)}return qt(g),m}function Xt(e){let t;for(let n=0;n{let t;for(const n in e)("class"===n||"style"===n||v(n))&&((t||(t={}))[n]=e[n]);return t},Qt=(e,t)=>{const n={};for(const r in e)y(r)&&r.slice(9)in t||(n[r]=e[r]);return n};function Yt(e,t,n){const r=Object.keys(t);if(r.length!==Object.keys(e).length)return!0;for(let o=0;o{l=!0;const[n,r]=rn(e,t,!0);b(o,n),r&&s.push(...r)};!n&&t.mixins.length&&t.mixins.forEach(r),e.extends&&r(e.extends),e.mixins&&e.mixins.forEach(r)}if(!r&&!l)return e.__props=d;if(E(r))for(let i=0;i-1,n[1]=r<0||t-1||x(n,"default"))&&s.push(e)}}}return e.__props=[o,s]}function on(e){return"$"!==e[0]}function sn(e){const t=e&&e.toString().match(/^\s*function (\w+)/);return t?t[1]:""}function ln(e,t){return sn(e)===sn(t)}function cn(e,t){return E(t)?t.findIndex((t=>ln(t,e))):C(t)&&ln(t,e)?0:-1}function an(e,t,n=Pr,r=!1){if(n){const o=n[e]||(n[e]=[]),s=t.__weh||(t.__weh=(...r)=>{if(n.isUnmounted)return;se(),Fr(n);const o=ft(t,n,e,r);return Fr(null),le(),o});return r?o.unshift(s):o.push(s),s}}const un=e=>(t,n=Pr)=>!$r&&an(e,t,n),fn=un("bm"),pn=un("m"),dn=un("bu"),hn=un("u"),mn=un("bum"),gn=un("um"),vn=un("rtg"),yn=un("rtc"),bn={};function _n(e,t,n){return wn(e,t,n)}function wn(e,t,{immediate:n,deep:r,flush:o,onTrack:s,onTrigger:l}=p,i=Pr){let c,a,u=!1;if(nt(e)?(c=()=>e.value,u=!!e._shallow):Qe(e)?(c=()=>e,r=!0):c=E(e)?()=>e.map((e=>nt(e)?e.value:Qe(e)?En(e):C(e)?ut(e,i,2,[i&&i.proxy]):void 0)):C(e)?t?()=>ut(e,i,2,[i&&i.proxy]):()=>{if(!i||!i.isUnmounted)return a&&a(),ft(e,i,3,[f])}:h,t&&r){const e=c;c=()=>En(e())}let f=e=>{a=v.options.onStop=()=>{ut(e,i,4)}},d=E(e)?[]:bn;const m=()=>{if(v.active)if(t){const e=v();(r||u||z(e,d))&&(a&&a(),ft(t,i,3,[e,d===bn?void 0:d,f]),d=e)}else v()};let g;m.allowRecurse=!!t,g="sync"===o?m:"post"===o?()=>Nn(m,i&&i.suspense):()=>{!i||i.isMounted?function(e){At(e,yt,vt,bt)}(m):m()};const v=Z(c,{lazy:!0,onTrack:s,onTrigger:l,scheduler:g});return Tr(v,i),t?n?m():d=v():"post"===o?Nn(v,i&&i.suspense):v(),()=>{ee(v),i&&_(i.effects,v)}}function xn(e,t,n){const r=this.proxy;return wn(R(e)?()=>r[e]:e.bind(r),t.bind(r),n,this)}function En(e,t=new Set){if(!P(e)||t.has(e))return e;if(t.add(e),nt(e))En(e.value,t);else if(E(e))for(let n=0;n{En(e,t)}));else for(const n in e)En(e[n],t);return e}const kn=e=>e.type.__isKeepAlive;function Sn(e,t,n=Pr){const r=e.__wdc||(e.__wdc=()=>{let t=n;for(;t;){if(t.isDeactivated)return;t=t.parent}e()});if(an(t,r,n),n){let e=n.parent;for(;e&&e.parent;)kn(e.parent.vnode)&&On(r,t,n,e),e=e.parent}}function On(e,t,n,r){const o=an(t,e,r,!0);gn((()=>{_(r[t],o)}),n)}const Cn=e=>"_"===e[0]||"$stable"===e,Rn=e=>E(e)?e.map(fr):[fr(e)],An=(e,t,n)=>Gt((e=>Rn(t(e))),n),Pn=(e,t)=>{const n=e._ctx;for(const r in e){if(Cn(r))continue;const o=e[r];if(C(o))t[r]=An(0,o,n);else if(null!=o){const e=Rn(o);t[r]=()=>e}}},Fn=(e,t)=>{const n=Rn(t);e.slots.default=()=>n};function jn(e,t){if(null===Bt)return e;const n=Bt.proxy,r=e.dirs||(e.dirs=[]);for(let o=0;o(s.has(e)||(e&&C(e.install)?(s.add(e),e.install(i,...t)):C(e)&&(s.add(e),e(i,...t))),i),mixin:e=>(o.mixins.includes(e)||(o.mixins.push(e),(e.props||e.emits)&&(o.deopt=!0)),i),component:(e,t)=>t?(o.components[e]=t,i):o.components[e],directive:(e,t)=>t?(o.directives[e]=t,i):o.directives[e],mount(s,c,a){if(!l){const u=ir(n,r);return u.appContext=o,c&&t?t(u,s):e(u,s,a),l=!0,i._container=s,s.__vue_app__=i,u.component.proxy}},unmount(){l&&(e(null,i._container),delete i._container.__vue_app__)},provide:(e,t)=>(o.provides[e]=t,i)};return i}}function Vn(e){return C(e)?{setup:e,name:e.name}:e}const Un={scheduler:Ct,allowRecurse:!0},Nn=function(e,t){t&&t.pendingBranch?E(e)?t.effects.push(...e):t.effects.push(e):At(e,wt,_t,xt)},Ln=(e,t,n,r)=>{if(E(e))return void e.forEach(((e,o)=>Ln(e,t&&(E(t)?t[o]:t),n,r)));let o;if(r){if(r.type.__asyncLoader)return;o=4&r.shapeFlag?r.component.exposed||r.component.proxy:r.el}else o=null;const{i:s,r:l}=e,i=t&&t.r,c=s.refs===p?s.refs={}:s.refs,a=s.setupState;if(null!=i&&i!==l&&(R(i)?(c[i]=null,x(a,i)&&(a[i]=null)):nt(i)&&(i.value=null)),R(l)){const e=()=>{c[l]=o,x(a,l)&&(a[l]=o)};o?(e.id=-1,Nn(e,n)):e()}else if(nt(l)){const e=()=>{l.value=o};o?(e.id=-1,Nn(e,n)):e()}else C(l)&&ut(l,s,12,[o,c])};function Bn(e){return function(e,t){const{insert:n,remove:r,patchProp:o,forcePatchProp:s,createElement:l,createText:i,createComment:c,setText:a,setElementText:u,parentNode:f,nextSibling:m,setScopeId:g=h,cloneNode:v,insertStaticContent:y}=e,_=(e,t,n,r=null,o=null,s=null,l=!1,i=null,c=!1)=>{e&&!rr(e,t)&&(r=re(e),J(e,o,s,!0),e=null),-2===t.patchFlag&&(c=!1,t.dynamicChildren=null);const{type:a,ref:u,shapeFlag:f}=t;switch(a){case Hn:w(e,t,n,r);break;case Xn:E(e,t,n,r);break;case Jn:null==e&&k(t,n,r,l);break;case Gn:I(e,t,n,r,o,s,l,i,c);break;default:1&f?C(e,t,n,r,o,s,l,i,c):6&f?V(e,t,n,r,o,s,l,i,c):(64&f||128&f)&&a.process(e,t,n,r,o,s,l,i,c,ie)}null!=u&&o&&Ln(u,e&&e.ref,s,t)},w=(e,t,r,o)=>{if(null==e)n(t.el=i(t.children),r,o);else{const n=t.el=e.el;t.children!==e.children&&a(n,t.children)}},E=(e,t,r,o)=>{null==e?n(t.el=c(t.children||""),r,o):t.el=e.el},k=(e,t,n,r)=>{[e.el,e.anchor]=y(e.children,t,n,r)},S=({el:e,anchor:t},r,o)=>{let s;for(;e&&e!==t;)s=m(e),n(e,r,o),e=s;n(t,r,o)},O=({el:e,anchor:t})=>{let n;for(;e&&e!==t;)n=m(e),r(e),e=n;r(t)},C=(e,t,n,r,o,s,l,i,c)=>{l=l||"svg"===t.type,null==e?R(t,n,r,o,s,l,i,c):j(e,t,o,s,l,i,c)},R=(e,t,r,s,i,c,a,f)=>{let p,d;const{type:h,props:m,shapeFlag:g,transition:y,patchFlag:b,dirs:_}=e;if(e.el&&void 0!==v&&-1===b)p=e.el=v(e.el);else{if(p=e.el=l(e.type,c,m&&m.is,m),8&g?u(p,e.children):16&g&&P(e.children,p,null,s,i,c&&"foreignObject"!==h,a,f||!!e.dynamicChildren),_&&$n(e,null,s,"created"),m){for(const t in m)T(t)||o(p,t,null,m[t],c,e.children,s,i,ne);(d=m.onVnodeBeforeMount)&&Dn(d,s,e)}A(p,e,e.scopeId,a,s)}_&&$n(e,null,s,"beforeMount");const w=(!i||i&&!i.pendingBranch)&&y&&!y.persisted;w&&y.beforeEnter(p),n(p,t,r),((d=m&&m.onVnodeMounted)||w||_)&&Nn((()=>{d&&Dn(d,s,e),w&&y.enter(p),_&&$n(e,null,s,"mounted")}),i)},A=(e,t,n,r,o)=>{if(n&&g(e,n),r)for(let s=0;s{for(let a=c;a{const a=t.el=e.el;let{patchFlag:f,dynamicChildren:d,dirs:h}=t;f|=16&e.patchFlag;const m=e.props||p,g=t.props||p;let v;if((v=g.onVnodeBeforeUpdate)&&Dn(v,n,t,e),h&&$n(t,e,n,"beforeUpdate"),f>0){if(16&f)M(a,t,m,g,n,r,l);else if(2&f&&m.class!==g.class&&o(a,"class",null,g.class,l),4&f&&o(a,"style",m.style,g.style,l),8&f){const i=t.dynamicProps;for(let t=0;t{v&&Dn(v,n,t,e),h&&$n(t,e,n,"updated")}),r)},$=(e,t,n,r,o,s,l)=>{for(let i=0;i{if(n!==r){for(const a in r){if(T(a))continue;const u=r[a],f=n[a];(u!==f||s&&s(e,a))&&o(e,a,f,u,c,t.children,l,i,ne)}if(n!==p)for(const s in n)T(s)||s in r||o(e,s,n[s],null,c,t.children,l,i,ne)}},I=(e,t,r,o,s,l,c,a,u)=>{const f=t.el=e?e.el:i(""),p=t.anchor=e?e.anchor:i("");let{patchFlag:d,dynamicChildren:h,slotScopeIds:m}=t;d>0&&(u=!0),m&&(a=a?a.concat(m):m),null==e?(n(f,r,o),n(p,r,o),P(t.children,r,p,s,l,c,a,u)):d>0&&64&d&&h&&e.dynamicChildren?($(e.dynamicChildren,h,r,s,l,c,a),(null!=t.key||s&&t===s.subTree)&&qn(e,t,!0)):z(e,t,r,p,s,l,c,a,u)},V=(e,t,n,r,o,s,l,i,c)=>{t.slotScopeIds=i,null==e?512&t.shapeFlag?o.ctx.activate(t,n,r,l,c):U(t,n,r,o,s,l,c):L(e,t,c)},U=(e,t,n,r,o,s,l)=>{const i=e.component=function(e,t,n){const r=e.type,o=(t?t.appContext:e.appContext)||Rr,s={uid:Ar++,vnode:e,type:r,parent:t,appContext:o,root:null,next:null,subTree:null,update:null,render:null,proxy:null,exposed:null,withProxy:null,effects:null,provides:t?t.provides:Object.create(o.provides),accessCache:null,renderCache:[],components:null,directives:null,propsOptions:rn(r,o),emitsOptions:It(r,o),emit:null,emitted:null,propsDefaults:p,ctx:p,data:p,props:p,attrs:p,slots:p,refs:p,setupState:p,setupContext:null,suspense:n,suspenseId:n?n.pendingId:0,asyncDep:null,asyncResolved:!1,isMounted:!1,isUnmounted:!1,isDeactivated:!1,bc:null,c:null,bm:null,m:null,bu:null,u:null,um:null,bum:null,da:null,a:null,rtg:null,rtc:null,ec:null};return s.ctx={_:s},s.root=t?t.root:s,s.emit=Mt.bind(null,s),s}(e,r,o);if(kn(e)&&(i.ctx.renderer=ie),function(e,t=!1){$r=t;const{props:n,children:r}=e.vnode,o=jr(e);en(e,n,o,t),((e,t)=>{if(32&e.vnode.shapeFlag){const n=t._;n?(e.slots=t,K(t,"_",n)):Pn(t,e.slots={})}else e.slots={},t&&Fn(e,t);K(e.slots,or,1)})(e,r);const s=o?function(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,Or);const{setup:r}=n;if(r){const n=e.setupContext=r.length>1?function(e){const t=t=>{e.exposed=it(t)};return{attrs:e.attrs,slots:e.slots,emit:e.emit,expose:t}}(e):null;Pr=e,se();const o=ut(r,e,0,[e.props,n]);if(le(),Pr=null,F(o)){if(t)return o.then((t=>{Mr(e,t)})).catch((t=>{pt(t,e,0)}));e.asyncDep=o}else Mr(e,o)}else Ir(e)}(e,t):void 0;$r=!1}(i),i.asyncDep){if(o&&o.registerDep(i,D),!e.el){const e=i.subTree=ir(Xn);E(null,e,t,n)}}else D(i,e,t,n,o,s,l)},L=(e,t,n)=>{const r=t.component=e.component;if(function(e,t,n){const{props:r,children:o,component:s}=e,{props:l,children:i,patchFlag:c}=t,a=s.emitsOptions;if(t.dirs||t.transition)return!0;if(!(n&&c>=0))return!(!o&&!i||i&&i.$stable)||r!==l&&(r?!l||Yt(r,l,a):!!l);if(1024&c)return!0;if(16&c)return r?Yt(r,l,a):!!l;if(8&c){const e=t.dynamicProps;for(let t=0;tgt&&mt.splice(t,1)}(r.update),r.update()}else t.component=e.component,t.el=e.el,r.vnode=t},D=(e,t,n,r,o,s,l)=>{e.update=Z((function(){if(e.isMounted){let t,{next:n,bu:r,u:i,parent:c,vnode:a}=e,u=n;n?(n.el=a.el,q(e,n,l)):n=a,r&&W(r),(t=n.props&&n.props.onVnodeBeforeUpdate)&&Dn(t,c,n,a);const p=Ht(e),d=e.subTree;e.subTree=p,_(d,p,f(d.el),re(d),e,o,s),n.el=p.el,null===u&&function({vnode:e,parent:t},n){for(;t&&t.subTree===e;)(e=t.vnode).el=n,t=t.parent}(e,p.el),i&&Nn(i,o),(t=n.props&&n.props.onVnodeUpdated)&&Nn((()=>{Dn(t,c,n,a)}),o)}else{let l;const{el:i,props:c}=t,{bm:a,m:u,parent:f}=e;a&&W(a),(l=c&&c.onVnodeBeforeMount)&&Dn(l,f,t);const p=e.subTree=Ht(e);if(i&&ue?ue(t.el,p,e,o,null):(_(null,p,n,r,e,o,s),t.el=p.el),u&&Nn(u,o),l=c&&c.onVnodeMounted){const e=t;Nn((()=>{Dn(l,f,e)}),o)}const{a:d}=e;d&&256&t.shapeFlag&&Nn(d,o),e.isMounted=!0,t=n=r=null}}),Un)},q=(e,t,n)=>{t.component=e;const r=e.vnode.props;e.vnode=t,e.next=null,function(e,t,n,r){const{props:o,attrs:s,vnode:{patchFlag:l}}=e,i=et(o),[c]=e.propsOptions;if(!(r||l>0)||16&l){let r;tn(e,t,o,s);for(const s in i)t&&(x(t,s)||(r=B(s))!==s&&x(t,r))||(c?!n||void 0===n[s]&&void 0===n[r]||(o[s]=nn(c,t||p,s,void 0,e)):delete o[s]);if(s!==i)for(const e in s)t&&x(t,e)||delete s[e]}else if(8&l){const n=e.vnode.dynamicProps;for(let r=0;r{const{vnode:r,slots:o}=e;let s=!0,l=p;if(32&r.shapeFlag){const e=t._;e?n&&1===e?s=!1:(b(o,t),n||1!==e||delete o._):(s=!t.$stable,Pn(t,o)),l=t}else t&&(Fn(e,t),l={default:1});if(s)for(const i in o)Cn(i)||i in l||delete o[i]})(e,t.children,n),se(),Pt(void 0,e.update),le()},z=(e,t,n,r,o,s,l,i,c=!1)=>{const a=e&&e.children,f=e?e.shapeFlag:0,p=t.children,{patchFlag:d,shapeFlag:h}=t;if(d>0){if(128&d)return void H(a,p,n,r,o,s,l,i,c);if(256&d)return void G(a,p,n,r,o,s,l,i,c)}8&h?(16&f&&ne(a,o,s),p!==a&&u(n,p)):16&f?16&h?H(a,p,n,r,o,s,l,i,c):ne(a,o,s,!0):(8&f&&u(n,""),16&h&&P(p,n,r,o,s,l,i,c))},G=(e,t,n,r,o,s,l,i,c)=>{t=t||d;const a=(e=e||d).length,u=t.length,f=Math.min(a,u);let p;for(p=0;pu?ne(e,o,s,!0,!1,f):P(t,n,r,o,s,l,i,c,f)},H=(e,t,n,r,o,s,l,i,c)=>{let a=0;const u=t.length;let f=e.length-1,p=u-1;for(;a<=f&&a<=p;){const r=e[a],u=t[a]=c?pr(t[a]):fr(t[a]);if(!rr(r,u))break;_(r,u,n,null,o,s,l,i,c),a++}for(;a<=f&&a<=p;){const r=e[f],a=t[p]=c?pr(t[p]):fr(t[p]);if(!rr(r,a))break;_(r,a,n,null,o,s,l,i,c),f--,p--}if(a>f){if(a<=p){const e=p+1,f=ep)for(;a<=f;)J(e[a],o,s,!0),a++;else{const h=a,m=a,g=new Map;for(a=m;a<=p;a++){const e=t[a]=c?pr(t[a]):fr(t[a]);null!=e.key&&g.set(e.key,a)}let v,y=0;const b=p-m+1;let w=!1,x=0;const E=new Array(b);for(a=0;a=b){J(r,o,s,!0);continue}let u;if(null!=r.key)u=g.get(r.key);else for(v=m;v<=p;v++)if(0===E[v-m]&&rr(r,t[v])){u=v;break}void 0===u?J(r,o,s,!0):(E[u-m]=a+1,u>=x?x=u:w=!0,_(r,t[u],n,null,o,s,l,i,c),y++)}const k=w?function(e){const t=e.slice(),n=[0];let r,o,s,l,i;const c=e.length;for(r=0;r0&&(t[r]=n[s-1]),n[s]=r)}}s=n.length,l=n[s-1];for(;s-- >0;)n[s]=l,l=t[l];return n}(E):d;for(v=k.length-1,a=b-1;a>=0;a--){const e=m+a,f=t[e],p=e+1{const{el:l,type:i,transition:c,children:a,shapeFlag:u}=e;if(6&u)return void X(e.component.subTree,t,r,o);if(128&u)return void e.suspense.move(t,r,o);if(64&u)return void i.move(e,t,r,ie);if(i===Gn){n(l,t,r);for(let e=0;ec.enter(l)),s);else{const{leave:e,delayLeave:o,afterLeave:s}=c,i=()=>n(l,t,r),a=()=>{e(l,(()=>{i(),s&&s()}))};o?o(l,i,a):a()}else n(l,t,r)},J=(e,t,n,r=!1,o=!1)=>{const{type:s,props:l,ref:i,children:c,dynamicChildren:a,shapeFlag:u,patchFlag:f,dirs:p}=e;if(null!=i&&Ln(i,null,n,null),256&u)return void t.ctx.deactivate(e);const d=1&u&&p;let h;if((h=l&&l.onVnodeBeforeUnmount)&&Dn(h,t,e),6&u)te(e.component,n,r);else{if(128&u)return void e.suspense.unmount(n,r);d&&$n(e,null,t,"beforeUnmount"),64&u?e.type.remove(e,t,n,o,ie,r):a&&(s!==Gn||f>0&&64&f)?ne(a,t,n,!1,!0):(s===Gn&&(128&f||256&f)||!o&&16&u)&&ne(c,t,n),r&&Q(e)}((h=l&&l.onVnodeUnmounted)||d)&&Nn((()=>{h&&Dn(h,t,e),d&&$n(e,null,t,"unmounted")}),n)},Q=e=>{const{type:t,el:n,anchor:o,transition:s}=e;if(t===Gn)return void Y(n,o);if(t===Jn)return void O(e);const l=()=>{r(n),s&&!s.persisted&&s.afterLeave&&s.afterLeave()};if(1&e.shapeFlag&&s&&!s.persisted){const{leave:t,delayLeave:r}=s,o=()=>t(n,l);r?r(e.el,l,o):o()}else l()},Y=(e,t)=>{let n;for(;e!==t;)n=m(e),r(e),e=n;r(t)},te=(e,t,n)=>{const{bum:r,effects:o,update:s,subTree:l,um:i}=e;if(r&&W(r),o)for(let c=0;c{e.isUnmounted=!0}),t),t&&t.pendingBranch&&!t.isUnmounted&&e.asyncDep&&!e.asyncResolved&&e.suspenseId===t.pendingId&&(t.deps--,0===t.deps&&t.resolve())},ne=(e,t,n,r=!1,o=!1,s=0)=>{for(let l=s;l6&e.shapeFlag?re(e.component.subTree):128&e.shapeFlag?e.suspense.next():m(e.anchor||e.el),oe=(e,t,n)=>{null==e?t._vnode&&J(t._vnode,null,null,!0):_(t._vnode||null,e,t,null,null,null,n),Ft(),t._vnode=e},ie={p:_,um:J,m:X,r:Q,mt:U,mc:P,pc:z,pbc:$,n:re,o:e};let ae,ue;t&&([ae,ue]=t(ie));return{render:oe,hydrate:ae,createApp:Tn(oe,ae)}}(e)}function Dn(e,t,n,r=null){ft(e,t,7,[n,r])}function qn(e,t,n=!1){const r=e.children,o=t.children;if(E(r)&&E(o))for(let s=0;snull!=e?e:null,lr=({ref:e})=>null!=e?R(e)||nt(e)||C(e)?{i:Bt,r:e}:e:null,ir=function(e,t=null,n=null,o=0,s=null,l=!1){e&&e!==Wn||(e=Xn);if(nr(e)){const r=cr(e,t,!0);return n&&dr(r,n),r}c=e,C(c)&&"__vccOpts"in c&&(e=e.__vccOpts);var c;if(t){(Ze(t)||or in t)&&(t=b({},t));let{class:e,style:n}=t;e&&!R(e)&&(t.class=i(e)),P(n)&&(Ze(n)&&!E(n)&&(n=b({},n)),t.style=r(n))}const a=R(e)?1:(e=>e.__isSuspense)(e)?128:(e=>e.__isTeleport)(e)?64:P(e)?4:C(e)?2:0,u={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&sr(t),ref:t&&lr(t),scopeId:Dt,slotScopeIds:null,children:null,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:a,patchFlag:o,dynamicProps:s,dynamicChildren:null,appContext:null};if(dr(u,n),128&a){const{content:e,fallback:t}=function(e){const{shapeFlag:t,children:n}=e;let r,o;return 32&t?(r=Zt(n.default),o=Zt(n.fallback)):(r=Zt(n),o=fr(null)),{content:r,fallback:o}}(u);u.ssContent=e,u.ssFallback=t}!l&&Yn&&(o>0||6&a)&&32!==o&&Yn.push(u);return u};function cr(e,t,n=!1){const{props:o,ref:s,patchFlag:l,children:c}=e,a=t?function(...e){const t=b({},e[0]);for(let n=1;n1)return n&&C(t)?t():t}}let gr=!0;function vr(e,t,n=[],r=[],o=[],s=!1){const{mixins:l,extends:i,data:c,computed:a,methods:u,watch:f,provide:d,inject:m,components:g,directives:v,beforeMount:y,mounted:_,beforeUpdate:w,updated:x,activated:k,deactivated:S,beforeDestroy:O,beforeUnmount:R,destroyed:A,unmounted:F,render:j,renderTracked:$,renderTriggered:M,errorCaptured:I,expose:T}=t,V=e.proxy,U=e.ctx,N=e.appContext.mixins;if(s&&j&&e.render===h&&(e.render=j),s||(gr=!1,yr("beforeCreate","bc",t,e,N),gr=!0,_r(e,N,n,r,o)),i&&vr(e,i,n,r,o,!0),l&&_r(e,l,n,r,o),m)if(E(m))for(let p=0;pwr(e,t,V))),c&&wr(e,c,V)),a)for(const p in a){const e=a[p],t=Ur({get:C(e)?e.bind(V,V):C(e.get)?e.get.bind(V,V):h,set:!C(e)&&C(e.set)?e.set.bind(V):h});Object.defineProperty(U,p,{enumerable:!0,configurable:!0,get:()=>t.value,set:e=>t.value=e})}var L;if(f&&r.push(f),!s&&r.length&&r.forEach((e=>{for(const t in e)xr(e[t],U,V,t)})),d&&o.push(d),!s&&o.length&&o.forEach((e=>{const t=C(e)?e.call(V):e;Reflect.ownKeys(t).forEach((e=>{hr(e,t[e])}))})),s&&(g&&b(e.components||(e.components=b({},e.type.components)),g),v&&b(e.directives||(e.directives=b({},e.type.directives)),v)),s||yr("created","c",t,e,N),y&&fn(y.bind(V)),_&&pn(_.bind(V)),w&&dn(w.bind(V)),x&&hn(x.bind(V)),k&&Sn(k.bind(V),"a",L),S&&function(e,t){Sn(e,"da",t)}(S.bind(V)),I&&((e,t=Pr)=>{an("ec",e,t)})(I.bind(V)),$&&yn($.bind(V)),M&&vn(M.bind(V)),R&&mn(R.bind(V)),F&&gn(F.bind(V)),E(T)&&!s)if(T.length){const t=e.exposed||(e.exposed=it({}));T.forEach((e=>{t[e]=function(e,t){return nt(e[t])?e[t]:new ct(e,t)}(V,e)}))}else e.exposed||(e.exposed=p)}function yr(e,t,n,r,o){for(let s=0;s{let t=e;for(let e=0;en[r];if(R(e)){const n=t[e];C(n)&&_n(o,n)}else if(C(e))_n(o,e.bind(n));else if(P(e))if(E(e))e.forEach((e=>xr(e,t,n,r)));else{const r=C(e.handler)?e.handler.bind(n):t[e.handler];C(r)&&_n(o,r,e)}}function Er(e,t,n){const r=n.appContext.config.optionMergeStrategies,{mixins:o,extends:s}=t;s&&Er(e,s,n),o&&o.forEach((t=>Er(e,t,n)));for(const l in t)r&&x(r,l)?e[l]=r[l](e[l],t[l],n.proxy,l):e[l]=t[l]}const kr=e=>e?jr(e)?e.exposed?e.exposed:e.proxy:kr(e.parent):null,Sr=b(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>kr(e.parent),$root:e=>kr(e.root),$emit:e=>e.emit,$options:e=>function(e){const t=e.type,{__merged:n,mixins:r,extends:o}=t;if(n)return n;const s=e.appContext.mixins;if(!s.length&&!r&&!o)return t;const l={};return s.forEach((t=>Er(l,t,e))),Er(l,t,e),t.__merged=l}(e),$forceUpdate:e=>()=>Ct(e.update),$nextTick:e=>Ot.bind(e.proxy),$watch:e=>xn.bind(e)}),Or={get({_:e},t){const{ctx:n,setupState:r,data:o,props:s,accessCache:l,type:i,appContext:c}=e;if("__v_skip"===t)return!0;let a;if("$"!==t[0]){const i=l[t];if(void 0!==i)switch(i){case 0:return r[t];case 1:return o[t];case 3:return n[t];case 2:return s[t]}else{if(r!==p&&x(r,t))return l[t]=0,r[t];if(o!==p&&x(o,t))return l[t]=1,o[t];if((a=e.propsOptions[0])&&x(a,t))return l[t]=2,s[t];if(n!==p&&x(n,t))return l[t]=3,n[t];gr&&(l[t]=4)}}const u=Sr[t];let f,d;return u?("$attrs"===t&&ie(e,0,t),u(e)):(f=i.__cssModules)&&(f=f[t])?f:n!==p&&x(n,t)?(l[t]=3,n[t]):(d=c.config.globalProperties,x(d,t)?d[t]:void 0)},set({_:e},t,n){const{data:r,setupState:o,ctx:s}=e;if(o!==p&&x(o,t))o[t]=n;else if(r!==p&&x(r,t))r[t]=n;else if(x(e.props,t))return!1;return("$"!==t[0]||!(t.slice(1)in e))&&(s[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:r,appContext:o,propsOptions:s}},l){let i;return void 0!==n[l]||e!==p&&x(e,l)||t!==p&&x(t,l)||(i=s[0])&&x(i,l)||x(r,l)||x(Sr,l)||x(o.config.globalProperties,l)}},Cr=b({},Or,{get(e,t){if(t!==Symbol.unscopables)return Or.get(e,t,e)},has:(e,n)=>"_"!==n[0]&&!t(n)}),Rr=Mn();let Ar=0;let Pr=null;const Fr=e=>{Pr=e};function jr(e){return 4&e.vnode.shapeFlag}let $r=!1;function Mr(e,t,n){C(t)?e.render=t:P(t)&&(e.setupState=it(t)),Ir(e)}function Ir(e,t){const n=e.type;e.render||(e.render=n.render||h,e.render._rc&&(e.withProxy=new Proxy(e.ctx,Cr))),Pr=e,se(),vr(e,n),le(),Pr=null}function Tr(e,t=Pr){t&&(t.effects||(t.effects=[])).push(e)}function Vr(e){return C(e)&&e.displayName||e.name}function Ur(e){const t=function(e){let t,n;return C(e)?(t=e,n=h):(t=e.get,n=e.set),new at(t,n,C(e)||!e.set)}(e);return Tr(t.effect),t}function Nr(e,t,n){const r=arguments.length;return 2===r?P(t)&&!E(t)?nr(t)?ir(e,null,[t]):ir(e,t):ir(e,null,t):(r>3?n=Array.prototype.slice.call(arguments,2):3===r&&nr(n)&&(n=[n]),ir(e,t,n))}function Lr(e,t){let n;if(E(e)||R(e)){n=new Array(e.length);for(let r=0,o=e.length;r{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{const o=t?qr.createElementNS(Dr,e):qr.createElement(e,n?{is:n}:void 0);return"select"===e&&r&&null!=r.multiple&&o.setAttribute("multiple",r.multiple),o},createText:e=>qr.createTextNode(e),createComment:e=>qr.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>qr.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},cloneNode(e){const t=e.cloneNode(!0);return"_value"in e&&(t._value=e._value),t},insertStaticContent(e,t,n,r){const o=r?Wr||(Wr=qr.createElementNS(Dr,"svg")):zr||(zr=qr.createElement("div"));o.innerHTML=e;const s=o.firstChild;let l=s,i=l;for(;l;)i=l,Kr.insert(l,t,n),l=o.firstChild;return[s,i]}};const Gr=/\s*!important$/;function Hr(e,t,n){if(E(n))n.forEach((n=>Hr(e,t,n)));else if(t.startsWith("--"))e.setProperty(t,n);else{const r=function(e,t){const n=Jr[t];if(n)return n;let r=N(t);if("filter"!==r&&r in e)return Jr[t]=r;r=D(r);for(let o=0;odocument.createEvent("Event").timeStamp&&(Yr=()=>performance.now());const e=navigator.userAgent.match(/firefox\/(\d+)/i);Zr=!!(e&&Number(e[1])<=53)}let eo=0;const to=Promise.resolve(),no=()=>{eo=0};function ro(e,t,n,r){e.addEventListener(t,n,r)}function oo(e,t,n,r,o=null){const s=e._vei||(e._vei={}),l=s[t];if(r&&l)l.value=r;else{const[n,i]=function(e){let t;if(so.test(e)){let n;for(t={};n=e.match(so);)e=e.slice(0,e.length-n[0].length),t[n[0].toLowerCase()]=!0}return[B(e.slice(2)),t]}(t);if(r){ro(e,n,s[t]=function(e,t){const n=e=>{const r=e.timeStamp||Yr();(Zr||r>=n.attached-1)&&ft(function(e,t){if(E(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map((e=>t=>!t._stopped&&e(t)))}return t}(e,n.value),t,5,[e])};return n.value=e,n.attached=(()=>eo||(to.then(no),eo=Yr()))(),n}(r,o),i)}else l&&(!function(e,t,n,r){e.removeEventListener(t,n,r)}(e,n,l,i),s[t]=void 0)}}const so=/(?:Once|Passive|Capture)$/;const lo=/^on[a-z]/;const io=e=>{const t=e.props["onUpdate:modelValue"];return E(t)?e=>W(t,e):t};function co(e){e.target.composing=!0}function ao(e){const t=e.target;t.composing&&(t.composing=!1,function(e,t){const n=document.createEvent("HTMLEvents");n.initEvent(t,!0,!0),e.dispatchEvent(n)}(t,"input"))}const uo={created(e,{modifiers:{lazy:t,trim:n,number:r}},o){e._assign=io(o);const s=r||"number"===e.type;ro(e,t?"change":"input",(t=>{if(t.target.composing)return;let r=e.value;n?r=r.trim():s&&(r=G(r)),e._assign(r)})),n&&ro(e,"change",(()=>{e.value=e.value.trim()})),t||(ro(e,"compositionstart",co),ro(e,"compositionend",ao),ro(e,"change",ao))},mounted(e,{value:t}){e.value=null==t?"":t},beforeUpdate(e,{value:t,modifiers:{trim:n,number:r}},o){if(e._assign=io(o),e.composing)return;if(document.activeElement===e){if(n&&e.value.trim()===t)return;if((r||"number"===e.type)&&G(e.value)===t)return}const s=null==t?"":t;e.value!==s&&(e.value=s)}},fo={created(e,t,n){e._assign=io(n),ro(e,"change",(()=>{const t=e._modelValue,n=vo(e),r=e.checked,o=e._assign;if(E(t)){const e=a(t,n),s=-1!==e;if(r&&!s)o(t.concat(n));else if(!r&&s){const n=[...t];n.splice(e,1),o(n)}}else if(S(t)){const e=new Set(t);r?e.add(n):e.delete(n),o(e)}else o(yo(e,r))}))},mounted:po,beforeUpdate(e,t,n){e._assign=io(n),po(e,t,n)}};function po(e,{value:t,oldValue:n},r){e._modelValue=t,E(t)?e.checked=a(t,r.props.value)>-1:S(t)?e.checked=t.has(r.props.value):t!==n&&(e.checked=c(t,yo(e,!0)))}const ho={created(e,{value:t},n){e.checked=c(t,n.props.value),e._assign=io(n),ro(e,"change",(()=>{e._assign(vo(e))}))},beforeUpdate(e,{value:t,oldValue:n},r){e._assign=io(r),t!==n&&(e.checked=c(t,r.props.value))}},mo={created(e,{value:t,modifiers:{number:n}},r){const o=S(t);ro(e,"change",(()=>{const t=Array.prototype.filter.call(e.options,(e=>e.selected)).map((e=>n?G(vo(e)):vo(e)));e._assign(e.multiple?o?new Set(t):t:t[0])})),e._assign=io(r)},mounted(e,{value:t}){go(e,t)},beforeUpdate(e,t,n){e._assign=io(n)},updated(e,{value:t}){go(e,t)}};function go(e,t){const n=e.multiple;if(!n||E(t)||S(t)){for(let r=0,o=e.options.length;r-1:o.selected=t.has(s);else if(c(vo(o),t))return void(e.selectedIndex=r)}n||(e.selectedIndex=-1)}}function vo(e){return"_value"in e?e._value:e.value}function yo(e,t){const n=t?"_trueValue":"_falseValue";return n in e?e[n]:t}const bo=["ctrl","shift","alt","meta"],_o={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&0!==e.button,middle:e=>"button"in e&&1!==e.button,right:e=>"button"in e&&2!==e.button,exact:(e,t)=>bo.some((n=>e[`${n}Key`]&&!t.includes(n)))},wo=(e,t)=>(n,...r)=>{for(let e=0;en=>{if(!("key"in n))return;const r=B(n.key);return t.some((e=>e===r||xo[e]===r))?e(n):void 0},ko={beforeMount(e,{value:t},{transition:n}){e._vod="none"===e.style.display?"":e.style.display,n&&t?n.beforeEnter(e):So(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:r}){!t!=!n&&(r?t?(r.beforeEnter(e),So(e,!0),r.enter(e)):r.leave(e,(()=>{So(e,!1)})):So(e,t))},beforeUnmount(e,{value:t}){So(e,t)}};function So(e,t){e.style.display=t?e._vod:"none"}const Oo=b({patchProp:(e,t,r,o,s=!1,l,i,c,a)=>{switch(t){case"class":!function(e,t,n){if(null==t&&(t=""),n)e.setAttribute("class",t);else{const n=e._vtc;n&&(t=(t?[t,...n]:[...n]).join(" ")),e.className=t}}(e,o,s);break;case"style":!function(e,t,n){const r=e.style;if(n)if(R(n)){if(t!==n){const t=r.display;r.cssText=n,"_vod"in e&&(r.display=t)}}else{for(const e in n)Hr(r,e,n[e]);if(t&&!R(t))for(const e in t)null==n[e]&&Hr(r,e,"")}else e.removeAttribute("style")}(e,r,o);break;default:v(t)?y(t)||oo(e,t,0,o,i):function(e,t,n,r){if(r)return"innerHTML"===t||!!(t in e&&lo.test(t)&&C(n));if("spellcheck"===t||"draggable"===t)return!1;if("form"===t)return!1;if("list"===t&&"INPUT"===e.tagName)return!1;if("type"===t&&"TEXTAREA"===e.tagName)return!1;if(lo.test(t)&&R(n))return!1;return t in e}(e,t,o,s)?function(e,t,n,r,o,s,l){if("innerHTML"===t||"textContent"===t)return r&&l(r,o,s),void(e[t]=null==n?"":n);if("value"!==t||"PROGRESS"===e.tagName){if(""===n||null==n){const r=typeof e[t];if(""===n&&"boolean"===r)return void(e[t]=!0);if(null==n&&"string"===r)return e[t]="",void e.removeAttribute(t);if("number"===r)return e[t]=0,void e.removeAttribute(t)}try{e[t]=n}catch(i){}}else{e._value=n;const t=null==n?"":n;e.value!==t&&(e.value=t)}}(e,t,o,l,i,c,a):("true-value"===t?e._trueValue=o:"false-value"===t&&(e._falseValue=o),function(e,t,r,o){if(o&&t.startsWith("xlink:"))null==r?e.removeAttributeNS(Qr,t.slice(6,t.length)):e.setAttributeNS(Qr,t,r);else{const o=n(t);null==r||o&&!1===r?e.removeAttribute(t):e.setAttribute(t,o?"":r)}}(e,t,o,s))}},forcePatchProp:(e,t)=>"value"===t},Kr);let Co;const Ro=(...e)=>{const t=(Co||(Co=Bn(Oo))).createApp(...e),{mount:n}=t;return t.mount=e=>{const r=function(e){if(R(e)){return document.querySelector(e)}return e} +/*! + * vue-router v4.0.8 + * (c) 2021 Eduardo San Martin Morote + * @license MIT + */(e);if(!r)return;const o=t._component;C(o)||o.render||o.template||(o.template=r.innerHTML),r.innerHTML="";const s=n(r,!1,r instanceof SVGElement);return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),s},t};const Ao="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag,Po=e=>Ao?Symbol(e):"_vr_"+e,Fo=Po("rvlm"),jo=Po("rvd"),$o=Po("r"),Mo=Po("rl"),Io=Po("rvl"),To="undefined"!=typeof window;const Vo=Object.assign;function Uo(e,t){const n={};for(const r in t){const o=t[r];n[r]=Array.isArray(o)?o.map(e):e(o)}return n}let No=()=>{};const Lo=/\/$/;function Bo(e,t,n="/"){let r,o={},s="",l="";const i=t.indexOf("?"),c=t.indexOf("#",i>-1?i:0);return i>-1&&(r=t.slice(0,i),s=t.slice(i+1,c>-1?c:t.length),o=e(s)),c>-1&&(r=r||t.slice(0,c),l=t.slice(c,t.length)),r=function(e,t){if(e.startsWith("/"))return e;if(!e)return t;const n=t.split("/"),r=e.split("/");let o,s,l=n.length-1;for(o=0;oe===t[n])):1===e.length&&e[0]===t}var Go,Ho,Xo,Jo;function Qo(e){if(!e)if(To){const t=document.querySelector("base");e=(e=t&&t.getAttribute("href")||"/").replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return"/"!==e[0]&&"#"!==e[0]&&(e="/"+e),e.replace(Lo,"")}(Ho=Go||(Go={})).pop="pop",Ho.push="push",(Jo=Xo||(Xo={})).back="back",Jo.forward="forward",Jo.unknown="";const Yo=/^[^#]+#/;function Zo(e,t){return e.replace(Yo,"#")+t}const es=()=>({left:window.pageXOffset,top:window.pageYOffset});function ts(e){let t;if("el"in e){let n=e.el;const r="string"==typeof n&&n.startsWith("#"),o="string"==typeof n?r?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!o)return;t=function(e,t){const n=document.documentElement.getBoundingClientRect(),r=e.getBoundingClientRect();return{behavior:t.behavior,left:r.left-n.left-(t.left||0),top:r.top-n.top-(t.top||0)}}(o,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(null!=t.left?t.left:window.pageXOffset,null!=t.top?t.top:window.pageYOffset)}function ns(e,t){return(history.state?history.state.position-t:-1)+e}const rs=new Map;function os(e,t){const{pathname:n,search:r,hash:o}=t,s=e.indexOf("#");if(s>-1){let t=o.includes(e.slice(s))?e.slice(s).length:1,n=o.slice(t);return"/"!==n[0]&&(n="/"+n),Do(n,"")}return Do(n,e)+r+o}function ss(e,t,n,r=!1,o=!1){return{back:e,current:t,forward:n,replaced:r,position:window.history.length,scroll:o?es():null}}function ls(e){const{history:t,location:n}=window;let r={value:os(e,n)},o={value:t.state};function s(r,s,l){const i=e.indexOf("#"),c=i>-1?(n.host&&document.querySelector("base")?e:e.slice(i))+r:location.protocol+"//"+location.host+e+r;try{t[l?"replaceState":"pushState"](s,"",c),o.value=s}catch(a){console.error(a),n[l?"replace":"assign"](c)}}return o.value||s(r.value,{back:null,current:r.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0),{location:r,state:o,push:function(e,n){const l=Vo({},o.value,t.state,{forward:e,scroll:es()});s(l.current,l,!0),s(e,Vo({},ss(r.value,e,null),{position:l.position+1},n),!1),r.value=e},replace:function(e,n){s(e,Vo({},t.state,ss(o.value.back,e,o.value.forward,!0),n,{position:o.value.position}),!0),r.value=e}}}function is(e){const t=ls(e=Qo(e)),n=function(e,t,n,r){let o=[],s=[],l=null;const i=({state:s})=>{const i=os(e,location),c=n.value,a=t.value;let u=0;if(s){if(n.value=i,t.value=s,l&&l===c)return void(l=null);u=a?s.position-a.position:0}else r(i);o.forEach((e=>{e(n.value,c,{delta:u,type:Go.pop,direction:u?u>0?Xo.forward:Xo.back:Xo.unknown})}))};function c(){const{history:e}=window;e.state&&e.replaceState(Vo({},e.state,{scroll:es()}),"")}return window.addEventListener("popstate",i),window.addEventListener("beforeunload",c),{pauseListeners:function(){l=n.value},listen:function(e){o.push(e);const t=()=>{const t=o.indexOf(e);t>-1&&o.splice(t,1)};return s.push(t),t},destroy:function(){for(const e of s)e();s=[],window.removeEventListener("popstate",i),window.removeEventListener("beforeunload",c)}}}(e,t.state,t.location,t.replace);const r=Vo({location:"",base:e,go:function(e,t=!0){t||n.pauseListeners(),history.go(e)},createHref:Zo.bind(null,e)},t,n);return Object.defineProperty(r,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(r,"state",{enumerable:!0,get:()=>t.state.value}),r}function cs(e){return(e=location.host?e||location.pathname+location.search:"").indexOf("#")<0&&(e+="#"),is(e)}function as(e){return"string"==typeof e||"symbol"==typeof e}const us={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0},fs=Po("nf");var ps,ds;function hs(e,t){return Vo(new Error,{type:e,[fs]:!0},t)}function ms(e,t){return e instanceof Error&&fs in e&&(null==t||!!(e.type&t))}(ds=ps||(ps={}))[ds.aborted=4]="aborted",ds[ds.cancelled=8]="cancelled",ds[ds.duplicated=16]="duplicated";const gs={sensitive:!1,strict:!1,start:!0,end:!0},vs=/[.+*?^${}()[\]/\\]/g;function ys(e,t){let n=0;for(;nt.length?1===t.length&&80===t[0]?1:-1:0}function bs(e,t){let n=0;const r=e.score,o=t.score;for(;n1&&("*"===i||"+"===i)&&t(`A repeatable param (${a}) must be alone in its segment. eg: '/:ids+.`),s.push({type:1,value:a,regexp:u,repeatable:"*"===i||"+"===i,optional:"*"===i||"?"===i})):t("Invalid state to consume buffer"),a="")}function p(){a+=i}for(;c{s(p)}:No}function s(e){if(as(e)){const t=r.get(e);t&&(r.delete(e),n.splice(n.indexOf(t),1),t.children.forEach(s),t.alias.forEach(s))}else{let t=n.indexOf(e);t>-1&&(n.splice(t,1),e.record.name&&r.delete(e.record.name),e.children.forEach(s),e.alias.forEach(s))}}function l(e){let t=0;for(;t=0;)t++;n.splice(t,0,e),e.record.name&&!Ss(e)&&r.set(e.record.name,e)}return t=Cs({strict:!1,end:!0,sensitive:!1},t),e.forEach((e=>o(e))),{addRoute:o,resolve:function(e,t){let o,s,l,i={};if("name"in e&&e.name){if(o=r.get(e.name),!o)throw hs(1,{location:e});l=o.record.name,i=Vo(function(e,t){let n={};for(let r of t)r in e&&(n[r]=e[r]);return n}(t.params,o.keys.filter((e=>!e.optional)).map((e=>e.name))),e.params),s=o.stringify(i)}else if("path"in e)s=e.path,o=n.find((e=>e.re.test(s))),o&&(i=o.parse(s),l=o.record.name);else{if(o=t.name?r.get(t.name):n.find((e=>e.re.test(t.path))),!o)throw hs(1,{location:e,currentLocation:t});l=o.record.name,i=Vo({},t.params,e.params),s=o.stringify(i)}const c=[];let a=o;for(;a;)c.unshift(a.record),a=a.parent;return{name:l,path:s,params:i,matched:c,meta:Os(c)}},removeRoute:s,getRoutes:function(){return n},getRecordMatcher:function(e){return r.get(e)}}}function ks(e){const t={},n=e.props||!1;if("component"in e)t.default=n;else for(let r in e.components)t[r]="boolean"==typeof n?n:n[r];return t}function Ss(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function Os(e){return e.reduce(((e,t)=>Vo(e,t.meta)),{})}function Cs(e,t){let n={};for(let r in e)n[r]=r in t?t[r]:e[r];return n}const Rs=/#/g,As=/&/g,Ps=/\//g,Fs=/=/g,js=/\?/g,$s=/\+/g,Ms=/%5B/g,Is=/%5D/g,Ts=/%5E/g,Vs=/%60/g,Us=/%7B/g,Ns=/%7C/g,Ls=/%7D/g,Bs=/%20/g;function Ds(e){return encodeURI(""+e).replace(Ns,"|").replace(Ms,"[").replace(Is,"]")}function qs(e){return Ds(e).replace($s,"%2B").replace(Bs,"+").replace(Rs,"%23").replace(As,"%26").replace(Vs,"`").replace(Us,"{").replace(Ls,"}").replace(Ts,"^")}function zs(e){return function(e){return Ds(e).replace(Rs,"%23").replace(js,"%3F")}(e).replace(Ps,"%2F")}function Ws(e){try{return decodeURIComponent(""+e)}catch(t){}return""+e}function Ks(e){const t={};if(""===e||"?"===e)return t;const n=("?"===e[0]?e.slice(1):e).split("&");for(let r=0;re&&qs(e))):[r&&qs(r)]).forEach((e=>{void 0!==e&&(t+=(t.length?"&":"")+n,null!=e&&(t+="="+e))}))}return t}function Hs(e){const t={};for(let n in e){let r=e[n];void 0!==r&&(t[n]=Array.isArray(r)?r.map((e=>null==e?null:""+e)):null==r?r:""+r)}return t}function Xs(){let e=[];return{add:function(t){return e.push(t),()=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)}},list:()=>e,reset:function(){e=[]}}}function Js(e,t,n,r,o){const s=r&&(r.enterCallbacks[o]=r.enterCallbacks[o]||[]);return()=>new Promise(((l,i)=>{const c=e=>{var c;!1===e?i(hs(4,{from:n,to:t})):e instanceof Error?i(e):"string"==typeof(c=e)||c&&"object"==typeof c?i(hs(2,{from:t,to:e})):(s&&r.enterCallbacks[o]===s&&"function"==typeof e&&s.push(e),l())},a=e.call(r&&r.instances[o],t,n,c);let u=Promise.resolve(a);e.length<3&&(u=u.then(c)),u.catch((e=>i(e)))}))}function Qs(e,t,n,r){const o=[];for(const l of e)for(const e in l.components){let i=l.components[e];if("beforeRouteEnter"===t||l.instances[e])if("object"==typeof(s=i)||"displayName"in s||"props"in s||"__vccOpts"in s){const s=(i.__vccOpts||i)[t];s&&o.push(Js(s,n,r,l,e))}else{let s=i();s=s.catch(console.error),o.push((()=>s.then((o=>{if(!o)return Promise.reject(new Error(`Couldn't resolve component "${e}" at "${l.path}"`));const s=(i=o).__esModule||Ao&&"Module"===i[Symbol.toStringTag]?o.default:o;var i;l.components[e]=s;const c=(s.__vccOpts||s)[t];return c&&Js(c,n,r,l,e)()}))))}}var s;return o}function Ys(e){const t=mr($o),n=mr(Mo),r=Ur((()=>t.resolve(st(e.to)))),o=Ur((()=>{let{matched:e}=r.value,{length:t}=e;const o=e[t-1];let s=n.matched;if(!o||!s.length)return-1;let l=s.findIndex(qo.bind(null,o));if(l>-1)return l;let i=el(e[t-2]);return t>1&&el(o)===i&&s[s.length-1].path!==i?s.findIndex(qo.bind(null,e[t-2])):l})),s=Ur((()=>o.value>-1&&function(e,t){for(let n in t){let r=t[n],o=e[n];if("string"==typeof r){if(r!==o)return!1}else if(!Array.isArray(o)||o.length!==r.length||r.some(((e,t)=>e!==o[t])))return!1}return!0}(n.params,r.value.params))),l=Ur((()=>o.value>-1&&o.value===n.matched.length-1&&zo(n.params,r.value.params)));return{route:r,href:Ur((()=>r.value.href)),isActive:s,isExactActive:l,navigate:function(n={}){return function(e){if(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)return;if(e.defaultPrevented)return;if(void 0!==e.button&&0!==e.button)return;if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}e.preventDefault&&e.preventDefault();return!0}(n)?t[st(e.replace)?"replace":"push"](st(e.to)):Promise.resolve()}}}const Zs=Vn({name:"RouterLink",props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"}},setup(e,{slots:t}){const n=He(Ys(e)),{options:r}=mr($o),o=Ur((()=>({[tl(e.activeClass,r.linkActiveClass,"router-link-active")]:n.isActive,[tl(e.exactActiveClass,r.linkExactActiveClass,"router-link-exact-active")]:n.isExactActive})));return()=>{const r=t.default&&t.default(n);return e.custom?r:Nr("a",{"aria-current":n.isExactActive?e.ariaCurrentValue:null,href:n.href,onClick:n.navigate,class:o.value},r)}}});function el(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const tl=(e,t,n)=>null!=e?e:null!=t?t:n;function nl(e,t){if(!e)return null;const n=e(t);return 1===n.length?n[0]:n}const rl=Vn({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},setup(e,{attrs:t,slots:n}){const r=mr(Io),o=Ur((()=>e.route||r.value)),s=mr(jo,0),l=Ur((()=>o.value.matched[s]));hr(jo,s+1),hr(Fo,l),hr(Io,o);const i=ot(c);var c;return _n((()=>[i.value,l.value,e.name]),(([e,t,n],[r,o,s])=>{t&&(t.instances[n]=e,o&&o!==t&&e&&e===r&&(t.leaveGuards.size||(t.leaveGuards=o.leaveGuards),t.updateGuards.size||(t.updateGuards=o.updateGuards))),!e||!t||o&&qo(t,o)&&r||(t.enterCallbacks[n]||[]).forEach((t=>t(e)))}),{flush:"post"}),()=>{const r=o.value,s=l.value,c=s&&s.components[e.name],a=e.name;if(!c)return nl(n.default,{Component:c,route:r});const u=s.props[e.name],f=u?!0===u?r.params:"function"==typeof u?u(r):u:null,p=Nr(c,Vo({},f,t,{onVnodeUnmounted:e=>{e.component.isUnmounted&&(s.instances[a]=null)},ref:i}));return nl(n.default,{Component:p,route:r})||p}}});function ol(e){const t=Es(e.routes,e);let n=e.parseQuery||Ks,r=e.stringifyQuery||Gs,o=e.history;const s=Xs(),l=Xs(),i=Xs(),c=ot(us,!0);let a=us;To&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const u=Uo.bind(null,(e=>""+e)),f=Uo.bind(null,zs),p=Uo.bind(null,Ws);function d(e,s){if(s=Vo({},s||c.value),"string"==typeof e){let r=Bo(n,e,s.path),l=t.resolve({path:r.path},s),i=o.createHref(r.fullPath);return Vo(r,l,{params:p(l.params),hash:Ws(r.hash),redirectedFrom:void 0,href:i})}let l;"path"in e?l=Vo({},e,{path:Bo(n,e.path,s.path).path}):(l=Vo({},e,{params:f(e.params)}),s.params=f(s.params));let i=t.resolve(l,s);const a=e.hash||"";i.params=u(p(i.params));const d=function(e,t){let n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}(r,Vo({},e,{hash:(h=a,Ds(h).replace(Us,"{").replace(Ls,"}").replace(Ts,"^")),path:i.path}));var h;let m=o.createHref(d);return Vo({fullPath:d,hash:a,query:r===Gs?Hs(e.query):e.query},i,{redirectedFrom:void 0,href:m})}function h(e){return"string"==typeof e?Bo(n,e,c.value.path):Vo({},e)}function m(e,t){if(a!==e)return hs(8,{from:t,to:e})}function g(e){return y(e)}function v(e){const t=e.matched[e.matched.length-1];if(t&&t.redirect){const{redirect:n}=t;let r="function"==typeof n?n(e):n;return"string"==typeof r&&(r=r.indexOf("?")>-1||r.indexOf("#")>-1?r=h(r):{path:r}),Vo({query:e.query,hash:e.hash,params:e.params},r)}}function y(e,t){const n=a=d(e),o=c.value,s=e.state,l=e.force,i=!0===e.replace,u=v(n);if(u)return y(Vo(h(u),{state:s,force:l,replace:i}),t||n);const f=n;let p;return f.redirectedFrom=t,!l&&function(e,t,n){let r=t.matched.length-1,o=n.matched.length-1;return r>-1&&r===o&&qo(t.matched[r],n.matched[o])&&zo(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}(r,o,n)&&(p=hs(16,{to:f,from:o}),P(o,o,!0,!1)),(p?Promise.resolve(p):_(f,o)).catch((e=>ms(e)?e:R(e))).then((e=>{if(e){if(ms(e,2))return y(Vo(h(e.to),{state:s,force:l,replace:i}),t||f)}else e=x(f,o,!0,i,s);return w(f,o,e),e}))}function b(e,t){const n=m(e,t);return n?Promise.reject(n):Promise.resolve()}function _(e,t){let n;const[r,o,i]=function(e,t){const n=[],r=[],o=[],s=Math.max(t.matched.length,e.matched.length);for(let l=0;lqo(e,s)))?r.push(s):n.push(s));const i=e.matched[l];i&&(t.matched.find((e=>qo(e,i)))||o.push(i))}return[n,r,o]}(e,t);n=Qs(r.reverse(),"beforeRouteLeave",e,t);for(const s of r)s.leaveGuards.forEach((r=>{n.push(Js(r,e,t))}));const c=b.bind(null,e,t);return n.push(c),sl(n).then((()=>{n=[];for(const r of s.list())n.push(Js(r,e,t));return n.push(c),sl(n)})).then((()=>{n=Qs(o,"beforeRouteUpdate",e,t);for(const r of o)r.updateGuards.forEach((r=>{n.push(Js(r,e,t))}));return n.push(c),sl(n)})).then((()=>{n=[];for(const r of e.matched)if(r.beforeEnter&&t.matched.indexOf(r)<0)if(Array.isArray(r.beforeEnter))for(const o of r.beforeEnter)n.push(Js(o,e,t));else n.push(Js(r.beforeEnter,e,t));return n.push(c),sl(n)})).then((()=>(e.matched.forEach((e=>e.enterCallbacks={})),n=Qs(i,"beforeRouteEnter",e,t),n.push(c),sl(n)))).then((()=>{n=[];for(const r of l.list())n.push(Js(r,e,t));return n.push(c),sl(n)})).catch((e=>ms(e,8)?e:Promise.reject(e)))}function w(e,t,n){for(const r of i.list())r(e,t,n)}function x(e,t,n,r,s){const l=m(e,t);if(l)return l;const i=t===us,a=To?history.state:{};n&&(r||i?o.replace(e.fullPath,Vo({scroll:i&&a&&a.scroll},s)):o.push(e.fullPath,s)),c.value=e,P(e,t,n,i),A()}let E;function k(){E=o.listen(((e,t,n)=>{let r=d(e);const s=v(r);if(s)return void y(Vo(s,{replace:!0}),r).catch(No);a=r;const l=c.value;var i,u;To&&(i=ns(l.fullPath,n.delta),u=es(),rs.set(i,u)),_(r,l).catch((e=>ms(e,12)?e:ms(e,2)?(y(e.to,r).catch(No),Promise.reject()):(n.delta&&o.go(-n.delta,!1),R(e)))).then((e=>{(e=e||x(r,l,!1))&&n.delta&&o.go(-n.delta,!1),w(r,l,e)})).catch(No)}))}let S,O=Xs(),C=Xs();function R(e){return A(e),C.list().forEach((t=>t(e))),Promise.reject(e)}function A(e){S||(S=!0,k(),O.list().forEach((([t,n])=>e?n(e):t())),O.reset())}function P(t,n,r,o){const{scrollBehavior:s}=e;if(!To||!s)return Promise.resolve();let l=!r&&function(e){const t=rs.get(e);return rs.delete(e),t}(ns(t.fullPath,0))||(o||!r)&&history.state&&history.state.scroll||null;return Ot().then((()=>s(t,n,l))).then((e=>e&&ts(e))).catch(R)}const F=e=>o.go(e);let j;const $=new Set;return{currentRoute:c,addRoute:function(e,n){let r,o;return as(e)?(r=t.getRecordMatcher(e),o=n):o=e,t.addRoute(o,r)},removeRoute:function(e){let n=t.getRecordMatcher(e);n&&t.removeRoute(n)},hasRoute:function(e){return!!t.getRecordMatcher(e)},getRoutes:function(){return t.getRoutes().map((e=>e.record))},resolve:d,options:e,push:g,replace:function(e){return g(Vo(h(e),{replace:!0}))},go:F,back:()=>F(-1),forward:()=>F(1),beforeEach:s.add,beforeResolve:l.add,afterEach:i.add,onError:C.add,isReady:function(){return S&&c.value!==us?Promise.resolve():new Promise(((e,t)=>{O.add([e,t])}))},install(e){e.component("RouterLink",Zs),e.component("RouterView",rl),e.config.globalProperties.$router=this,Object.defineProperty(e.config.globalProperties,"$route",{enumerable:!0,get:()=>st(c)}),To&&!j&&c.value===us&&(j=!0,g(o.location).catch((e=>{})));const t={};for(let r in us)t[r]=Ur((()=>c.value[r]));e.provide($o,this),e.provide(Mo,He(t)),e.provide(Io,c);let n=e.unmount;$.add(e),e.unmount=function(){$.delete(e),$.size<1&&(E(),c.value=us,j=!1,S=!1),n()}}}}function sl(e){return e.reduce(((e,t)=>e.then((()=>t()))),Promise.resolve())}export{Gn as F,ir as a,ur as b,tr as c,Vn as d,ar as e,Lr as f,wo as g,jn as h,Eo as i,Kt as j,Wt as k,ho as l,mo as m,Nt as n,Zn as o,zt as p,fo as q,zn as r,ko as s,u as t,ol as u,uo as v,Gt as w,cs as x,Ro as y}; diff --git a/build/public/assets/vendor.b622ee49.js b/build/public/assets/vendor.b622ee49.js deleted file mode 100644 index 3b5cc43..0000000 --- a/build/public/assets/vendor.b622ee49.js +++ /dev/null @@ -1,6 +0,0 @@ -function e(e,t){const n=Object.create(null),r=e.split(",");for(let o=0;o!!n[e.toLowerCase()]:e=>!!n[e]}const t=e("Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt"),n=e("itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly");function r(e){if(E(e)){const t={};for(let n=0;n{if(e){const n=e.split(s);n.length>1&&(t[n[0].trim()]=n[1].trim())}})),t}function i(e){let t="";if(R(e))t=e;else if(E(e))for(let n=0;nc(e,t)))}const u=e=>null==e?"":P(e)?JSON.stringify(e,f,2):String(e),f=(e,t)=>k(t)?{[`Map(${t.size})`]:[...t.entries()].reduce(((e,[t,n])=>(e[`${t} =>`]=n,e)),{})}:S(t)?{[`Set(${t.size})`]:[...t.values()]}:!P(t)||E(t)||M(t)?t:String(t),p={},d=[],h=()=>{},m=()=>!1,g=/^on[^a-z]/,v=e=>g.test(e),y=e=>e.startsWith("onUpdate:"),b=Object.assign,_=(e,t)=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)},w=Object.prototype.hasOwnProperty,x=(e,t)=>w.call(e,t),E=Array.isArray,k=e=>"[object Map]"===$(e),S=e=>"[object Set]"===$(e),O=e=>e instanceof Date,C=e=>"function"==typeof e,R=e=>"string"==typeof e,A=e=>"symbol"==typeof e,P=e=>null!==e&&"object"==typeof e,F=e=>P(e)&&C(e.then)&&C(e.catch),j=Object.prototype.toString,$=e=>j.call(e),M=e=>"[object Object]"===$(e),I=e=>R(e)&&"NaN"!==e&&"-"!==e[0]&&""+parseInt(e,10)===e,T=e(",key,ref,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),U=e=>{const t=Object.create(null);return n=>t[n]||(t[n]=e(n))},V=/-(\w)/g,N=U((e=>e.replace(V,((e,t)=>t?t.toUpperCase():"")))),L=/\B([A-Z])/g,B=U((e=>e.replace(L,"-$1").toLowerCase())),D=U((e=>e.charAt(0).toUpperCase()+e.slice(1))),q=U((e=>e?`on${D(e)}`:"")),z=(e,t)=>e!==t&&(e==e||t==t),W=(e,t)=>{for(let n=0;n{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,value:n})},G=e=>{const t=parseFloat(e);return isNaN(t)?e:t},H=new WeakMap,X=[];let J;const Q=Symbol(""),Y=Symbol("");function Z(e,t=p){(function(e){return e&&!0===e._isEffect})(e)&&(e=e.raw);const n=function(e,t){const n=function(){if(!n.active)return t.scheduler?void 0:e();if(!X.includes(n)){ne(n);try{return oe.push(re),re=!0,X.push(n),J=n,e()}finally{X.pop(),le(),J=X[X.length-1]}}};return n.id=te++,n.allowRecurse=!!t.allowRecurse,n._isEffect=!0,n.active=!0,n.raw=e,n.deps=[],n.options=t,n}(e,t);return t.lazy||n(),n}function ee(e){e.active&&(ne(e),e.options.onStop&&e.options.onStop(),e.active=!1)}let te=0;function ne(e){const{deps:t}=e;if(t.length){for(let n=0;n{e&&e.forEach((e=>{(e!==J||e.allowRecurse)&&i.add(e)}))};if("clear"===t)l.forEach(c);else if("length"===n&&E(e))l.forEach(((e,t)=>{("length"===t||t>=r)&&c(e)}));else switch(void 0!==n&&c(l.get(n)),t){case"add":E(e)?I(n)&&c(l.get("length")):(c(l.get(Q)),k(e)&&c(l.get(Y)));break;case"delete":E(e)||(c(l.get(Q)),k(e)&&c(l.get(Y)));break;case"set":k(e)&&c(l.get(Q))}i.forEach((e=>{e.options.scheduler?e.options.scheduler(e):e()}))}const ae=e("__proto__,__v_isRef,__isVue"),ue=new Set(Object.getOwnPropertyNames(Symbol).map((e=>Symbol[e])).filter(A)),fe=ge(),pe=ge(!1,!0),de=ge(!0),he=ge(!0,!0),me={};function ge(e=!1,t=!1){return function(n,r,o){if("__v_isReactive"===r)return!e;if("__v_isReadonly"===r)return e;if("__v_raw"===r&&o===(e?t?Ke:We:t?ze:qe).get(n))return n;const s=E(n);if(!e&&s&&x(me,r))return Reflect.get(me,r,o);const l=Reflect.get(n,r,o);if(A(r)?ue.has(r):ae(r))return l;if(e||ie(n,0,r),t)return l;if(nt(l)){return!s||!I(r)?l.value:l}return P(l)?e?Xe(l):He(l):l}}["includes","indexOf","lastIndexOf"].forEach((e=>{const t=Array.prototype[e];me[e]=function(...e){const n=et(this);for(let t=0,o=this.length;t{const t=Array.prototype[e];me[e]=function(...e){se();const n=t.apply(this,e);return le(),n}}));function ve(e=!1){return function(t,n,r,o){let s=t[n];if(!e&&(r=et(r),s=et(s),!E(t)&&nt(s)&&!nt(r)))return s.value=r,!0;const l=E(t)&&I(n)?Number(n)!0,deleteProperty:(e,t)=>!0},_e=b({},ye,{get:pe,set:ve(!0)});b({},be,{get:he});const we=e=>P(e)?He(e):e,xe=e=>P(e)?Xe(e):e,Ee=e=>e,ke=e=>Reflect.getPrototypeOf(e);function Se(e,t,n=!1,r=!1){const o=et(e=e.__v_raw),s=et(t);t!==s&&!n&&ie(o,0,t),!n&&ie(o,0,s);const{has:l}=ke(o),i=r?Ee:n?xe:we;return l.call(o,t)?i(e.get(t)):l.call(o,s)?i(e.get(s)):void 0}function Oe(e,t=!1){const n=this.__v_raw,r=et(n),o=et(e);return e!==o&&!t&&ie(r,0,e),!t&&ie(r,0,o),e===o?n.has(e):n.has(e)||n.has(o)}function Ce(e,t=!1){return e=e.__v_raw,!t&&ie(et(e),0,Q),Reflect.get(e,"size",e)}function Re(e){e=et(e);const t=et(this);return ke(t).has.call(t,e)||(t.add(e),ce(t,"add",e,e)),this}function Ae(e,t){t=et(t);const n=et(this),{has:r,get:o}=ke(n);let s=r.call(n,e);s||(e=et(e),s=r.call(n,e));const l=o.call(n,e);return n.set(e,t),s?z(t,l)&&ce(n,"set",e,t):ce(n,"add",e,t),this}function Pe(e){const t=et(this),{has:n,get:r}=ke(t);let o=n.call(t,e);o||(e=et(e),o=n.call(t,e)),r&&r.call(t,e);const s=t.delete(e);return o&&ce(t,"delete",e,void 0),s}function Fe(){const e=et(this),t=0!==e.size,n=e.clear();return t&&ce(e,"clear",void 0,void 0),n}function je(e,t){return function(n,r){const o=this,s=o.__v_raw,l=et(s),i=t?Ee:e?xe:we;return!e&&ie(l,0,Q),s.forEach(((e,t)=>n.call(r,i(e),i(t),o)))}}function $e(e,t,n){return function(...r){const o=this.__v_raw,s=et(o),l=k(s),i="entries"===e||e===Symbol.iterator&&l,c="keys"===e&&l,a=o[e](...r),u=n?Ee:t?xe:we;return!t&&ie(s,0,c?Y:Q),{next(){const{value:e,done:t}=a.next();return t?{value:e,done:t}:{value:i?[u(e[0]),u(e[1])]:u(e),done:t}},[Symbol.iterator](){return this}}}}function Me(e){return function(...t){return"delete"!==e&&this}}const Ie={get(e){return Se(this,e)},get size(){return Ce(this)},has:Oe,add:Re,set:Ae,delete:Pe,clear:Fe,forEach:je(!1,!1)},Te={get(e){return Se(this,e,!1,!0)},get size(){return Ce(this)},has:Oe,add:Re,set:Ae,delete:Pe,clear:Fe,forEach:je(!1,!0)},Ue={get(e){return Se(this,e,!0)},get size(){return Ce(this,!0)},has(e){return Oe.call(this,e,!0)},add:Me("add"),set:Me("set"),delete:Me("delete"),clear:Me("clear"),forEach:je(!0,!1)},Ve={get(e){return Se(this,e,!0,!0)},get size(){return Ce(this,!0)},has(e){return Oe.call(this,e,!0)},add:Me("add"),set:Me("set"),delete:Me("delete"),clear:Me("clear"),forEach:je(!0,!0)};function Ne(e,t){const n=t?e?Ve:Te:e?Ue:Ie;return(t,r,o)=>"__v_isReactive"===r?!e:"__v_isReadonly"===r?e:"__v_raw"===r?t:Reflect.get(x(n,r)&&r in t?n:t,r,o)}["keys","values","entries",Symbol.iterator].forEach((e=>{Ie[e]=$e(e,!1,!1),Ue[e]=$e(e,!0,!1),Te[e]=$e(e,!1,!0),Ve[e]=$e(e,!0,!0)}));const Le={get:Ne(!1,!1)},Be={get:Ne(!1,!0)},De={get:Ne(!0,!1)},qe=new WeakMap,ze=new WeakMap,We=new WeakMap,Ke=new WeakMap;function Ge(e){return e.__v_skip||!Object.isExtensible(e)?0:function(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}((e=>$(e).slice(8,-1))(e))}function He(e){return e&&e.__v_isReadonly?e:Je(e,!1,ye,Le,qe)}function Xe(e){return Je(e,!0,be,De,We)}function Je(e,t,n,r,o){if(!P(e))return e;if(e.__v_raw&&(!t||!e.__v_isReactive))return e;const s=o.get(e);if(s)return s;const l=Ge(e);if(0===l)return e;const i=new Proxy(e,2===l?r:n);return o.set(e,i),i}function Qe(e){return Ye(e)?Qe(e.__v_raw):!(!e||!e.__v_isReactive)}function Ye(e){return!(!e||!e.__v_isReadonly)}function Ze(e){return Qe(e)||Ye(e)}function et(e){return e&&et(e.__v_raw)||e}const tt=e=>P(e)?He(e):e;function nt(e){return Boolean(e&&!0===e.__v_isRef)}class rt{constructor(e,t=!1){this._rawValue=e,this._shallow=t,this.__v_isRef=!0,this._value=t?e:tt(e)}get value(){return ie(et(this),0,"value"),this._value}set value(e){z(et(e),this._rawValue)&&(this._rawValue=e,this._value=this._shallow?e:tt(e),ce(et(this),"set","value",e))}}function ot(e,t=!1){return nt(e)?e:new rt(e,t)}function st(e){return nt(e)?e.value:e}const lt={get:(e,t,n)=>st(Reflect.get(e,t,n)),set:(e,t,n,r)=>{const o=e[t];return nt(o)&&!nt(n)?(o.value=n,!0):Reflect.set(e,t,n,r)}};function it(e){return Qe(e)?e:new Proxy(e,lt)}class ct{constructor(e,t){this._object=e,this._key=t,this.__v_isRef=!0}get value(){return this._object[this._key]}set value(e){this._object[this._key]=e}}class at{constructor(e,t,n){this._setter=t,this._dirty=!0,this.__v_isRef=!0,this.effect=Z(e,{lazy:!0,scheduler:()=>{this._dirty||(this._dirty=!0,ce(et(this),"set","value"))}}),this.__v_isReadonly=n}get value(){const e=et(this);return e._dirty&&(e._value=this.effect(),e._dirty=!1),ie(e,0,"value"),e._value}set value(e){this._setter(e)}}function ut(e,t,n,r){let o;try{o=r?e(...r):e()}catch(s){pt(s,t,n)}return o}function ft(e,t,n,r){if(C(e)){const o=ut(e,t,n,r);return o&&F(o)&&o.catch((e=>{pt(e,t,n)})),o}const o=[];for(let s=0;s>>1;jt(mt[e])-1?mt.splice(t,0,e):mt.push(e),Rt()}}function Rt(){dt||ht||(ht=!0,kt=Et.then($t))}function At(e,t,n,r){E(e)?n.push(...e):t&&t.includes(e,e.allowRecurse?r+1:r)||n.push(e),Rt()}function Pt(e,t=null){if(vt.length){for(St=t,yt=[...new Set(vt)],vt.length=0,bt=0;btjt(e)-jt(t))),xt=0;xtnull==e.id?1/0:e.id;function $t(e){ht=!1,dt=!0,Pt(e),mt.sort(((e,t)=>jt(e)-jt(t)));try{for(gt=0;gte.trim())):t&&(o=n.map(G))}let i,c=r[i=q(t)]||r[i=q(N(t))];!c&&s&&(c=r[i=q(B(t))]),c&&ft(c,e,6,o);const a=r[i+"Once"];if(a){if(e.emitted){if(e.emitted[i])return}else(e.emitted={})[i]=!0;ft(a,e,6,o)}}function It(e,t,n=!1){if(!t.deopt&&void 0!==e.__emits)return e.__emits;const r=e.emits;let o={},s=!1;if(!C(e)){const r=e=>{const n=It(e,t,!0);n&&(s=!0,b(o,n))};!n&&t.mixins.length&&t.mixins.forEach(r),e.extends&&r(e.extends),e.mixins&&e.mixins.forEach(r)}return r||s?(E(r)?r.forEach((e=>o[e]=null)):b(o,r),e.__emits=o):e.__emits=null}function Tt(e,t){return!(!e||!v(t))&&(t=t.slice(2).replace(/Once$/,""),x(e,t[0].toLowerCase()+t.slice(1))||x(e,B(t))||x(e,t))}let Ut=0;const Vt=e=>Ut+=e;function Nt(e,t,n={},r,o){let s=e[t];Ut++,Qn();const l=s&&Lt(s(n)),i=Zn(Wn,{key:n.key||`_${t}`},l||(r?r():[]),l&&1===e._?64:-2);return!o&&i.scopeId&&(i.slotScopeIds=[i.scopeId+"-s"]),Ut--,i}function Lt(e){return e.some((e=>!er(e)||e.type!==Gn&&!(e.type===Wn&&!Lt(e.children))))?e:null}let Bt=null,Dt=null;function qt(e){const t=Bt;return Bt=e,Dt=e&&e.type.__scopeId||null,t}const zt=e=>Wt;function Wt(e,t=Bt){if(!t)return e;const n=(...n)=>{Ut||Qn(!0);const r=qt(t),o=e(...n);return qt(r),Ut||Yn(),o};return n._c=!0,n}function Kt(e){const{type:t,vnode:n,proxy:r,withProxy:o,props:s,propsOptions:[l],slots:i,attrs:c,emit:a,render:u,renderCache:f,data:p,setupState:d,ctx:h}=e;let m;const g=qt(e);try{let e;if(4&n.shapeFlag){const t=o||r;m=ar(u.call(t,t,f,s,d,p,h)),e=c}else{const n=t;0,m=ar(n.length>1?n(s,{attrs:c,slots:i,emit:a}):n(s,null)),e=t.props?c:Ht(c)}let g=m;if(!1!==t.inheritAttrs&&e){const t=Object.keys(e),{shapeFlag:n}=g;t.length&&(1&n||6&n)&&(l&&t.some(y)&&(e=Xt(e,l)),g=lr(g,e))}n.dirs&&(g.dirs=g.dirs?g.dirs.concat(n.dirs):n.dirs),n.transition&&(g.transition=n.transition),m=g}catch(v){Xn.length=0,pt(v,e,1),m=sr(Gn)}return qt(g),m}function Gt(e){let t;for(let n=0;n{let t;for(const n in e)("class"===n||"style"===n||v(n))&&((t||(t={}))[n]=e[n]);return t},Xt=(e,t)=>{const n={};for(const r in e)y(r)&&r.slice(9)in t||(n[r]=e[r]);return n};function Jt(e,t,n){const r=Object.keys(t);if(r.length!==Object.keys(e).length)return!0;for(let o=0;o{l=!0;const[n,r]=tn(e,t,!0);b(o,n),r&&s.push(...r)};!n&&t.mixins.length&&t.mixins.forEach(r),e.extends&&r(e.extends),e.mixins&&e.mixins.forEach(r)}if(!r&&!l)return e.__props=d;if(E(r))for(let i=0;i-1,n[1]=r<0||t-1||x(n,"default"))&&s.push(e)}}}return e.__props=[o,s]}function nn(e){return"$"!==e[0]}function rn(e){const t=e&&e.toString().match(/^\s*function (\w+)/);return t?t[1]:""}function on(e,t){return rn(e)===rn(t)}function sn(e,t){return E(t)?t.findIndex((t=>on(t,e))):C(t)&&on(t,e)?0:-1}function ln(e,t,n=Rr,r=!1){if(n){const o=n[e]||(n[e]=[]),s=t.__weh||(t.__weh=(...r)=>{if(n.isUnmounted)return;se(),Ar(n);const o=ft(t,n,e,r);return Ar(null),le(),o});return r?o.unshift(s):o.push(s),s}}const cn=e=>(t,n=Rr)=>!Fr&&ln(e,t,n),an=cn("bm"),un=cn("m"),fn=cn("bu"),pn=cn("u"),dn=cn("bum"),hn=cn("um"),mn=cn("rtg"),gn=cn("rtc"),vn={};function yn(e,t,n){return bn(e,t,n)}function bn(e,t,{immediate:n,deep:r,flush:o,onTrack:s,onTrigger:l}=p,i=Rr){let c,a,u=!1;if(nt(e)?(c=()=>e.value,u=!!e._shallow):Qe(e)?(c=()=>e,r=!0):c=E(e)?()=>e.map((e=>nt(e)?e.value:Qe(e)?wn(e):C(e)?ut(e,i,2,[i&&i.proxy]):void 0)):C(e)?t?()=>ut(e,i,2,[i&&i.proxy]):()=>{if(!i||!i.isUnmounted)return a&&a(),ft(e,i,3,[f])}:h,t&&r){const e=c;c=()=>wn(e())}let f=e=>{a=v.options.onStop=()=>{ut(e,i,4)}},d=E(e)?[]:vn;const m=()=>{if(v.active)if(t){const e=v();(r||u||z(e,d))&&(a&&a(),ft(t,i,3,[e,d===vn?void 0:d,f]),d=e)}else v()};let g;m.allowRecurse=!!t,g="sync"===o?m:"post"===o?()=>Un(m,i&&i.suspense):()=>{!i||i.isMounted?function(e){At(e,yt,vt,bt)}(m):m()};const v=Z(c,{lazy:!0,onTrack:s,onTrigger:l,scheduler:g});return Mr(v,i),t?n?m():d=v():"post"===o?Un(v,i&&i.suspense):v(),()=>{ee(v),i&&_(i.effects,v)}}function _n(e,t,n){const r=this.proxy;return bn(R(e)?()=>r[e]:e.bind(r),t.bind(r),n,this)}function wn(e,t=new Set){if(!P(e)||t.has(e))return e;if(t.add(e),nt(e))wn(e.value,t);else if(E(e))for(let n=0;n{wn(e,t)}));else for(const n in e)wn(e[n],t);return e}const xn=e=>e.type.__isKeepAlive;function En(e,t,n=Rr){const r=e.__wdc||(e.__wdc=()=>{let t=n;for(;t;){if(t.isDeactivated)return;t=t.parent}e()});if(ln(t,r,n),n){let e=n.parent;for(;e&&e.parent;)xn(e.parent.vnode)&&kn(r,t,n,e),e=e.parent}}function kn(e,t,n,r){const o=ln(t,e,r,!0);hn((()=>{_(r[t],o)}),n)}const Sn=e=>"_"===e[0]||"$stable"===e,On=e=>E(e)?e.map(ar):[ar(e)],Cn=(e,t,n)=>Wt((e=>On(t(e))),n),Rn=(e,t)=>{const n=e._ctx;for(const r in e){if(Sn(r))continue;const o=e[r];if(C(o))t[r]=Cn(0,o,n);else if(null!=o){const e=On(o);t[r]=()=>e}}},An=(e,t)=>{const n=On(t);e.slots.default=()=>n};function Pn(e,t){if(null===Bt)return e;const n=Bt.proxy,r=e.dirs||(e.dirs=[]);for(let o=0;o(s.has(e)||(e&&C(e.install)?(s.add(e),e.install(i,...t)):C(e)&&(s.add(e),e(i,...t))),i),mixin:e=>(o.mixins.includes(e)||(o.mixins.push(e),(e.props||e.emits)&&(o.deopt=!0)),i),component:(e,t)=>t?(o.components[e]=t,i):o.components[e],directive:(e,t)=>t?(o.directives[e]=t,i):o.directives[e],mount(s,c,a){if(!l){const u=sr(n,r);return u.appContext=o,c&&t?t(u,s):e(u,s,a),l=!0,i._container=s,s.__vue_app__=i,u.component.proxy}},unmount(){l&&(e(null,i._container),delete i._container.__vue_app__)},provide:(e,t)=>(o.provides[e]=t,i)};return i}}function In(e){return C(e)?{setup:e,name:e.name}:e}const Tn={scheduler:Ct,allowRecurse:!0},Un=function(e,t){t&&t.pendingBranch?E(e)?t.effects.push(...e):t.effects.push(e):At(e,wt,_t,xt)},Vn=(e,t,n,r)=>{if(E(e))return void e.forEach(((e,o)=>Vn(e,t&&(E(t)?t[o]:t),n,r)));let o;if(r){if(r.type.__asyncLoader)return;o=4&r.shapeFlag?r.component.exposed||r.component.proxy:r.el}else o=null;const{i:s,r:l}=e,i=t&&t.r,c=s.refs===p?s.refs={}:s.refs,a=s.setupState;if(null!=i&&i!==l&&(R(i)?(c[i]=null,x(a,i)&&(a[i]=null)):nt(i)&&(i.value=null)),R(l)){const e=()=>{c[l]=o,x(a,l)&&(a[l]=o)};o?(e.id=-1,Un(e,n)):e()}else if(nt(l)){const e=()=>{l.value=o};o?(e.id=-1,Un(e,n)):e()}else C(l)&&ut(l,s,12,[o,c])};function Nn(e){return function(e,t){const{insert:n,remove:r,patchProp:o,forcePatchProp:s,createElement:l,createText:i,createComment:c,setText:a,setElementText:u,parentNode:f,nextSibling:m,setScopeId:g=h,cloneNode:v,insertStaticContent:y}=e,_=(e,t,n,r=null,o=null,s=null,l=!1,i=null,c=!1)=>{e&&!tr(e,t)&&(r=re(e),J(e,o,s,!0),e=null),-2===t.patchFlag&&(c=!1,t.dynamicChildren=null);const{type:a,ref:u,shapeFlag:f}=t;switch(a){case Kn:w(e,t,n,r);break;case Gn:E(e,t,n,r);break;case Hn:null==e&&k(t,n,r,l);break;case Wn:I(e,t,n,r,o,s,l,i,c);break;default:1&f?C(e,t,n,r,o,s,l,i,c):6&f?U(e,t,n,r,o,s,l,i,c):(64&f||128&f)&&a.process(e,t,n,r,o,s,l,i,c,ie)}null!=u&&o&&Vn(u,e&&e.ref,s,t)},w=(e,t,r,o)=>{if(null==e)n(t.el=i(t.children),r,o);else{const n=t.el=e.el;t.children!==e.children&&a(n,t.children)}},E=(e,t,r,o)=>{null==e?n(t.el=c(t.children||""),r,o):t.el=e.el},k=(e,t,n,r)=>{[e.el,e.anchor]=y(e.children,t,n,r)},S=({el:e,anchor:t},r,o)=>{let s;for(;e&&e!==t;)s=m(e),n(e,r,o),e=s;n(t,r,o)},O=({el:e,anchor:t})=>{let n;for(;e&&e!==t;)n=m(e),r(e),e=n;r(t)},C=(e,t,n,r,o,s,l,i,c)=>{l=l||"svg"===t.type,null==e?R(t,n,r,o,s,l,i,c):j(e,t,o,s,l,i,c)},R=(e,t,r,s,i,c,a,f)=>{let p,d;const{type:h,props:m,shapeFlag:g,transition:y,patchFlag:b,dirs:_}=e;if(e.el&&void 0!==v&&-1===b)p=e.el=v(e.el);else{if(p=e.el=l(e.type,c,m&&m.is,m),8&g?u(p,e.children):16&g&&P(e.children,p,null,s,i,c&&"foreignObject"!==h,a,f||!!e.dynamicChildren),_&&Fn(e,null,s,"created"),m){for(const t in m)T(t)||o(p,t,null,m[t],c,e.children,s,i,ne);(d=m.onVnodeBeforeMount)&&Ln(d,s,e)}A(p,e,e.scopeId,a,s)}_&&Fn(e,null,s,"beforeMount");const w=(!i||i&&!i.pendingBranch)&&y&&!y.persisted;w&&y.beforeEnter(p),n(p,t,r),((d=m&&m.onVnodeMounted)||w||_)&&Un((()=>{d&&Ln(d,s,e),w&&y.enter(p),_&&Fn(e,null,s,"mounted")}),i)},A=(e,t,n,r,o)=>{if(n&&g(e,n),r)for(let s=0;s{for(let a=c;a{const a=t.el=e.el;let{patchFlag:f,dynamicChildren:d,dirs:h}=t;f|=16&e.patchFlag;const m=e.props||p,g=t.props||p;let v;if((v=g.onVnodeBeforeUpdate)&&Ln(v,n,t,e),h&&Fn(t,e,n,"beforeUpdate"),f>0){if(16&f)M(a,t,m,g,n,r,l);else if(2&f&&m.class!==g.class&&o(a,"class",null,g.class,l),4&f&&o(a,"style",m.style,g.style,l),8&f){const i=t.dynamicProps;for(let t=0;t{v&&Ln(v,n,t,e),h&&Fn(t,e,n,"updated")}),r)},$=(e,t,n,r,o,s,l)=>{for(let i=0;i{if(n!==r){for(const a in r){if(T(a))continue;const u=r[a],f=n[a];(u!==f||s&&s(e,a))&&o(e,a,f,u,c,t.children,l,i,ne)}if(n!==p)for(const s in n)T(s)||s in r||o(e,s,n[s],null,c,t.children,l,i,ne)}},I=(e,t,r,o,s,l,c,a,u)=>{const f=t.el=e?e.el:i(""),p=t.anchor=e?e.anchor:i("");let{patchFlag:d,dynamicChildren:h,slotScopeIds:m}=t;d>0&&(u=!0),m&&(a=a?a.concat(m):m),null==e?(n(f,r,o),n(p,r,o),P(t.children,r,p,s,l,c,a,u)):d>0&&64&d&&h&&e.dynamicChildren?($(e.dynamicChildren,h,r,s,l,c,a),(null!=t.key||s&&t===s.subTree)&&Bn(e,t,!0)):z(e,t,r,p,s,l,c,a,u)},U=(e,t,n,r,o,s,l,i,c)=>{t.slotScopeIds=i,null==e?512&t.shapeFlag?o.ctx.activate(t,n,r,l,c):V(t,n,r,o,s,l,c):L(e,t,c)},V=(e,t,n,r,o,s,l)=>{const i=e.component=function(e,t,n){const r=e.type,o=(t?t.appContext:e.appContext)||Or,s={uid:Cr++,vnode:e,type:r,parent:t,appContext:o,root:null,next:null,subTree:null,update:null,render:null,proxy:null,exposed:null,withProxy:null,effects:null,provides:t?t.provides:Object.create(o.provides),accessCache:null,renderCache:[],components:null,directives:null,propsOptions:tn(r,o),emitsOptions:It(r,o),emit:null,emitted:null,propsDefaults:p,ctx:p,data:p,props:p,attrs:p,slots:p,refs:p,setupState:p,setupContext:null,suspense:n,suspenseId:n?n.pendingId:0,asyncDep:null,asyncResolved:!1,isMounted:!1,isUnmounted:!1,isDeactivated:!1,bc:null,c:null,bm:null,m:null,bu:null,u:null,um:null,bum:null,da:null,a:null,rtg:null,rtc:null,ec:null};return s.ctx={_:s},s.root=t?t.root:s,s.emit=Mt.bind(null,s),s}(e,r,o);if(xn(e)&&(i.ctx.renderer=ie),function(e,t=!1){Fr=t;const{props:n,children:r}=e.vnode,o=Pr(e);Yt(e,n,o,t),((e,t)=>{if(32&e.vnode.shapeFlag){const n=t._;n?(e.slots=t,K(t,"_",n)):Rn(t,e.slots={})}else e.slots={},t&&An(e,t);K(e.slots,nr,1)})(e,r);const s=o?function(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=new Proxy(e.ctx,kr);const{setup:r}=n;if(r){const n=e.setupContext=r.length>1?function(e){const t=t=>{e.exposed=it(t)};return{attrs:e.attrs,slots:e.slots,emit:e.emit,expose:t}}(e):null;Rr=e,se();const o=ut(r,e,0,[e.props,n]);if(le(),Rr=null,F(o)){if(t)return o.then((t=>{jr(e,t)})).catch((t=>{pt(t,e,0)}));e.asyncDep=o}else jr(e,o)}else $r(e)}(e,t):void 0;Fr=!1}(i),i.asyncDep){if(o&&o.registerDep(i,D),!e.el){const e=i.subTree=sr(Gn);E(null,e,t,n)}}else D(i,e,t,n,o,s,l)},L=(e,t,n)=>{const r=t.component=e.component;if(function(e,t,n){const{props:r,children:o,component:s}=e,{props:l,children:i,patchFlag:c}=t,a=s.emitsOptions;if(t.dirs||t.transition)return!0;if(!(n&&c>=0))return!(!o&&!i||i&&i.$stable)||r!==l&&(r?!l||Jt(r,l,a):!!l);if(1024&c)return!0;if(16&c)return r?Jt(r,l,a):!!l;if(8&c){const e=t.dynamicProps;for(let t=0;tgt&&mt.splice(t,1)}(r.update),r.update()}else t.component=e.component,t.el=e.el,r.vnode=t},D=(e,t,n,r,o,s,l)=>{e.update=Z((function(){if(e.isMounted){let t,{next:n,bu:r,u:i,parent:c,vnode:a}=e,u=n;n?(n.el=a.el,q(e,n,l)):n=a,r&&W(r),(t=n.props&&n.props.onVnodeBeforeUpdate)&&Ln(t,c,n,a);const p=Kt(e),d=e.subTree;e.subTree=p,_(d,p,f(d.el),re(d),e,o,s),n.el=p.el,null===u&&function({vnode:e,parent:t},n){for(;t&&t.subTree===e;)(e=t.vnode).el=n,t=t.parent}(e,p.el),i&&Un(i,o),(t=n.props&&n.props.onVnodeUpdated)&&Un((()=>{Ln(t,c,n,a)}),o)}else{let l;const{el:i,props:c}=t,{bm:a,m:u,parent:f}=e;a&&W(a),(l=c&&c.onVnodeBeforeMount)&&Ln(l,f,t);const p=e.subTree=Kt(e);if(i&&ue?ue(t.el,p,e,o,null):(_(null,p,n,r,e,o,s),t.el=p.el),u&&Un(u,o),l=c&&c.onVnodeMounted){const e=t;Un((()=>{Ln(l,f,e)}),o)}const{a:d}=e;d&&256&t.shapeFlag&&Un(d,o),e.isMounted=!0,t=n=r=null}}),Tn)},q=(e,t,n)=>{t.component=e;const r=e.vnode.props;e.vnode=t,e.next=null,function(e,t,n,r){const{props:o,attrs:s,vnode:{patchFlag:l}}=e,i=et(o),[c]=e.propsOptions;if(!(r||l>0)||16&l){let r;Zt(e,t,o,s);for(const s in i)t&&(x(t,s)||(r=B(s))!==s&&x(t,r))||(c?!n||void 0===n[s]&&void 0===n[r]||(o[s]=en(c,t||p,s,void 0,e)):delete o[s]);if(s!==i)for(const e in s)t&&x(t,e)||delete s[e]}else if(8&l){const n=e.vnode.dynamicProps;for(let r=0;r{const{vnode:r,slots:o}=e;let s=!0,l=p;if(32&r.shapeFlag){const e=t._;e?n&&1===e?s=!1:(b(o,t),n||1!==e||delete o._):(s=!t.$stable,Rn(t,o)),l=t}else t&&(An(e,t),l={default:1});if(s)for(const i in o)Sn(i)||i in l||delete o[i]})(e,t.children,n),se(),Pt(void 0,e.update),le()},z=(e,t,n,r,o,s,l,i,c=!1)=>{const a=e&&e.children,f=e?e.shapeFlag:0,p=t.children,{patchFlag:d,shapeFlag:h}=t;if(d>0){if(128&d)return void H(a,p,n,r,o,s,l,i,c);if(256&d)return void G(a,p,n,r,o,s,l,i,c)}8&h?(16&f&&ne(a,o,s),p!==a&&u(n,p)):16&f?16&h?H(a,p,n,r,o,s,l,i,c):ne(a,o,s,!0):(8&f&&u(n,""),16&h&&P(p,n,r,o,s,l,i,c))},G=(e,t,n,r,o,s,l,i,c)=>{t=t||d;const a=(e=e||d).length,u=t.length,f=Math.min(a,u);let p;for(p=0;pu?ne(e,o,s,!0,!1,f):P(t,n,r,o,s,l,i,c,f)},H=(e,t,n,r,o,s,l,i,c)=>{let a=0;const u=t.length;let f=e.length-1,p=u-1;for(;a<=f&&a<=p;){const r=e[a],u=t[a]=c?ur(t[a]):ar(t[a]);if(!tr(r,u))break;_(r,u,n,null,o,s,l,i,c),a++}for(;a<=f&&a<=p;){const r=e[f],a=t[p]=c?ur(t[p]):ar(t[p]);if(!tr(r,a))break;_(r,a,n,null,o,s,l,i,c),f--,p--}if(a>f){if(a<=p){const e=p+1,f=ep)for(;a<=f;)J(e[a],o,s,!0),a++;else{const h=a,m=a,g=new Map;for(a=m;a<=p;a++){const e=t[a]=c?ur(t[a]):ar(t[a]);null!=e.key&&g.set(e.key,a)}let v,y=0;const b=p-m+1;let w=!1,x=0;const E=new Array(b);for(a=0;a=b){J(r,o,s,!0);continue}let u;if(null!=r.key)u=g.get(r.key);else for(v=m;v<=p;v++)if(0===E[v-m]&&tr(r,t[v])){u=v;break}void 0===u?J(r,o,s,!0):(E[u-m]=a+1,u>=x?x=u:w=!0,_(r,t[u],n,null,o,s,l,i,c),y++)}const k=w?function(e){const t=e.slice(),n=[0];let r,o,s,l,i;const c=e.length;for(r=0;r0&&(t[r]=n[s-1]),n[s]=r)}}s=n.length,l=n[s-1];for(;s-- >0;)n[s]=l,l=t[l];return n}(E):d;for(v=k.length-1,a=b-1;a>=0;a--){const e=m+a,f=t[e],p=e+1{const{el:l,type:i,transition:c,children:a,shapeFlag:u}=e;if(6&u)return void X(e.component.subTree,t,r,o);if(128&u)return void e.suspense.move(t,r,o);if(64&u)return void i.move(e,t,r,ie);if(i===Wn){n(l,t,r);for(let e=0;ec.enter(l)),s);else{const{leave:e,delayLeave:o,afterLeave:s}=c,i=()=>n(l,t,r),a=()=>{e(l,(()=>{i(),s&&s()}))};o?o(l,i,a):a()}else n(l,t,r)},J=(e,t,n,r=!1,o=!1)=>{const{type:s,props:l,ref:i,children:c,dynamicChildren:a,shapeFlag:u,patchFlag:f,dirs:p}=e;if(null!=i&&Vn(i,null,n,null),256&u)return void t.ctx.deactivate(e);const d=1&u&&p;let h;if((h=l&&l.onVnodeBeforeUnmount)&&Ln(h,t,e),6&u)te(e.component,n,r);else{if(128&u)return void e.suspense.unmount(n,r);d&&Fn(e,null,t,"beforeUnmount"),64&u?e.type.remove(e,t,n,o,ie,r):a&&(s!==Wn||f>0&&64&f)?ne(a,t,n,!1,!0):(s===Wn&&(128&f||256&f)||!o&&16&u)&&ne(c,t,n),r&&Q(e)}((h=l&&l.onVnodeUnmounted)||d)&&Un((()=>{h&&Ln(h,t,e),d&&Fn(e,null,t,"unmounted")}),n)},Q=e=>{const{type:t,el:n,anchor:o,transition:s}=e;if(t===Wn)return void Y(n,o);if(t===Hn)return void O(e);const l=()=>{r(n),s&&!s.persisted&&s.afterLeave&&s.afterLeave()};if(1&e.shapeFlag&&s&&!s.persisted){const{leave:t,delayLeave:r}=s,o=()=>t(n,l);r?r(e.el,l,o):o()}else l()},Y=(e,t)=>{let n;for(;e!==t;)n=m(e),r(e),e=n;r(t)},te=(e,t,n)=>{const{bum:r,effects:o,update:s,subTree:l,um:i}=e;if(r&&W(r),o)for(let c=0;c{e.isUnmounted=!0}),t),t&&t.pendingBranch&&!t.isUnmounted&&e.asyncDep&&!e.asyncResolved&&e.suspenseId===t.pendingId&&(t.deps--,0===t.deps&&t.resolve())},ne=(e,t,n,r=!1,o=!1,s=0)=>{for(let l=s;l6&e.shapeFlag?re(e.component.subTree):128&e.shapeFlag?e.suspense.next():m(e.anchor||e.el),oe=(e,t,n)=>{null==e?t._vnode&&J(t._vnode,null,null,!0):_(t._vnode||null,e,t,null,null,null,n),Ft(),t._vnode=e},ie={p:_,um:J,m:X,r:Q,mt:V,mc:P,pc:z,pbc:$,n:re,o:e};let ae,ue;t&&([ae,ue]=t(ie));return{render:oe,hydrate:ae,createApp:Mn(oe,ae)}}(e)}function Ln(e,t,n,r=null){ft(e,t,7,[n,r])}function Bn(e,t,n=!1){const r=e.children,o=t.children;if(E(r)&&E(o))for(let s=0;snull!=e?e:null,or=({ref:e})=>null!=e?R(e)||nt(e)||C(e)?{i:Bt,r:e}:e:null,sr=function(e,t=null,n=null,o=0,s=null,l=!1){e&&e!==qn||(e=Gn);if(er(e)){const r=lr(e,t,!0);return n&&fr(r,n),r}c=e,C(c)&&"__vccOpts"in c&&(e=e.__vccOpts);var c;if(t){(Ze(t)||nr in t)&&(t=b({},t));let{class:e,style:n}=t;e&&!R(e)&&(t.class=i(e)),P(n)&&(Ze(n)&&!E(n)&&(n=b({},n)),t.style=r(n))}const a=R(e)?1:(e=>e.__isSuspense)(e)?128:(e=>e.__isTeleport)(e)?64:P(e)?4:C(e)?2:0,u={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&rr(t),ref:t&&or(t),scopeId:Dt,slotScopeIds:null,children:null,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:a,patchFlag:o,dynamicProps:s,dynamicChildren:null,appContext:null};if(fr(u,n),128&a){const{content:e,fallback:t}=function(e){const{shapeFlag:t,children:n}=e;let r,o;return 32&t?(r=Qt(n.default),o=Qt(n.fallback)):(r=Qt(n),o=ar(null)),{content:r,fallback:o}}(u);u.ssContent=e,u.ssFallback=t}!l&&Jn&&(o>0||6&a)&&32!==o&&Jn.push(u);return u};function lr(e,t,n=!1){const{props:o,ref:s,patchFlag:l,children:c}=e,a=t?function(...e){const t=b({},e[0]);for(let n=1;n1)return n&&C(t)?t():t}}let hr=!0;function mr(e,t,n=[],r=[],o=[],s=!1){const{mixins:l,extends:i,data:c,computed:a,methods:u,watch:f,provide:d,inject:m,components:g,directives:v,beforeMount:y,mounted:_,beforeUpdate:w,updated:x,activated:k,deactivated:S,beforeDestroy:O,beforeUnmount:R,destroyed:A,unmounted:F,render:j,renderTracked:$,renderTriggered:M,errorCaptured:I,expose:T}=t,U=e.proxy,V=e.ctx,N=e.appContext.mixins;if(s&&j&&e.render===h&&(e.render=j),s||(hr=!1,gr("beforeCreate","bc",t,e,N),hr=!0,yr(e,N,n,r,o)),i&&mr(e,i,n,r,o,!0),l&&yr(e,l,n,r,o),m)if(E(m))for(let p=0;pbr(e,t,U))),c&&br(e,c,U)),a)for(const p in a){const e=a[p],t=Tr({get:C(e)?e.bind(U,U):C(e.get)?e.get.bind(U,U):h,set:!C(e)&&C(e.set)?e.set.bind(U):h});Object.defineProperty(V,p,{enumerable:!0,configurable:!0,get:()=>t.value,set:e=>t.value=e})}var L;if(f&&r.push(f),!s&&r.length&&r.forEach((e=>{for(const t in e)_r(e[t],V,U,t)})),d&&o.push(d),!s&&o.length&&o.forEach((e=>{const t=C(e)?e.call(U):e;Reflect.ownKeys(t).forEach((e=>{pr(e,t[e])}))})),s&&(g&&b(e.components||(e.components=b({},e.type.components)),g),v&&b(e.directives||(e.directives=b({},e.type.directives)),v)),s||gr("created","c",t,e,N),y&&an(y.bind(U)),_&&un(_.bind(U)),w&&fn(w.bind(U)),x&&pn(x.bind(U)),k&&En(k.bind(U),"a",L),S&&function(e,t){En(e,"da",t)}(S.bind(U)),I&&((e,t=Rr)=>{ln("ec",e,t)})(I.bind(U)),$&&gn($.bind(U)),M&&mn(M.bind(U)),R&&dn(R.bind(U)),F&&hn(F.bind(U)),E(T)&&!s)if(T.length){const t=e.exposed||(e.exposed=it({}));T.forEach((e=>{t[e]=function(e,t){return nt(e[t])?e[t]:new ct(e,t)}(U,e)}))}else e.exposed||(e.exposed=p)}function gr(e,t,n,r,o){for(let s=0;s{let t=e;for(let e=0;en[r];if(R(e)){const n=t[e];C(n)&&yn(o,n)}else if(C(e))yn(o,e.bind(n));else if(P(e))if(E(e))e.forEach((e=>_r(e,t,n,r)));else{const r=C(e.handler)?e.handler.bind(n):t[e.handler];C(r)&&yn(o,r,e)}}function wr(e,t,n){const r=n.appContext.config.optionMergeStrategies,{mixins:o,extends:s}=t;s&&wr(e,s,n),o&&o.forEach((t=>wr(e,t,n)));for(const l in t)r&&x(r,l)?e[l]=r[l](e[l],t[l],n.proxy,l):e[l]=t[l]}const xr=e=>e?Pr(e)?e.exposed?e.exposed:e.proxy:xr(e.parent):null,Er=b(Object.create(null),{$:e=>e,$el:e=>e.vnode.el,$data:e=>e.data,$props:e=>e.props,$attrs:e=>e.attrs,$slots:e=>e.slots,$refs:e=>e.refs,$parent:e=>xr(e.parent),$root:e=>xr(e.root),$emit:e=>e.emit,$options:e=>function(e){const t=e.type,{__merged:n,mixins:r,extends:o}=t;if(n)return n;const s=e.appContext.mixins;if(!s.length&&!r&&!o)return t;const l={};return s.forEach((t=>wr(l,t,e))),wr(l,t,e),t.__merged=l}(e),$forceUpdate:e=>()=>Ct(e.update),$nextTick:e=>Ot.bind(e.proxy),$watch:e=>_n.bind(e)}),kr={get({_:e},t){const{ctx:n,setupState:r,data:o,props:s,accessCache:l,type:i,appContext:c}=e;if("__v_skip"===t)return!0;let a;if("$"!==t[0]){const i=l[t];if(void 0!==i)switch(i){case 0:return r[t];case 1:return o[t];case 3:return n[t];case 2:return s[t]}else{if(r!==p&&x(r,t))return l[t]=0,r[t];if(o!==p&&x(o,t))return l[t]=1,o[t];if((a=e.propsOptions[0])&&x(a,t))return l[t]=2,s[t];if(n!==p&&x(n,t))return l[t]=3,n[t];hr&&(l[t]=4)}}const u=Er[t];let f,d;return u?("$attrs"===t&&ie(e,0,t),u(e)):(f=i.__cssModules)&&(f=f[t])?f:n!==p&&x(n,t)?(l[t]=3,n[t]):(d=c.config.globalProperties,x(d,t)?d[t]:void 0)},set({_:e},t,n){const{data:r,setupState:o,ctx:s}=e;if(o!==p&&x(o,t))o[t]=n;else if(r!==p&&x(r,t))r[t]=n;else if(x(e.props,t))return!1;return("$"!==t[0]||!(t.slice(1)in e))&&(s[t]=n,!0)},has({_:{data:e,setupState:t,accessCache:n,ctx:r,appContext:o,propsOptions:s}},l){let i;return void 0!==n[l]||e!==p&&x(e,l)||t!==p&&x(t,l)||(i=s[0])&&x(i,l)||x(r,l)||x(Er,l)||x(o.config.globalProperties,l)}},Sr=b({},kr,{get(e,t){if(t!==Symbol.unscopables)return kr.get(e,t,e)},has:(e,n)=>"_"!==n[0]&&!t(n)}),Or=jn();let Cr=0;let Rr=null;const Ar=e=>{Rr=e};function Pr(e){return 4&e.vnode.shapeFlag}let Fr=!1;function jr(e,t,n){C(t)?e.render=t:P(t)&&(e.setupState=it(t)),$r(e)}function $r(e,t){const n=e.type;e.render||(e.render=n.render||h,e.render._rc&&(e.withProxy=new Proxy(e.ctx,Sr))),Rr=e,se(),mr(e,n),le(),Rr=null}function Mr(e,t=Rr){t&&(t.effects||(t.effects=[])).push(e)}function Ir(e){return C(e)&&e.displayName||e.name}function Tr(e){const t=function(e){let t,n;return C(e)?(t=e,n=h):(t=e.get,n=e.set),new at(t,n,C(e)||!e.set)}(e);return Mr(t.effect),t}function Ur(e,t,n){const r=arguments.length;return 2===r?P(t)&&!E(t)?er(t)?sr(e,null,[t]):sr(e,t):sr(e,null,t):(r>3?n=Array.prototype.slice.call(arguments,2):3===r&&er(n)&&(n=[n]),sr(e,t,n))}function Vr(e,t){let n;if(E(e)||R(e)){n=new Array(e.length);for(let r=0,o=e.length;r{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,r)=>{const o=t?Br.createElementNS(Lr,e):Br.createElement(e,n?{is:n}:void 0);return"select"===e&&r&&null!=r.multiple&&o.setAttribute("multiple",r.multiple),o},createText:e=>Br.createTextNode(e),createComment:e=>Br.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Br.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},cloneNode(e){const t=e.cloneNode(!0);return"_value"in e&&(t._value=e._value),t},insertStaticContent(e,t,n,r){const o=r?qr||(qr=Br.createElementNS(Lr,"svg")):Dr||(Dr=Br.createElement("div"));o.innerHTML=e;const s=o.firstChild;let l=s,i=l;for(;l;)i=l,zr.insert(l,t,n),l=o.firstChild;return[s,i]}};const Wr=/\s*!important$/;function Kr(e,t,n){if(E(n))n.forEach((n=>Kr(e,t,n)));else if(t.startsWith("--"))e.setProperty(t,n);else{const r=function(e,t){const n=Hr[t];if(n)return n;let r=N(t);if("filter"!==r&&r in e)return Hr[t]=r;r=D(r);for(let o=0;odocument.createEvent("Event").timeStamp&&(Jr=()=>performance.now());const e=navigator.userAgent.match(/firefox\/(\d+)/i);Qr=!!(e&&Number(e[1])<=53)}let Yr=0;const Zr=Promise.resolve(),eo=()=>{Yr=0};function to(e,t,n,r){e.addEventListener(t,n,r)}function no(e,t,n,r,o=null){const s=e._vei||(e._vei={}),l=s[t];if(r&&l)l.value=r;else{const[n,i]=function(e){let t;if(ro.test(e)){let n;for(t={};n=e.match(ro);)e=e.slice(0,e.length-n[0].length),t[n[0].toLowerCase()]=!0}return[B(e.slice(2)),t]}(t);if(r){to(e,n,s[t]=function(e,t){const n=e=>{const r=e.timeStamp||Jr();(Qr||r>=n.attached-1)&&ft(function(e,t){if(E(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map((e=>t=>!t._stopped&&e(t)))}return t}(e,n.value),t,5,[e])};return n.value=e,n.attached=(()=>Yr||(Zr.then(eo),Yr=Jr()))(),n}(r,o),i)}else l&&(!function(e,t,n,r){e.removeEventListener(t,n,r)}(e,n,l,i),s[t]=void 0)}}const ro=/(?:Once|Passive|Capture)$/;const oo=/^on[a-z]/;const so=e=>{const t=e.props["onUpdate:modelValue"];return E(t)?e=>W(t,e):t};function lo(e){e.target.composing=!0}function io(e){const t=e.target;t.composing&&(t.composing=!1,function(e,t){const n=document.createEvent("HTMLEvents");n.initEvent(t,!0,!0),e.dispatchEvent(n)}(t,"input"))}const co={created(e,{modifiers:{lazy:t,trim:n,number:r}},o){e._assign=so(o);const s=r||"number"===e.type;to(e,t?"change":"input",(t=>{if(t.target.composing)return;let r=e.value;n?r=r.trim():s&&(r=G(r)),e._assign(r)})),n&&to(e,"change",(()=>{e.value=e.value.trim()})),t||(to(e,"compositionstart",lo),to(e,"compositionend",io),to(e,"change",io))},mounted(e,{value:t}){e.value=null==t?"":t},beforeUpdate(e,{value:t,modifiers:{trim:n,number:r}},o){if(e._assign=so(o),e.composing)return;if(document.activeElement===e){if(n&&e.value.trim()===t)return;if((r||"number"===e.type)&&G(e.value)===t)return}const s=null==t?"":t;e.value!==s&&(e.value=s)}},ao={created(e,{value:t},n){e.checked=c(t,n.props.value),e._assign=so(n),to(e,"change",(()=>{e._assign(po(e))}))},beforeUpdate(e,{value:t,oldValue:n},r){e._assign=so(r),t!==n&&(e.checked=c(t,r.props.value))}},uo={created(e,{value:t,modifiers:{number:n}},r){const o=S(t);to(e,"change",(()=>{const t=Array.prototype.filter.call(e.options,(e=>e.selected)).map((e=>n?G(po(e)):po(e)));e._assign(e.multiple?o?new Set(t):t:t[0])})),e._assign=so(r)},mounted(e,{value:t}){fo(e,t)},beforeUpdate(e,t,n){e._assign=so(n)},updated(e,{value:t}){fo(e,t)}};function fo(e,t){const n=e.multiple;if(!n||E(t)||S(t)){for(let r=0,o=e.options.length;r-1:o.selected=t.has(s);else if(c(po(o),t))return void(e.selectedIndex=r)}n||(e.selectedIndex=-1)}}function po(e){return"_value"in e?e._value:e.value}const ho=["ctrl","shift","alt","meta"],mo={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&0!==e.button,middle:e=>"button"in e&&1!==e.button,right:e=>"button"in e&&2!==e.button,exact:(e,t)=>ho.some((n=>e[`${n}Key`]&&!t.includes(n)))},go=(e,t)=>(n,...r)=>{for(let e=0;en=>{if(!("key"in n))return;const r=B(n.key);return t.some((e=>e===r||vo[e]===r))?e(n):void 0},bo={beforeMount(e,{value:t},{transition:n}){e._vod="none"===e.style.display?"":e.style.display,n&&t?n.beforeEnter(e):_o(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:r}){!t!=!n&&(r?t?(r.beforeEnter(e),_o(e,!0),r.enter(e)):r.leave(e,(()=>{_o(e,!1)})):_o(e,t))},beforeUnmount(e,{value:t}){_o(e,t)}};function _o(e,t){e.style.display=t?e._vod:"none"}const wo=b({patchProp:(e,t,r,o,s=!1,l,i,c,a)=>{switch(t){case"class":!function(e,t,n){if(null==t&&(t=""),n)e.setAttribute("class",t);else{const n=e._vtc;n&&(t=(t?[t,...n]:[...n]).join(" ")),e.className=t}}(e,o,s);break;case"style":!function(e,t,n){const r=e.style;if(n)if(R(n)){if(t!==n){const t=r.display;r.cssText=n,"_vod"in e&&(r.display=t)}}else{for(const e in n)Kr(r,e,n[e]);if(t&&!R(t))for(const e in t)null==n[e]&&Kr(r,e,"")}else e.removeAttribute("style")}(e,r,o);break;default:v(t)?y(t)||no(e,t,0,o,i):function(e,t,n,r){if(r)return"innerHTML"===t||!!(t in e&&oo.test(t)&&C(n));if("spellcheck"===t||"draggable"===t)return!1;if("form"===t)return!1;if("list"===t&&"INPUT"===e.tagName)return!1;if("type"===t&&"TEXTAREA"===e.tagName)return!1;if(oo.test(t)&&R(n))return!1;return t in e}(e,t,o,s)?function(e,t,n,r,o,s,l){if("innerHTML"===t||"textContent"===t)return r&&l(r,o,s),void(e[t]=null==n?"":n);if("value"!==t||"PROGRESS"===e.tagName){if(""===n||null==n){const r=typeof e[t];if(""===n&&"boolean"===r)return void(e[t]=!0);if(null==n&&"string"===r)return e[t]="",void e.removeAttribute(t);if("number"===r)return e[t]=0,void e.removeAttribute(t)}try{e[t]=n}catch(i){}}else{e._value=n;const t=null==n?"":n;e.value!==t&&(e.value=t)}}(e,t,o,l,i,c,a):("true-value"===t?e._trueValue=o:"false-value"===t&&(e._falseValue=o),function(e,t,r,o){if(o&&t.startsWith("xlink:"))null==r?e.removeAttributeNS(Xr,t.slice(6,t.length)):e.setAttributeNS(Xr,t,r);else{const o=n(t);null==r||o&&!1===r?e.removeAttribute(t):e.setAttribute(t,o?"":r)}}(e,t,o,s))}},forcePatchProp:(e,t)=>"value"===t},zr);let xo;const Eo=(...e)=>{const t=(xo||(xo=Nn(wo))).createApp(...e),{mount:n}=t;return t.mount=e=>{const r=function(e){if(R(e)){return document.querySelector(e)}return e} -/*! - * vue-router v4.0.8 - * (c) 2021 Eduardo San Martin Morote - * @license MIT - */(e);if(!r)return;const o=t._component;C(o)||o.render||o.template||(o.template=r.innerHTML),r.innerHTML="";const s=n(r,!1,r instanceof SVGElement);return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),s},t};const ko="function"==typeof Symbol&&"symbol"==typeof Symbol.toStringTag,So=e=>ko?Symbol(e):"_vr_"+e,Oo=So("rvlm"),Co=So("rvd"),Ro=So("r"),Ao=So("rl"),Po=So("rvl"),Fo="undefined"!=typeof window;const jo=Object.assign;function $o(e,t){const n={};for(const r in t){const o=t[r];n[r]=Array.isArray(o)?o.map(e):e(o)}return n}let Mo=()=>{};const Io=/\/$/;function To(e,t,n="/"){let r,o={},s="",l="";const i=t.indexOf("?"),c=t.indexOf("#",i>-1?i:0);return i>-1&&(r=t.slice(0,i),s=t.slice(i+1,c>-1?c:t.length),o=e(s)),c>-1&&(r=r||t.slice(0,c),l=t.slice(c,t.length)),r=function(e,t){if(e.startsWith("/"))return e;if(!e)return t;const n=t.split("/"),r=e.split("/");let o,s,l=n.length-1;for(o=0;oe===t[n])):1===e.length&&e[0]===t}var Do,qo,zo,Wo;function Ko(e){if(!e)if(Fo){const t=document.querySelector("base");e=(e=t&&t.getAttribute("href")||"/").replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return"/"!==e[0]&&"#"!==e[0]&&(e="/"+e),e.replace(Io,"")}(qo=Do||(Do={})).pop="pop",qo.push="push",(Wo=zo||(zo={})).back="back",Wo.forward="forward",Wo.unknown="";const Go=/^[^#]+#/;function Ho(e,t){return e.replace(Go,"#")+t}const Xo=()=>({left:window.pageXOffset,top:window.pageYOffset});function Jo(e){let t;if("el"in e){let n=e.el;const r="string"==typeof n&&n.startsWith("#"),o="string"==typeof n?r?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!o)return;t=function(e,t){const n=document.documentElement.getBoundingClientRect(),r=e.getBoundingClientRect();return{behavior:t.behavior,left:r.left-n.left-(t.left||0),top:r.top-n.top-(t.top||0)}}(o,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(null!=t.left?t.left:window.pageXOffset,null!=t.top?t.top:window.pageYOffset)}function Qo(e,t){return(history.state?history.state.position-t:-1)+e}const Yo=new Map;function Zo(e,t){const{pathname:n,search:r,hash:o}=t,s=e.indexOf("#");if(s>-1){let t=o.includes(e.slice(s))?e.slice(s).length:1,n=o.slice(t);return"/"!==n[0]&&(n="/"+n),Uo(n,"")}return Uo(n,e)+r+o}function es(e,t,n,r=!1,o=!1){return{back:e,current:t,forward:n,replaced:r,position:window.history.length,scroll:o?Xo():null}}function ts(e){const{history:t,location:n}=window;let r={value:Zo(e,n)},o={value:t.state};function s(r,s,l){const i=e.indexOf("#"),c=i>-1?(n.host&&document.querySelector("base")?e:e.slice(i))+r:location.protocol+"//"+location.host+e+r;try{t[l?"replaceState":"pushState"](s,"",c),o.value=s}catch(a){console.error(a),n[l?"replace":"assign"](c)}}return o.value||s(r.value,{back:null,current:r.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0),{location:r,state:o,push:function(e,n){const l=jo({},o.value,t.state,{forward:e,scroll:Xo()});s(l.current,l,!0),s(e,jo({},es(r.value,e,null),{position:l.position+1},n),!1),r.value=e},replace:function(e,n){s(e,jo({},t.state,es(o.value.back,e,o.value.forward,!0),n,{position:o.value.position}),!0),r.value=e}}}function ns(e){const t=ts(e=Ko(e)),n=function(e,t,n,r){let o=[],s=[],l=null;const i=({state:s})=>{const i=Zo(e,location),c=n.value,a=t.value;let u=0;if(s){if(n.value=i,t.value=s,l&&l===c)return void(l=null);u=a?s.position-a.position:0}else r(i);o.forEach((e=>{e(n.value,c,{delta:u,type:Do.pop,direction:u?u>0?zo.forward:zo.back:zo.unknown})}))};function c(){const{history:e}=window;e.state&&e.replaceState(jo({},e.state,{scroll:Xo()}),"")}return window.addEventListener("popstate",i),window.addEventListener("beforeunload",c),{pauseListeners:function(){l=n.value},listen:function(e){o.push(e);const t=()=>{const t=o.indexOf(e);t>-1&&o.splice(t,1)};return s.push(t),t},destroy:function(){for(const e of s)e();s=[],window.removeEventListener("popstate",i),window.removeEventListener("beforeunload",c)}}}(e,t.state,t.location,t.replace);const r=jo({location:"",base:e,go:function(e,t=!0){t||n.pauseListeners(),history.go(e)},createHref:Ho.bind(null,e)},t,n);return Object.defineProperty(r,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(r,"state",{enumerable:!0,get:()=>t.state.value}),r}function rs(e){return(e=location.host?e||location.pathname+location.search:"").indexOf("#")<0&&(e+="#"),ns(e)}function os(e){return"string"==typeof e||"symbol"==typeof e}const ss={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0},ls=So("nf");var is,cs;function as(e,t){return jo(new Error,{type:e,[ls]:!0},t)}function us(e,t){return e instanceof Error&&ls in e&&(null==t||!!(e.type&t))}(cs=is||(is={}))[cs.aborted=4]="aborted",cs[cs.cancelled=8]="cancelled",cs[cs.duplicated=16]="duplicated";const fs={sensitive:!1,strict:!1,start:!0,end:!0},ps=/[.+*?^${}()[\]/\\]/g;function ds(e,t){let n=0;for(;nt.length?1===t.length&&80===t[0]?1:-1:0}function hs(e,t){let n=0;const r=e.score,o=t.score;for(;n1&&("*"===i||"+"===i)&&t(`A repeatable param (${a}) must be alone in its segment. eg: '/:ids+.`),s.push({type:1,value:a,regexp:u,repeatable:"*"===i||"+"===i,optional:"*"===i||"?"===i})):t("Invalid state to consume buffer"),a="")}function p(){a+=i}for(;c{s(p)}:Mo}function s(e){if(os(e)){const t=r.get(e);t&&(r.delete(e),n.splice(n.indexOf(t),1),t.children.forEach(s),t.alias.forEach(s))}else{let t=n.indexOf(e);t>-1&&(n.splice(t,1),e.record.name&&r.delete(e.record.name),e.children.forEach(s),e.alias.forEach(s))}}function l(e){let t=0;for(;t=0;)t++;n.splice(t,0,e),e.record.name&&!_s(e)&&r.set(e.record.name,e)}return t=xs({strict:!1,end:!0,sensitive:!1},t),e.forEach((e=>o(e))),{addRoute:o,resolve:function(e,t){let o,s,l,i={};if("name"in e&&e.name){if(o=r.get(e.name),!o)throw as(1,{location:e});l=o.record.name,i=jo(function(e,t){let n={};for(let r of t)r in e&&(n[r]=e[r]);return n}(t.params,o.keys.filter((e=>!e.optional)).map((e=>e.name))),e.params),s=o.stringify(i)}else if("path"in e)s=e.path,o=n.find((e=>e.re.test(s))),o&&(i=o.parse(s),l=o.record.name);else{if(o=t.name?r.get(t.name):n.find((e=>e.re.test(t.path))),!o)throw as(1,{location:e,currentLocation:t});l=o.record.name,i=jo({},t.params,e.params),s=o.stringify(i)}const c=[];let a=o;for(;a;)c.unshift(a.record),a=a.parent;return{name:l,path:s,params:i,matched:c,meta:ws(c)}},removeRoute:s,getRoutes:function(){return n},getRecordMatcher:function(e){return r.get(e)}}}function bs(e){const t={},n=e.props||!1;if("component"in e)t.default=n;else for(let r in e.components)t[r]="boolean"==typeof n?n:n[r];return t}function _s(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function ws(e){return e.reduce(((e,t)=>jo(e,t.meta)),{})}function xs(e,t){let n={};for(let r in e)n[r]=r in t?t[r]:e[r];return n}const Es=/#/g,ks=/&/g,Ss=/\//g,Os=/=/g,Cs=/\?/g,Rs=/\+/g,As=/%5B/g,Ps=/%5D/g,Fs=/%5E/g,js=/%60/g,$s=/%7B/g,Ms=/%7C/g,Is=/%7D/g,Ts=/%20/g;function Us(e){return encodeURI(""+e).replace(Ms,"|").replace(As,"[").replace(Ps,"]")}function Vs(e){return Us(e).replace(Rs,"%2B").replace(Ts,"+").replace(Es,"%23").replace(ks,"%26").replace(js,"`").replace($s,"{").replace(Is,"}").replace(Fs,"^")}function Ns(e){return function(e){return Us(e).replace(Es,"%23").replace(Cs,"%3F")}(e).replace(Ss,"%2F")}function Ls(e){try{return decodeURIComponent(""+e)}catch(t){}return""+e}function Bs(e){const t={};if(""===e||"?"===e)return t;const n=("?"===e[0]?e.slice(1):e).split("&");for(let r=0;re&&Vs(e))):[r&&Vs(r)]).forEach((e=>{void 0!==e&&(t+=(t.length?"&":"")+n,null!=e&&(t+="="+e))}))}return t}function qs(e){const t={};for(let n in e){let r=e[n];void 0!==r&&(t[n]=Array.isArray(r)?r.map((e=>null==e?null:""+e)):null==r?r:""+r)}return t}function zs(){let e=[];return{add:function(t){return e.push(t),()=>{const n=e.indexOf(t);n>-1&&e.splice(n,1)}},list:()=>e,reset:function(){e=[]}}}function Ws(e,t,n,r,o){const s=r&&(r.enterCallbacks[o]=r.enterCallbacks[o]||[]);return()=>new Promise(((l,i)=>{const c=e=>{var c;!1===e?i(as(4,{from:n,to:t})):e instanceof Error?i(e):"string"==typeof(c=e)||c&&"object"==typeof c?i(as(2,{from:t,to:e})):(s&&r.enterCallbacks[o]===s&&"function"==typeof e&&s.push(e),l())},a=e.call(r&&r.instances[o],t,n,c);let u=Promise.resolve(a);e.length<3&&(u=u.then(c)),u.catch((e=>i(e)))}))}function Ks(e,t,n,r){const o=[];for(const l of e)for(const e in l.components){let i=l.components[e];if("beforeRouteEnter"===t||l.instances[e])if("object"==typeof(s=i)||"displayName"in s||"props"in s||"__vccOpts"in s){const s=(i.__vccOpts||i)[t];s&&o.push(Ws(s,n,r,l,e))}else{let s=i();s=s.catch(console.error),o.push((()=>s.then((o=>{if(!o)return Promise.reject(new Error(`Couldn't resolve component "${e}" at "${l.path}"`));const s=(i=o).__esModule||ko&&"Module"===i[Symbol.toStringTag]?o.default:o;var i;l.components[e]=s;const c=(s.__vccOpts||s)[t];return c&&Ws(c,n,r,l,e)()}))))}}var s;return o}function Gs(e){const t=dr(Ro),n=dr(Ao),r=Tr((()=>t.resolve(st(e.to)))),o=Tr((()=>{let{matched:e}=r.value,{length:t}=e;const o=e[t-1];let s=n.matched;if(!o||!s.length)return-1;let l=s.findIndex(Vo.bind(null,o));if(l>-1)return l;let i=Xs(e[t-2]);return t>1&&Xs(o)===i&&s[s.length-1].path!==i?s.findIndex(Vo.bind(null,e[t-2])):l})),s=Tr((()=>o.value>-1&&function(e,t){for(let n in t){let r=t[n],o=e[n];if("string"==typeof r){if(r!==o)return!1}else if(!Array.isArray(o)||o.length!==r.length||r.some(((e,t)=>e!==o[t])))return!1}return!0}(n.params,r.value.params))),l=Tr((()=>o.value>-1&&o.value===n.matched.length-1&&No(n.params,r.value.params)));return{route:r,href:Tr((()=>r.value.href)),isActive:s,isExactActive:l,navigate:function(n={}){return function(e){if(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)return;if(e.defaultPrevented)return;if(void 0!==e.button&&0!==e.button)return;if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}e.preventDefault&&e.preventDefault();return!0}(n)?t[st(e.replace)?"replace":"push"](st(e.to)):Promise.resolve()}}}const Hs=In({name:"RouterLink",props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"}},setup(e,{slots:t}){const n=He(Gs(e)),{options:r}=dr(Ro),o=Tr((()=>({[Js(e.activeClass,r.linkActiveClass,"router-link-active")]:n.isActive,[Js(e.exactActiveClass,r.linkExactActiveClass,"router-link-exact-active")]:n.isExactActive})));return()=>{const r=t.default&&t.default(n);return e.custom?r:Ur("a",{"aria-current":n.isExactActive?e.ariaCurrentValue:null,href:n.href,onClick:n.navigate,class:o.value},r)}}});function Xs(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const Js=(e,t,n)=>null!=e?e:null!=t?t:n;function Qs(e,t){if(!e)return null;const n=e(t);return 1===n.length?n[0]:n}const Ys=In({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},setup(e,{attrs:t,slots:n}){const r=dr(Po),o=Tr((()=>e.route||r.value)),s=dr(Co,0),l=Tr((()=>o.value.matched[s]));pr(Co,s+1),pr(Oo,l),pr(Po,o);const i=ot(c);var c;return yn((()=>[i.value,l.value,e.name]),(([e,t,n],[r,o,s])=>{t&&(t.instances[n]=e,o&&o!==t&&e&&e===r&&(t.leaveGuards.size||(t.leaveGuards=o.leaveGuards),t.updateGuards.size||(t.updateGuards=o.updateGuards))),!e||!t||o&&Vo(t,o)&&r||(t.enterCallbacks[n]||[]).forEach((t=>t(e)))}),{flush:"post"}),()=>{const r=o.value,s=l.value,c=s&&s.components[e.name],a=e.name;if(!c)return Qs(n.default,{Component:c,route:r});const u=s.props[e.name],f=u?!0===u?r.params:"function"==typeof u?u(r):u:null,p=Ur(c,jo({},f,t,{onVnodeUnmounted:e=>{e.component.isUnmounted&&(s.instances[a]=null)},ref:i}));return Qs(n.default,{Component:p,route:r})||p}}});function Zs(e){const t=ys(e.routes,e);let n=e.parseQuery||Bs,r=e.stringifyQuery||Ds,o=e.history;const s=zs(),l=zs(),i=zs(),c=ot(ss,!0);let a=ss;Fo&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const u=$o.bind(null,(e=>""+e)),f=$o.bind(null,Ns),p=$o.bind(null,Ls);function d(e,s){if(s=jo({},s||c.value),"string"==typeof e){let r=To(n,e,s.path),l=t.resolve({path:r.path},s),i=o.createHref(r.fullPath);return jo(r,l,{params:p(l.params),hash:Ls(r.hash),redirectedFrom:void 0,href:i})}let l;"path"in e?l=jo({},e,{path:To(n,e.path,s.path).path}):(l=jo({},e,{params:f(e.params)}),s.params=f(s.params));let i=t.resolve(l,s);const a=e.hash||"";i.params=u(p(i.params));const d=function(e,t){let n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}(r,jo({},e,{hash:(h=a,Us(h).replace($s,"{").replace(Is,"}").replace(Fs,"^")),path:i.path}));var h;let m=o.createHref(d);return jo({fullPath:d,hash:a,query:r===Ds?qs(e.query):e.query},i,{redirectedFrom:void 0,href:m})}function h(e){return"string"==typeof e?To(n,e,c.value.path):jo({},e)}function m(e,t){if(a!==e)return as(8,{from:t,to:e})}function g(e){return y(e)}function v(e){const t=e.matched[e.matched.length-1];if(t&&t.redirect){const{redirect:n}=t;let r="function"==typeof n?n(e):n;return"string"==typeof r&&(r=r.indexOf("?")>-1||r.indexOf("#")>-1?r=h(r):{path:r}),jo({query:e.query,hash:e.hash,params:e.params},r)}}function y(e,t){const n=a=d(e),o=c.value,s=e.state,l=e.force,i=!0===e.replace,u=v(n);if(u)return y(jo(h(u),{state:s,force:l,replace:i}),t||n);const f=n;let p;return f.redirectedFrom=t,!l&&function(e,t,n){let r=t.matched.length-1,o=n.matched.length-1;return r>-1&&r===o&&Vo(t.matched[r],n.matched[o])&&No(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}(r,o,n)&&(p=as(16,{to:f,from:o}),P(o,o,!0,!1)),(p?Promise.resolve(p):_(f,o)).catch((e=>us(e)?e:R(e))).then((e=>{if(e){if(us(e,2))return y(jo(h(e.to),{state:s,force:l,replace:i}),t||f)}else e=x(f,o,!0,i,s);return w(f,o,e),e}))}function b(e,t){const n=m(e,t);return n?Promise.reject(n):Promise.resolve()}function _(e,t){let n;const[r,o,i]=function(e,t){const n=[],r=[],o=[],s=Math.max(t.matched.length,e.matched.length);for(let l=0;lVo(e,s)))?r.push(s):n.push(s));const i=e.matched[l];i&&(t.matched.find((e=>Vo(e,i)))||o.push(i))}return[n,r,o]}(e,t);n=Ks(r.reverse(),"beforeRouteLeave",e,t);for(const s of r)s.leaveGuards.forEach((r=>{n.push(Ws(r,e,t))}));const c=b.bind(null,e,t);return n.push(c),el(n).then((()=>{n=[];for(const r of s.list())n.push(Ws(r,e,t));return n.push(c),el(n)})).then((()=>{n=Ks(o,"beforeRouteUpdate",e,t);for(const r of o)r.updateGuards.forEach((r=>{n.push(Ws(r,e,t))}));return n.push(c),el(n)})).then((()=>{n=[];for(const r of e.matched)if(r.beforeEnter&&t.matched.indexOf(r)<0)if(Array.isArray(r.beforeEnter))for(const o of r.beforeEnter)n.push(Ws(o,e,t));else n.push(Ws(r.beforeEnter,e,t));return n.push(c),el(n)})).then((()=>(e.matched.forEach((e=>e.enterCallbacks={})),n=Ks(i,"beforeRouteEnter",e,t),n.push(c),el(n)))).then((()=>{n=[];for(const r of l.list())n.push(Ws(r,e,t));return n.push(c),el(n)})).catch((e=>us(e,8)?e:Promise.reject(e)))}function w(e,t,n){for(const r of i.list())r(e,t,n)}function x(e,t,n,r,s){const l=m(e,t);if(l)return l;const i=t===ss,a=Fo?history.state:{};n&&(r||i?o.replace(e.fullPath,jo({scroll:i&&a&&a.scroll},s)):o.push(e.fullPath,s)),c.value=e,P(e,t,n,i),A()}let E;function k(){E=o.listen(((e,t,n)=>{let r=d(e);const s=v(r);if(s)return void y(jo(s,{replace:!0}),r).catch(Mo);a=r;const l=c.value;var i,u;Fo&&(i=Qo(l.fullPath,n.delta),u=Xo(),Yo.set(i,u)),_(r,l).catch((e=>us(e,12)?e:us(e,2)?(y(e.to,r).catch(Mo),Promise.reject()):(n.delta&&o.go(-n.delta,!1),R(e)))).then((e=>{(e=e||x(r,l,!1))&&n.delta&&o.go(-n.delta,!1),w(r,l,e)})).catch(Mo)}))}let S,O=zs(),C=zs();function R(e){return A(e),C.list().forEach((t=>t(e))),Promise.reject(e)}function A(e){S||(S=!0,k(),O.list().forEach((([t,n])=>e?n(e):t())),O.reset())}function P(t,n,r,o){const{scrollBehavior:s}=e;if(!Fo||!s)return Promise.resolve();let l=!r&&function(e){const t=Yo.get(e);return Yo.delete(e),t}(Qo(t.fullPath,0))||(o||!r)&&history.state&&history.state.scroll||null;return Ot().then((()=>s(t,n,l))).then((e=>e&&Jo(e))).catch(R)}const F=e=>o.go(e);let j;const $=new Set;return{currentRoute:c,addRoute:function(e,n){let r,o;return os(e)?(r=t.getRecordMatcher(e),o=n):o=e,t.addRoute(o,r)},removeRoute:function(e){let n=t.getRecordMatcher(e);n&&t.removeRoute(n)},hasRoute:function(e){return!!t.getRecordMatcher(e)},getRoutes:function(){return t.getRoutes().map((e=>e.record))},resolve:d,options:e,push:g,replace:function(e){return g(jo(h(e),{replace:!0}))},go:F,back:()=>F(-1),forward:()=>F(1),beforeEach:s.add,beforeResolve:l.add,afterEach:i.add,onError:C.add,isReady:function(){return S&&c.value!==ss?Promise.resolve():new Promise(((e,t)=>{O.add([e,t])}))},install(e){e.component("RouterLink",Hs),e.component("RouterView",Ys),e.config.globalProperties.$router=this,Object.defineProperty(e.config.globalProperties,"$route",{enumerable:!0,get:()=>st(c)}),Fo&&!j&&c.value===ss&&(j=!0,g(o.location).catch((e=>{})));const t={};for(let r in ss)t[r]=Tr((()=>c.value[r]));e.provide(Ro,this),e.provide(Ao,He(t)),e.provide(Po,c);let n=e.unmount;$.add(e),e.unmount=function(){$.delete(e),$.size<1&&(E(),c.value=ss,j=!1,S=!1),n()}}}}function el(e){return e.reduce(((e,t)=>e.then((()=>t()))),Promise.resolve())}export{Wn as F,sr as a,cr as b,Zn as c,In as d,ir as e,Vr as f,go as g,Pn as h,yo as i,zt as j,ao as k,uo as l,Nt as m,bo as n,Qn as o,Zs as p,rs as q,Dn as r,Eo as s,u as t,co as v,Wt as w}; diff --git a/build/public/index.html b/build/public/index.html index 39e5a46..773251f 100644 --- a/build/public/index.html +++ b/build/public/index.html @@ -4,9 +4,9 @@ 🧩 jigsaw.hyottoko.club - - - + + +
diff --git a/build/server/main.js b/build/server/main.js index 618ce84..9ef521f 100644 --- a/build/server/main.js +++ b/build/server/main.js @@ -1,5 +1,6 @@ import WebSocket from 'ws'; import express from 'express'; +import compression from 'compression'; import multer from 'multer'; import fs from 'fs'; import { fileURLToPath } from 'url'; @@ -7,7 +8,6 @@ import { dirname } from 'path'; import sizeOf from 'image-size'; import exif from 'exif'; import sharp from 'sharp'; -import bodyParser from 'body-parser'; import v8 from 'v8'; import bsqlite from 'better-sqlite3'; @@ -19,7 +19,7 @@ class Rng { random(min, max) { this.rand_high = ((this.rand_high << 16) + (this.rand_high >> 16) + this.rand_low) & 0xffffffff; this.rand_low = (this.rand_low + this.rand_high) & 0xffffffff; - var n = (this.rand_high >>> 0) / 0xffffffff; + const n = (this.rand_high >>> 0) / 0xffffffff; return (min + n * (max - min + 1)) | 0; } // get one random item from the given array @@ -79,7 +79,9 @@ const logger = (...pre) => { }; }; // get a unique id -const uniqId = () => Date.now().toString(36) + Math.random().toString(36).substring(2); +const uniqId = () => { + return Date.now().toString(36) + Math.random().toString(36).substring(2); +}; function encodeShape(data) { /* encoded in 1 byte: 00000000 @@ -101,10 +103,10 @@ function decodeShape(data) { left: (data >> 6 & 0b11) - 1, }; } -function encodeTile(data) { +function encodePiece(data) { return [data.idx, data.pos.x, data.pos.y, data.z, data.owner, data.group]; } -function decodeTile(data) { +function decodePiece(data) { return { idx: data[0], pos: { @@ -143,23 +145,20 @@ function decodePlayer(data) { }; } function encodeGame(data) { - if (Array.isArray(data)) { - return data; - } return [ data.id, - data.rng.type, + data.rng.type || '', Rng.serialize(data.rng.obj), data.puzzle, data.players, data.evtInfos, data.scoreMode, + data.shapeMode, + data.snapMode, + data.creatorUserId, ]; } function decodeGame(data) { - if (!Array.isArray(data)) { - return data; - } return { id: data[0], rng: { @@ -170,19 +169,22 @@ function decodeGame(data) { players: data[4], evtInfos: data[5], scoreMode: data[6], + shapeMode: data[7], + snapMode: data[8], + creatorUserId: data[9], }; } -function coordByTileIdx(info, tileIdx) { +function coordByPieceIdx(info, pieceIdx) { const wTiles = info.width / info.tileSize; return { - x: tileIdx % wTiles, - y: Math.floor(tileIdx / wTiles), + x: pieceIdx % wTiles, + y: Math.floor(pieceIdx / wTiles), }; } const hash = (str) => { let hash = 0; for (let i = 0; i < str.length; i++) { - let chr = str.charCodeAt(i); + const chr = str.charCodeAt(i); hash = ((hash << 5) - hash) + chr; hash |= 0; // Convert to 32bit integer } @@ -190,7 +192,7 @@ const hash = (str) => { }; function asQueryArgs(data) { const q = []; - for (let k in data) { + for (const k in data) { const pair = [k, data[k]].map(encodeURIComponent); q.push(pair.join('=')); } @@ -205,13 +207,13 @@ var Util = { uniqId, encodeShape, decodeShape, - encodeTile, - decodeTile, + encodePiece, + decodePiece, encodePlayer, decodePlayer, encodeGame, decodeGame, - coordByTileIdx, + coordByPieceIdx, asQueryArgs, }; @@ -318,10 +320,8 @@ EV_SERVER_INIT: event sent to one client after that client */ const EV_SERVER_EVENT = 1; const EV_SERVER_INIT = 4; -const EV_SERVER_INIT_REPLAY = 5; const EV_CLIENT_EVENT = 2; const EV_CLIENT_INIT = 3; -const EV_CLIENT_INIT_REPLAY = 6; const LOG_HEADER = 1; const LOG_ADD_PLAYER = 2; const LOG_UPDATE_PLAYER = 4; @@ -336,16 +336,22 @@ const INPUT_EV_PLAYER_COLOR = 7; const INPUT_EV_PLAYER_NAME = 8; const INPUT_EV_MOVE = 9; const INPUT_EV_TOGGLE_PREVIEW = 10; +const INPUT_EV_TOGGLE_SOUNDS = 11; +const INPUT_EV_REPLAY_TOGGLE_PAUSE = 12; +const INPUT_EV_REPLAY_SPEED_UP = 13; +const INPUT_EV_REPLAY_SPEED_DOWN = 14; +const INPUT_EV_TOGGLE_PLAYER_NAMES = 15; +const INPUT_EV_CENTER_FIT_PUZZLE = 16; +const INPUT_EV_TOGGLE_FIXED_PIECES = 17; +const INPUT_EV_TOGGLE_LOOSE_PIECES = 18; const CHANGE_DATA = 1; const CHANGE_TILE = 2; const CHANGE_PLAYER = 3; var Protocol = { EV_SERVER_EVENT, EV_SERVER_INIT, - EV_SERVER_INIT_REPLAY, EV_CLIENT_EVENT, EV_CLIENT_INIT, - EV_CLIENT_INIT_REPLAY, LOG_HEADER, LOG_ADD_PLAYER, LOG_UPDATE_PLAYER, @@ -360,6 +366,14 @@ var Protocol = { INPUT_EV_PLAYER_COLOR, INPUT_EV_PLAYER_NAME, INPUT_EV_TOGGLE_PREVIEW, + INPUT_EV_TOGGLE_SOUNDS, + INPUT_EV_REPLAY_TOGGLE_PAUSE, + INPUT_EV_REPLAY_SPEED_UP, + INPUT_EV_REPLAY_SPEED_DOWN, + INPUT_EV_TOGGLE_PLAYER_NAMES, + INPUT_EV_CENTER_FIT_PUZZLE, + INPUT_EV_TOGGLE_FIXED_PIECES, + INPUT_EV_TOGGLE_LOOSE_PIECES, CHANGE_DATA, CHANGE_TILE, CHANGE_PLAYER, @@ -474,6 +488,36 @@ var ScoreMode; ScoreMode[ScoreMode["FINAL"] = 0] = "FINAL"; ScoreMode[ScoreMode["ANY"] = 1] = "ANY"; })(ScoreMode || (ScoreMode = {})); +var ShapeMode; +(function (ShapeMode) { + ShapeMode[ShapeMode["NORMAL"] = 0] = "NORMAL"; + ShapeMode[ShapeMode["ANY"] = 1] = "ANY"; + ShapeMode[ShapeMode["FLAT"] = 2] = "FLAT"; +})(ShapeMode || (ShapeMode = {})); +var SnapMode; +(function (SnapMode) { + SnapMode[SnapMode["NORMAL"] = 0] = "NORMAL"; + SnapMode[SnapMode["REAL"] = 1] = "REAL"; +})(SnapMode || (SnapMode = {})); +const DefaultScoreMode = (v) => { + if (v === ScoreMode.FINAL || v === ScoreMode.ANY) { + return v; + } + return ScoreMode.FINAL; +}; +const DefaultShapeMode = (v) => { + if (v === ShapeMode.NORMAL || v === ShapeMode.ANY || v === ShapeMode.FLAT) { + return v; + } + return ShapeMode.NORMAL; +}; +const DefaultSnapMode = (v) => { + if (v === SnapMode.NORMAL || v === SnapMode.REAL) { + return v; + } + return SnapMode.NORMAL; +}; + const IDLE_TIMEOUT_SEC = 30; // Map const GAMES = {}; @@ -498,7 +542,7 @@ function setGame(gameId, game) { } function getPlayerIndexById(gameId, playerId) { let i = 0; - for (let player of GAMES[gameId].players) { + for (const player of GAMES[gameId].players) { if (Util.decodePlayer(player).id === playerId) { return i; } @@ -514,6 +558,9 @@ function getPlayerIdByIndex(gameId, playerIndex) { } function getPlayer(gameId, playerId) { const idx = getPlayerIndexById(gameId, playerId); + if (idx === -1) { + return null; + } return Util.decodePlayer(GAMES[gameId].players[idx]); } function setPlayer(gameId, playerId, player) { @@ -525,8 +572,8 @@ function setPlayer(gameId, playerId, player) { GAMES[gameId].players[idx] = Util.encodePlayer(player); } } -function setTile(gameId, tileIdx, tile) { - GAMES[gameId].puzzle.tiles[tileIdx] = Util.encodeTile(tile); +function setPiece(gameId, pieceIdx, piece) { + GAMES[gameId].puzzle.tiles[pieceIdx] = Util.encodePiece(piece); } function setPuzzleData(gameId, data) { GAMES[gameId].puzzle.data = data; @@ -565,12 +612,16 @@ function setEvtInfo(gameId, playerId, evtInfo) { } function getAllGames() { return Object.values(GAMES).sort((a, b) => { + const finished = isFinished(a.id); // when both have same finished state, sort by started - if (isFinished(a.id) === isFinished(b.id)) { + if (finished === isFinished(b.id)) { + if (finished) { + return b.puzzle.data.finished - a.puzzle.data.finished; + } return b.puzzle.data.started - a.puzzle.data.started; } // otherwise, sort: unfinished, finished - return isFinished(a.id) ? 1 : -1; + return finished ? 1 : -1; }); } function getAllPlayers(gameId) { @@ -579,66 +630,82 @@ function getAllPlayers(gameId) { : []; } function get$1(gameId) { - return GAMES[gameId]; + return GAMES[gameId] || null; } -function getTileCount(gameId) { +function getPieceCount(gameId) { return GAMES[gameId].puzzle.tiles.length; } function getImageUrl(gameId) { - return GAMES[gameId].puzzle.info.imageUrl; -} -function setImageUrl(gameId, imageUrl) { - GAMES[gameId].puzzle.info.imageUrl = imageUrl; + const imageUrl = GAMES[gameId].puzzle.info.image?.url + || GAMES[gameId].puzzle.info.imageUrl; + if (!imageUrl) { + throw new Error('[2021-07-11] no image url set'); + } + return imageUrl; } function getScoreMode(gameId) { - return GAMES[gameId].scoreMode || ScoreMode.FINAL; + return GAMES[gameId].scoreMode; +} +function getSnapMode(gameId) { + return GAMES[gameId].snapMode; } function isFinished(gameId) { - return getFinishedTileCount(gameId) === getTileCount(gameId); + return getFinishedPiecesCount(gameId) === getPieceCount(gameId); } -function getFinishedTileCount(gameId) { +function getFinishedPiecesCount(gameId) { let count = 0; - for (let t of GAMES[gameId].puzzle.tiles) { - if (Util.decodeTile(t).owner === -1) { + for (const t of GAMES[gameId].puzzle.tiles) { + if (Util.decodePiece(t).owner === -1) { count++; } } return count; } -function getTilesSortedByZIndex(gameId) { - const tiles = GAMES[gameId].puzzle.tiles.map(Util.decodeTile); - return tiles.sort((t1, t2) => t1.z - t2.z); +function getPiecesSortedByZIndex(gameId) { + const pieces = GAMES[gameId].puzzle.tiles.map(Util.decodePiece); + return pieces.sort((t1, t2) => t1.z - t2.z); } function changePlayer(gameId, playerId, change) { const player = getPlayer(gameId, playerId); - for (let k of Object.keys(change)) { + if (player === null) { + return; + } + for (const k of Object.keys(change)) { // @ts-ignore player[k] = change[k]; } setPlayer(gameId, playerId, player); } function changeData(gameId, change) { - for (let k of Object.keys(change)) { + for (const k of Object.keys(change)) { // @ts-ignore GAMES[gameId].puzzle.data[k] = change[k]; } } -function changeTile(gameId, tileIdx, change) { - for (let k of Object.keys(change)) { - const tile = Util.decodeTile(GAMES[gameId].puzzle.tiles[tileIdx]); +function changePiece(gameId, pieceIdx, change) { + for (const k of Object.keys(change)) { + const piece = Util.decodePiece(GAMES[gameId].puzzle.tiles[pieceIdx]); // @ts-ignore - tile[k] = change[k]; - GAMES[gameId].puzzle.tiles[tileIdx] = Util.encodeTile(tile); + piece[k] = change[k]; + GAMES[gameId].puzzle.tiles[pieceIdx] = Util.encodePiece(piece); } } -const getTile = (gameId, tileIdx) => { - return Util.decodeTile(GAMES[gameId].puzzle.tiles[tileIdx]); +const getPiece = (gameId, pieceIdx) => { + return Util.decodePiece(GAMES[gameId].puzzle.tiles[pieceIdx]); }; -const getTileGroup = (gameId, tileIdx) => { - const tile = getTile(gameId, tileIdx); +const getPieceGroup = (gameId, tileIdx) => { + const tile = getPiece(gameId, tileIdx); return tile.group; }; -const getFinalTilePos = (gameId, tileIdx) => { +const isCornerPiece = (gameId, tileIdx) => { + const info = GAMES[gameId].puzzle.info; + return (tileIdx === 0 // top left corner + || tileIdx === (info.tilesX - 1) // top right corner + || tileIdx === (info.tiles - info.tilesX) // bottom left corner + || tileIdx === (info.tiles - 1) // bottom right corner + ); +}; +const getFinalPiecePos = (gameId, tileIdx) => { const info = GAMES[gameId].puzzle.info; const boardPos = { x: (info.table.width - info.width) / 2, @@ -647,8 +714,8 @@ const getFinalTilePos = (gameId, tileIdx) => { const srcPos = srcPosByTileIdx(gameId, tileIdx); return Geometry.pointAdd(boardPos, srcPos); }; -const getTilePos = (gameId, tileIdx) => { - const tile = getTile(gameId, tileIdx); +const getPiecePos = (gameId, tileIdx) => { + const tile = getPiece(gameId, tileIdx); return tile.pos; }; // todo: instead, just make the table bigger and use that :) @@ -664,9 +731,9 @@ const getBounds = (gameId) => { h: th + 2 * overY, }; }; -const getTileBounds = (gameId, tileIdx) => { - const s = getTileSize(gameId); - const tile = getTile(gameId, tileIdx); +const getPieceBounds = (gameId, tileIdx) => { + const s = getPieceSize(gameId); + const tile = getPiece(gameId, tileIdx); return { x: tile.pos.x, y: tile.pos.y, @@ -674,30 +741,29 @@ const getTileBounds = (gameId, tileIdx) => { h: s, }; }; -const getTileZIndex = (gameId, tileIdx) => { - const tile = getTile(gameId, tileIdx); - return tile.z; +const getPieceZIndex = (gameId, pieceIdx) => { + return getPiece(gameId, pieceIdx).z; }; -const getFirstOwnedTileIdx = (gameId, playerId) => { - for (let t of GAMES[gameId].puzzle.tiles) { - const tile = Util.decodeTile(t); +const getFirstOwnedPieceIdx = (gameId, playerId) => { + for (const t of GAMES[gameId].puzzle.tiles) { + const tile = Util.decodePiece(t); if (tile.owner === playerId) { return tile.idx; } } return -1; }; -const getFirstOwnedTile = (gameId, playerId) => { - const idx = getFirstOwnedTileIdx(gameId, playerId); +const getFirstOwnedPiece = (gameId, playerId) => { + const idx = getFirstOwnedPieceIdx(gameId, playerId); return idx < 0 ? null : GAMES[gameId].puzzle.tiles[idx]; }; -const getTileDrawOffset = (gameId) => { +const getPieceDrawOffset = (gameId) => { return GAMES[gameId].puzzle.info.tileDrawOffset; }; -const getTileDrawSize = (gameId) => { +const getPieceDrawSize = (gameId) => { return GAMES[gameId].puzzle.info.tileDrawSize; }; -const getTileSize = (gameId) => { +const getPieceSize = (gameId) => { return GAMES[gameId].puzzle.info.tileSize; }; const getStartTs = (gameId) => { @@ -712,26 +778,26 @@ const getMaxGroup = (gameId) => { const getMaxZIndex = (gameId) => { return GAMES[gameId].puzzle.data.maxZ; }; -const getMaxZIndexByTileIdxs = (gameId, tileIdxs) => { +const getMaxZIndexByPieceIdxs = (gameId, pieceIdxs) => { let maxZ = 0; - for (let tileIdx of tileIdxs) { - let tileZIndex = getTileZIndex(gameId, tileIdx); - if (tileZIndex > maxZ) { - maxZ = tileZIndex; + for (const pieceIdx of pieceIdxs) { + const curZ = getPieceZIndex(gameId, pieceIdx); + if (curZ > maxZ) { + maxZ = curZ; } } return maxZ; }; function srcPosByTileIdx(gameId, tileIdx) { const info = GAMES[gameId].puzzle.info; - const c = Util.coordByTileIdx(info, tileIdx); + const c = Util.coordByPieceIdx(info, tileIdx); const cx = c.x * info.tileSize; const cy = c.y * info.tileSize; return { x: cx, y: cy }; } function getSurroundingTilesByIdx(gameId, tileIdx) { const info = GAMES[gameId].puzzle.info; - const c = Util.coordByTileIdx(info, tileIdx); + const c = Util.coordByPieceIdx(info, tileIdx); return [ // top (c.y > 0) ? (tileIdx - info.tilesX) : -1, @@ -743,93 +809,99 @@ function getSurroundingTilesByIdx(gameId, tileIdx) { (c.x > 0) ? (tileIdx - 1) : -1, ]; } -const setTilesZIndex = (gameId, tileIdxs, zIndex) => { - for (let tilesIdx of tileIdxs) { - changeTile(gameId, tilesIdx, { z: zIndex }); +const setPiecesZIndex = (gameId, tileIdxs, zIndex) => { + for (const tilesIdx of tileIdxs) { + changePiece(gameId, tilesIdx, { z: zIndex }); } }; const moveTileDiff = (gameId, tileIdx, diff) => { - const oldPos = getTilePos(gameId, tileIdx); + const oldPos = getPiecePos(gameId, tileIdx); const pos = Geometry.pointAdd(oldPos, diff); - changeTile(gameId, tileIdx, { pos }); + changePiece(gameId, tileIdx, { pos }); }; -const moveTilesDiff = (gameId, tileIdxs, diff) => { - const tileDrawSize = getTileDrawSize(gameId); +const movePiecesDiff = (gameId, pieceIdxs, diff) => { + const drawSize = getPieceDrawSize(gameId); const bounds = getBounds(gameId); const cappedDiff = diff; - for (let tileIdx of tileIdxs) { - const t = getTile(gameId, tileIdx); + for (const pieceIdx of pieceIdxs) { + const t = getPiece(gameId, pieceIdx); if (t.pos.x + diff.x < bounds.x) { cappedDiff.x = Math.max(bounds.x - t.pos.x, cappedDiff.x); } - else if (t.pos.x + tileDrawSize + diff.x > bounds.x + bounds.w) { - cappedDiff.x = Math.min(bounds.x + bounds.w - t.pos.x + tileDrawSize, cappedDiff.x); + else if (t.pos.x + drawSize + diff.x > bounds.x + bounds.w) { + cappedDiff.x = Math.min(bounds.x + bounds.w - t.pos.x + drawSize, cappedDiff.x); } if (t.pos.y + diff.y < bounds.y) { cappedDiff.y = Math.max(bounds.y - t.pos.y, cappedDiff.y); } - else if (t.pos.y + tileDrawSize + diff.y > bounds.y + bounds.h) { - cappedDiff.y = Math.min(bounds.y + bounds.h - t.pos.y + tileDrawSize, cappedDiff.y); + else if (t.pos.y + drawSize + diff.y > bounds.y + bounds.h) { + cappedDiff.y = Math.min(bounds.y + bounds.h - t.pos.y + drawSize, cappedDiff.y); } } - for (let tileIdx of tileIdxs) { - moveTileDiff(gameId, tileIdx, cappedDiff); + for (const pieceIdx of pieceIdxs) { + moveTileDiff(gameId, pieceIdx, cappedDiff); } }; -const finishTiles = (gameId, tileIdxs) => { - for (let tileIdx of tileIdxs) { - changeTile(gameId, tileIdx, { owner: -1, z: 1 }); +const isFinishedPiece = (gameId, pieceIdx) => { + return getPieceOwner(gameId, pieceIdx) === -1; +}; +const getPieceOwner = (gameId, pieceIdx) => { + return getPiece(gameId, pieceIdx).owner; +}; +const finishPieces = (gameId, pieceIdxs) => { + for (const pieceIdx of pieceIdxs) { + changePiece(gameId, pieceIdx, { owner: -1, z: 1 }); } }; -const setTilesOwner = (gameId, tileIdxs, owner) => { - for (let tileIdx of tileIdxs) { - changeTile(gameId, tileIdx, { owner }); +const setTilesOwner = (gameId, pieceIdxs, owner) => { + for (const pieceIdx of pieceIdxs) { + changePiece(gameId, pieceIdx, { owner }); } }; // get all grouped tiles for a tile -function getGroupedTileIdxs(gameId, tileIdx) { - const tiles = GAMES[gameId].puzzle.tiles; - const tile = Util.decodeTile(tiles[tileIdx]); +function getGroupedPieceIdxs(gameId, pieceIdx) { + const pieces = GAMES[gameId].puzzle.tiles; + const piece = Util.decodePiece(pieces[pieceIdx]); const grouped = []; - if (tile.group) { - for (let other of tiles) { - const otherTile = Util.decodeTile(other); - if (otherTile.group === tile.group) { - grouped.push(otherTile.idx); + if (piece.group) { + for (const other of pieces) { + const otherPiece = Util.decodePiece(other); + if (otherPiece.group === piece.group) { + grouped.push(otherPiece.idx); } } } else { - grouped.push(tile.idx); + grouped.push(piece.idx); } return grouped; } // Returns the index of the puzzle tile with the highest z index // that is not finished yet and that matches the position -const freeTileIdxByPos = (gameId, pos) => { - let info = GAMES[gameId].puzzle.info; - let tiles = GAMES[gameId].puzzle.tiles; +const freePieceIdxByPos = (gameId, pos) => { + const info = GAMES[gameId].puzzle.info; + const pieces = GAMES[gameId].puzzle.tiles; let maxZ = -1; - let tileIdx = -1; - for (let idx = 0; idx < tiles.length; idx++) { - const tile = Util.decodeTile(tiles[idx]); - if (tile.owner !== 0) { + let pieceIdx = -1; + for (let idx = 0; idx < pieces.length; idx++) { + const piece = Util.decodePiece(pieces[idx]); + if (piece.owner !== 0) { continue; } const collisionRect = { - x: tile.pos.x, - y: tile.pos.y, + x: piece.pos.x, + y: piece.pos.y, w: info.tileSize, h: info.tileSize, }; if (Geometry.pointInBounds(pos, collisionRect)) { - if (maxZ === -1 || tile.z > maxZ) { - maxZ = tile.z; - tileIdx = idx; + if (maxZ === -1 || piece.z > maxZ) { + maxZ = piece.z; + pieceIdx = idx; } } } - return tileIdx; + return pieceIdx; }; const getPlayerBgColor = (gameId, playerId) => { const p = getPlayer(gameId, playerId); @@ -849,8 +921,8 @@ const getPlayerPoints = (gameId, playerId) => { }; // determine if two tiles are grouped together const areGrouped = (gameId, tileIdx1, tileIdx2) => { - const g1 = getTileGroup(gameId, tileIdx1); - const g2 = getTileGroup(gameId, tileIdx2); + const g1 = getPieceGroup(gameId, tileIdx1); + const g2 = getPieceGroup(gameId, tileIdx2); return !!(g1 && g1 === g2); }; const getTableWidth = (gameId) => { @@ -871,35 +943,39 @@ const getPuzzleWidth = (gameId) => { const getPuzzleHeight = (gameId) => { return GAMES[gameId].puzzle.info.height; }; -function handleInput$1(gameId, playerId, input, ts) { +function handleInput$1(gameId, playerId, input, ts, onSnap) { const puzzle = GAMES[gameId].puzzle; const evtInfo = getEvtInfo(gameId, playerId); const changes = []; const _dataChange = () => { changes.push([Protocol.CHANGE_DATA, puzzle.data]); }; - const _tileChange = (tileIdx) => { + const _pieceChange = (pieceIdx) => { changes.push([ Protocol.CHANGE_TILE, - Util.encodeTile(getTile(gameId, tileIdx)), + Util.encodePiece(getPiece(gameId, pieceIdx)), ]); }; - const _tileChanges = (tileIdxs) => { - for (const tileIdx of tileIdxs) { - _tileChange(tileIdx); + const _pieceChanges = (pieceIdxs) => { + for (const pieceIdx of pieceIdxs) { + _pieceChange(pieceIdx); } }; const _playerChange = () => { + const player = getPlayer(gameId, playerId); + if (!player) { + return; + } changes.push([ Protocol.CHANGE_PLAYER, - Util.encodePlayer(getPlayer(gameId, playerId)), + Util.encodePlayer(player), ]); }; // put both tiles (and their grouped tiles) in the same group - const groupTiles = (gameId, tileIdx1, tileIdx2) => { - const tiles = GAMES[gameId].puzzle.tiles; - const group1 = getTileGroup(gameId, tileIdx1); - const group2 = getTileGroup(gameId, tileIdx2); + const groupTiles = (gameId, pieceIdx1, pieceIdx2) => { + const pieces = GAMES[gameId].puzzle.tiles; + const group1 = getPieceGroup(gameId, pieceIdx1); + const group2 = getPieceGroup(gameId, pieceIdx2); let group; const searchGroups = []; if (group1) { @@ -920,17 +996,17 @@ function handleInput$1(gameId, playerId, input, ts) { _dataChange(); group = getMaxGroup(gameId); } - changeTile(gameId, tileIdx1, { group }); - _tileChange(tileIdx1); - changeTile(gameId, tileIdx2, { group }); - _tileChange(tileIdx2); + changePiece(gameId, pieceIdx1, { group }); + _pieceChange(pieceIdx1); + changePiece(gameId, pieceIdx2, { group }); + _pieceChange(pieceIdx2); // TODO: strange if (searchGroups.length > 0) { - for (const t of tiles) { - const tile = Util.decodeTile(t); - if (searchGroups.includes(tile.group)) { - changeTile(gameId, tile.idx, { group }); - _tileChange(tile.idx); + for (const p of pieces) { + const piece = Util.decodePiece(p); + if (searchGroups.includes(piece.group)) { + changePiece(gameId, piece.idx, { group }); + _pieceChange(piece.idx); } } } @@ -951,6 +1027,17 @@ function handleInput$1(gameId, playerId, input, ts) { changePlayer(gameId, playerId, { name, ts }); _playerChange(); } + else if (type === Protocol.INPUT_EV_MOVE) { + const w = input[1]; + const h = input[2]; + const player = getPlayer(gameId, playerId); + if (player) { + const x = player.x - w; + const y = player.y - h; + changePlayer(gameId, playerId, { ts, x, y }); + _playerChange(); + } + } else if (type === Protocol.INPUT_EV_MOUSE_DOWN) { const x = input[1]; const y = input[2]; @@ -958,15 +1045,15 @@ function handleInput$1(gameId, playerId, input, ts) { changePlayer(gameId, playerId, { d: 1, ts }); _playerChange(); evtInfo._last_mouse_down = pos; - const tileIdxAtPos = freeTileIdxByPos(gameId, pos); + const tileIdxAtPos = freePieceIdxByPos(gameId, pos); if (tileIdxAtPos >= 0) { - let maxZ = getMaxZIndex(gameId) + 1; + const maxZ = getMaxZIndex(gameId) + 1; changeData(gameId, { maxZ }); _dataChange(); - const tileIdxs = getGroupedTileIdxs(gameId, tileIdxAtPos); - setTilesZIndex(gameId, tileIdxs, getMaxZIndex(gameId)); + const tileIdxs = getGroupedPieceIdxs(gameId, tileIdxAtPos); + setPiecesZIndex(gameId, tileIdxs, getMaxZIndex(gameId)); setTilesOwner(gameId, tileIdxs, playerId); - _tileChanges(tileIdxs); + _pieceChanges(tileIdxs); } evtInfo._last_mouse = pos; } @@ -980,18 +1067,18 @@ function handleInput$1(gameId, playerId, input, ts) { _playerChange(); } else { - let tileIdx = getFirstOwnedTileIdx(gameId, playerId); - if (tileIdx >= 0) { + const pieceIdx = getFirstOwnedPieceIdx(gameId, playerId); + if (pieceIdx >= 0) { // player is moving a tile (and hand) changePlayer(gameId, playerId, { x, y, ts }); _playerChange(); // check if pos is on the tile, otherwise dont move // (mouse could be out of table, but tile stays on it) - const tileIdxs = getGroupedTileIdxs(gameId, tileIdx); + const pieceIdxs = getGroupedPieceIdxs(gameId, pieceIdx); let anyOk = Geometry.pointInBounds(pos, getBounds(gameId)) && Geometry.pointInBounds(evtInfo._last_mouse_down, getBounds(gameId)); - for (let idx of tileIdxs) { - const bounds = getTileBounds(gameId, idx); + for (const idx of pieceIdxs) { + const bounds = getPieceBounds(gameId, idx); if (Geometry.pointInBounds(pos, bounds)) { anyOk = true; break; @@ -1001,8 +1088,8 @@ function handleInput$1(gameId, playerId, input, ts) { const diffX = x - evtInfo._last_mouse_down.x; const diffY = y - evtInfo._last_mouse_down.y; const diff = { x: diffX, y: diffY }; - moveTilesDiff(gameId, tileIdxs, diff); - _tileChanges(tileIdxs); + movePiecesDiff(gameId, pieceIdxs, diff); + _pieceChanges(pieceIdxs); } } else { @@ -1020,24 +1107,39 @@ function handleInput$1(gameId, playerId, input, ts) { const pos = { x, y }; const d = 0; evtInfo._last_mouse_down = null; - let tileIdx = getFirstOwnedTileIdx(gameId, playerId); - if (tileIdx >= 0) { + const pieceIdx = getFirstOwnedPieceIdx(gameId, playerId); + if (pieceIdx >= 0) { // drop the tile(s) - let tileIdxs = getGroupedTileIdxs(gameId, tileIdx); - setTilesOwner(gameId, tileIdxs, 0); - _tileChanges(tileIdxs); + const pieceIdxs = getGroupedPieceIdxs(gameId, pieceIdx); + setTilesOwner(gameId, pieceIdxs, 0); + _pieceChanges(pieceIdxs); // Check if the tile was dropped near the final location - let tilePos = getTilePos(gameId, tileIdx); - let finalPos = getFinalTilePos(gameId, tileIdx); - if (Geometry.pointDistance(finalPos, tilePos) < puzzle.info.snapDistance) { - let diff = Geometry.pointSub(finalPos, tilePos); + const tilePos = getPiecePos(gameId, pieceIdx); + const finalPos = getFinalPiecePos(gameId, pieceIdx); + let canSnapToFinal = false; + if (getSnapMode(gameId) === SnapMode.REAL) { + // only can snap to final if any of the grouped pieces are + // corner pieces + for (const pieceIdxTmp of pieceIdxs) { + if (isCornerPiece(gameId, pieceIdxTmp)) { + canSnapToFinal = true; + break; + } + } + } + else { + canSnapToFinal = true; + } + if (canSnapToFinal + && Geometry.pointDistance(finalPos, tilePos) < puzzle.info.snapDistance) { + const diff = Geometry.pointSub(finalPos, tilePos); // Snap the tile to the final destination - moveTilesDiff(gameId, tileIdxs, diff); - finishTiles(gameId, tileIdxs); - _tileChanges(tileIdxs); + movePiecesDiff(gameId, pieceIdxs, diff); + finishPieces(gameId, pieceIdxs); + _pieceChanges(pieceIdxs); let points = getPlayerPoints(gameId, playerId); if (getScoreMode(gameId) === ScoreMode.FINAL) { - points += tileIdxs.length; + points += pieceIdxs.length; } else if (getScoreMode(gameId) === ScoreMode.ANY) { points += 1; @@ -1046,43 +1148,51 @@ function handleInput$1(gameId, playerId, input, ts) { changePlayer(gameId, playerId, { d, ts, points }); _playerChange(); // check if the puzzle is finished - if (getFinishedTileCount(gameId) === getTileCount(gameId)) { + if (getFinishedPiecesCount(gameId) === getPieceCount(gameId)) { changeData(gameId, { finished: ts }); _dataChange(); } + if (onSnap) { + onSnap(playerId); + } } else { // Snap to other tiles const check = (gameId, tileIdx, otherTileIdx, off) => { - let info = GAMES[gameId].puzzle.info; + const info = GAMES[gameId].puzzle.info; if (otherTileIdx < 0) { return false; } if (areGrouped(gameId, tileIdx, otherTileIdx)) { return false; } - const tilePos = getTilePos(gameId, tileIdx); - const dstPos = Geometry.pointAdd(getTilePos(gameId, otherTileIdx), { x: off[0] * info.tileSize, y: off[1] * info.tileSize }); + const tilePos = getPiecePos(gameId, tileIdx); + const dstPos = Geometry.pointAdd(getPiecePos(gameId, otherTileIdx), { x: off[0] * info.tileSize, y: off[1] * info.tileSize }); if (Geometry.pointDistance(tilePos, dstPos) < info.snapDistance) { - let diff = Geometry.pointSub(dstPos, tilePos); - let tileIdxs = getGroupedTileIdxs(gameId, tileIdx); - moveTilesDiff(gameId, tileIdxs, diff); + const diff = Geometry.pointSub(dstPos, tilePos); + let pieceIdxs = getGroupedPieceIdxs(gameId, tileIdx); + movePiecesDiff(gameId, pieceIdxs, diff); groupTiles(gameId, tileIdx, otherTileIdx); - tileIdxs = getGroupedTileIdxs(gameId, tileIdx); - const zIndex = getMaxZIndexByTileIdxs(gameId, tileIdxs); - setTilesZIndex(gameId, tileIdxs, zIndex); - _tileChanges(tileIdxs); + pieceIdxs = getGroupedPieceIdxs(gameId, tileIdx); + if (isFinishedPiece(gameId, otherTileIdx)) { + finishPieces(gameId, pieceIdxs); + } + else { + const zIndex = getMaxZIndexByPieceIdxs(gameId, pieceIdxs); + setPiecesZIndex(gameId, pieceIdxs, zIndex); + } + _pieceChanges(pieceIdxs); return true; } return false; }; let snapped = false; - for (let tileIdxTmp of getGroupedTileIdxs(gameId, tileIdx)) { - let othersIdxs = getSurroundingTilesByIdx(gameId, tileIdxTmp); - if (check(gameId, tileIdxTmp, othersIdxs[0], [0, 1]) // top - || check(gameId, tileIdxTmp, othersIdxs[1], [-1, 0]) // right - || check(gameId, tileIdxTmp, othersIdxs[2], [0, -1]) // bottom - || check(gameId, tileIdxTmp, othersIdxs[3], [1, 0]) // left + for (const pieceIdxTmp of getGroupedPieceIdxs(gameId, pieceIdx)) { + const othersIdxs = getSurroundingTilesByIdx(gameId, pieceIdxTmp); + if (check(gameId, pieceIdxTmp, othersIdxs[0], [0, 1]) // top + || check(gameId, pieceIdxTmp, othersIdxs[1], [-1, 0]) // right + || check(gameId, pieceIdxTmp, othersIdxs[2], [0, -1]) // bottom + || check(gameId, pieceIdxTmp, othersIdxs[3], [1, 0]) // left ) { snapped = true; break; @@ -1097,6 +1207,15 @@ function handleInput$1(gameId, playerId, input, ts) { changePlayer(gameId, playerId, { d, ts }); _playerChange(); } + if (snapped && getSnapMode(gameId) === SnapMode.REAL) { + if (getFinishedPiecesCount(gameId) === getPieceCount(gameId)) { + changeData(gameId, { finished: ts }); + _dataChange(); + } + } + if (snapped && onSnap) { + onSnap(playerId); + } } } else { @@ -1127,17 +1246,15 @@ function handleInput$1(gameId, playerId, input, ts) { return changes; } var GameCommon = { - __createPlayerObject, setGame, exists: exists$1, playerExists, getActivePlayers, getIdlePlayers, addPlayer: addPlayer$1, - getFinishedTileCount, - getTileCount, + getFinishedPiecesCount, + getPieceCount, getImageUrl, - setImageUrl, get: get$1, getAllGames, getPlayerBgColor, @@ -1147,7 +1264,7 @@ var GameCommon = { getPlayerIdByIndex, changePlayer, setPlayer, - setTile, + setPiece, setPuzzleData, getTableWidth, getTableHeight, @@ -1155,11 +1272,11 @@ var GameCommon = { getRng, getPuzzleWidth, getPuzzleHeight, - getTilesSortedByZIndex, - getFirstOwnedTile, - getTileDrawOffset, - getTileDrawSize, - getFinalTilePos, + getPiecesSortedByZIndex, + getFirstOwnedPiece, + getPieceDrawOffset, + getPieceDrawSize, + getFinalPiecePos, getStartTs, getFinishTs, handleInput: handleInput$1, @@ -1175,49 +1292,89 @@ const PUBLIC_DIR = `${BASE_DIR}/build/public/`; const DB_PATCHES_DIR = `${BASE_DIR}/src/dbpatches`; const DB_FILE = `${BASE_DIR}/data/db.sqlite`; -const log$4 = logger('GameLog.js'); -const filename = (gameId) => `${DATA_DIR}/log_${gameId}.log`; -const create = (gameId) => { - const file = filename(gameId); - if (!fs.existsSync(file)) { - fs.appendFileSync(file, ''); +const LINES_PER_LOG_FILE = 10000; +const POST_GAME_LOG_DURATION = 5 * Time.MIN; +const shouldLog = (finishTs, currentTs) => { + // when not finished yet, always log + if (!finishTs) { + return true; + } + // in finished games, log max POST_GAME_LOG_DURATION after + // the game finished, to record winning dance moves etc :P + const timeSinceGameEnd = currentTs - finishTs; + return timeSinceGameEnd <= POST_GAME_LOG_DURATION; +}; +const filename = (gameId, offset) => `${DATA_DIR}/log_${gameId}-${offset}.log`; +const idxname = (gameId) => `${DATA_DIR}/log_${gameId}.idx.log`; +const create = (gameId, ts) => { + const idxfile = idxname(gameId); + if (!fs.existsSync(idxfile)) { + fs.appendFileSync(idxfile, JSON.stringify({ + gameId: gameId, + total: 0, + lastTs: ts, + currentFile: '', + perFile: LINES_PER_LOG_FILE, + })); } }; const exists = (gameId) => { - const file = filename(gameId); - return fs.existsSync(file); + const idxfile = idxname(gameId); + return fs.existsSync(idxfile); }; -const _log = (gameId, ...args) => { - const file = filename(gameId); - if (!fs.existsSync(file)) { +const _log = (gameId, type, ...args) => { + const idxfile = idxname(gameId); + if (!fs.existsSync(idxfile)) { return; } - const str = JSON.stringify(args); - fs.appendFileSync(file, str + "\n"); + const idxObj = JSON.parse(fs.readFileSync(idxfile, 'utf-8')); + if (idxObj.total % idxObj.perFile === 0) { + idxObj.currentFile = filename(gameId, idxObj.total); + } + const tsIdx = type === Protocol.LOG_HEADER ? 3 : (args.length - 1); + const ts = args[tsIdx]; + if (type !== Protocol.LOG_HEADER) { + // for everything but header save the diff to last log entry + args[tsIdx] = ts - idxObj.lastTs; + } + const line = JSON.stringify([type, ...args]).slice(1, -1); + fs.appendFileSync(idxObj.currentFile, line + "\n"); + idxObj.total++; + idxObj.lastTs = ts; + fs.writeFileSync(idxfile, JSON.stringify(idxObj)); }; -const get = (gameId) => { - const file = filename(gameId); +const get = (gameId, offset = 0) => { + const idxfile = idxname(gameId); + if (!fs.existsSync(idxfile)) { + return []; + } + const file = filename(gameId, offset); if (!fs.existsSync(file)) { return []; } const lines = fs.readFileSync(file, 'utf-8').split("\n"); - return lines.filter((line) => !!line).map((line) => { - try { - return JSON.parse(line); - } - catch (e) { - log$4.log(line); - log$4.log(e); - } + const log = lines.filter(line => !!line).map(line => { + return JSON.parse(`[${line}]`); }); + if (offset === 0 && log.length > 0) { + log[0][5] = DefaultScoreMode(log[0][5]); + log[0][6] = DefaultShapeMode(log[0][6]); + log[0][7] = DefaultSnapMode(log[0][7]); + log[0][8] = log[0][8] || null; + } + return log; }; var GameLog = { + shouldLog, create, exists, log: _log, get, + filename, + idxname, }; +const log$4 = logger('Images.ts'); const resizeImage = async (filename) => { if (!filename.toLowerCase().match(/\.(jpe?g|webp|png)$/)) { return; @@ -1241,44 +1398,66 @@ const resizeImage = async (filename) => { [150, 100], [375, 210], ]; - for (let [w, h] of sizes) { - console.log(w, h, imagePath); - await sharpImg.resize(w, h, { fit: 'contain' }).toFile(`${imageOutPath}-${w}x${h}.webp`); + for (const [w, h] of sizes) { + log$4.info(w, h, imagePath); + await sharpImg + .resize(w, h, { fit: 'contain' }) + .toFile(`${imageOutPath}-${w}x${h}.webp`); } }; async function getExifOrientation(imagePath) { - return new Promise((resolve, reject) => { - new exif.ExifImage({ image: imagePath }, function (error, exifData) { + return new Promise((resolve) => { + new exif.ExifImage({ image: imagePath }, (error, exifData) => { if (error) { resolve(0); } else { - resolve(exifData.image.Orientation); + resolve(exifData.image.Orientation || 0); } }); }); } +const getAllTags = (db) => { + const query = ` +select c.id, c.slug, c.title, count(*) as total from categories c +inner join image_x_category ixc on c.id = ixc.category_id +inner join images i on i.id = ixc.image_id +group by c.id order by total desc;`; + return db._getMany(query).map(row => ({ + id: parseInt(row.id, 10) || 0, + slug: row.slug, + title: row.title, + total: parseInt(row.total, 10) || 0, + })); +}; const getTags = (db, imageId) => { const query = ` select * from categories c inner join image_x_category ixc on c.id = ixc.category_id where ixc.image_id = ?`; - return db._getMany(query, [imageId]); + return db._getMany(query, [imageId]).map(row => ({ + id: parseInt(row.id, 10) || 0, + slug: row.slug, + title: row.title, + total: 0, + })); }; const imageFromDb = (db, imageId) => { const i = db.get('images', { id: imageId }); return { id: i.id, + uploaderUserId: i.uploader_user_id, filename: i.filename, - file: `${UPLOAD_DIR}/${i.filename}`, url: `${UPLOAD_URL}/${encodeURIComponent(i.filename)}`, title: i.title, tags: getTags(db, i.id), created: i.created * 1000, + width: i.width, + height: i.height, }; }; -const allImagesFromDb = (db, tagSlugs, sort) => { - const sortMap = { +const allImagesFromDb = (db, tagSlugs, orderBy) => { + const orderByMap = { alpha_asc: [{ filename: 1 }], alpha_desc: [{ filename: -1 }], date_asc: [{ created: 1 }], @@ -1303,38 +1482,45 @@ inner join images i on i.id = ixc.image_id ${where.sql}; } wheresRaw['id'] = { '$in': ids }; } - const images = db.getMany('images', wheresRaw, sortMap[sort]); + const images = db.getMany('images', wheresRaw, orderByMap[orderBy]); return images.map(i => ({ id: i.id, + uploaderUserId: i.uploader_user_id, filename: i.filename, - file: `${UPLOAD_DIR}/${i.filename}`, url: `${UPLOAD_URL}/${encodeURIComponent(i.filename)}`, title: i.title, tags: getTags(db, i.id), created: i.created * 1000, + width: i.width, + height: i.height, })); }; +/** + * @deprecated old function, now database is used + */ const allImagesFromDisk = (tags, sort) => { let images = fs.readdirSync(UPLOAD_DIR) .filter(f => f.toLowerCase().match(/\.(jpe?g|webp|png)$/)) .map(f => ({ id: 0, + uploaderUserId: null, filename: f, - file: `${UPLOAD_DIR}/${f}`, url: `${UPLOAD_URL}/${encodeURIComponent(f)}`, title: f.replace(/\.[a-z]+$/, ''), tags: [], created: fs.statSync(`${UPLOAD_DIR}/${f}`).mtime.getTime(), + width: 0, + height: 0, // may have to fill when the function is used again })); switch (sort) { case 'alpha_asc': images = images.sort((a, b) => { - return a.file > b.file ? 1 : -1; + return a.filename > b.filename ? 1 : -1; }); break; case 'alpha_desc': images = images.sort((a, b) => { - return a.file < b.file ? 1 : -1; + return a.filename < b.filename ? 1 : -1; }); break; case 'date_asc': @@ -1352,7 +1538,7 @@ const allImagesFromDisk = (tags, sort) => { return images; }; async function getDimensions(imagePath) { - let dimensions = sizeOf(imagePath); + const dimensions = sizeOf(imagePath); const orientation = await getExifOrientation(imagePath); // when image is rotated to the left or right, switch width/height // https://jdhao.github.io/2019/07/31/image_rotation_exif_info/ @@ -1371,6 +1557,7 @@ var Images = { allImagesFromDisk, imageFromDb, allImagesFromDb, + getAllTags, resizeImage, getDimensions, }; @@ -1378,24 +1565,24 @@ var Images = { // cut size of each puzzle tile in the // final resized version of the puzzle image const TILE_SIZE = 64; -async function createPuzzle(rng, targetTiles, image, ts) { - const imagePath = image.file; +async function createPuzzle(rng, targetTiles, image, ts, shapeMode) { + const imagePath = `${UPLOAD_DIR}/${image.filename}`; const imageUrl = image.url; // determine puzzle information from the image dimensions const dim = await Images.getDimensions(imagePath); if (!dim.w || !dim.h) { throw `[ 2021-05-16 invalid dimension for path ${imagePath} ]`; } - const info = determinePuzzleInfo(dim.w, dim.h, targetTiles); - let tiles = new Array(info.tiles); - for (let i = 0; i < tiles.length; i++) { - tiles[i] = { idx: i }; + const info = determinePuzzleInfo(dim, targetTiles); + const rawPieces = new Array(info.tiles); + for (let i = 0; i < rawPieces.length; i++) { + rawPieces[i] = { idx: i }; } - const shapes = determinePuzzleTileShapes(rng, info); + const shapes = determinePuzzleTileShapes(rng, info, shapeMode); let positions = new Array(info.tiles); - for (let tile of tiles) { - const coord = Util.coordByTileIdx(info, tile.idx); - positions[tile.idx] = { + for (const piece of rawPieces) { + const coord = Util.coordByPieceIdx(info, piece.idx); + positions[piece.idx] = { // instead of info.tileSize, we use info.tileDrawSize // to spread the tiles a bit x: coord.x * info.tileSize * 1.5, @@ -1405,7 +1592,7 @@ async function createPuzzle(rng, targetTiles, image, ts) { const tableWidth = info.width * 3; const tableHeight = info.height * 3; const off = info.tileSize * 1.5; - let last = { + const last = { x: info.width - (1 * off), y: info.height - (2 * off), }; @@ -1414,7 +1601,7 @@ async function createPuzzle(rng, targetTiles, image, ts) { let diffX = off; let diffY = 0; let index = 0; - for (let pos of positions) { + for (const pos of positions) { pos.x = last.x; pos.y = last.y; last.x += diffX; @@ -1440,9 +1627,9 @@ async function createPuzzle(rng, targetTiles, image, ts) { } // then shuffle the positions positions = rng.shuffle(positions); - const pieces = tiles.map(tile => { - return Util.encodeTile({ - idx: tile.idx, + const pieces = rawPieces.map(piece => { + return Util.encodePiece({ + idx: piece.idx, group: 0, z: 0, // who owns the tile @@ -1453,7 +1640,7 @@ async function createPuzzle(rng, targetTiles, image, ts) { // physical current position of the tile (x/y in pixels) // this position is the initial position only and is the // value that changes when moving a tile - pos: positions[tile.idx], + pos: positions[piece.idx], }); }); // Complete puzzle object @@ -1478,6 +1665,7 @@ async function createPuzzle(rng, targetTiles, image, ts) { // information that was used to create the puzzle targetTiles: targetTiles, imageUrl, + image: image, width: info.width, height: info.height, tileSize: info.tileSize, @@ -1500,11 +1688,22 @@ async function createPuzzle(rng, targetTiles, image, ts) { }, }; } -function determinePuzzleTileShapes(rng, info) { - const tabs = [-1, 1]; +function determineTabs(shapeMode) { + switch (shapeMode) { + case ShapeMode.ANY: + return [-1, 0, 1]; + case ShapeMode.FLAT: + return [0]; + case ShapeMode.NORMAL: + default: + return [-1, 1]; + } +} +function determinePuzzleTileShapes(rng, info, shapeMode) { + const tabs = determineTabs(shapeMode); const shapes = new Array(info.tiles); for (let i = 0; i < info.tiles; i++) { - let coord = Util.coordByTileIdx(info, i); + const coord = Util.coordByPieceIdx(info, i); shapes[i] = { top: coord.y === 0 ? 0 : shapes[i - info.tilesX].bottom * -1, right: coord.x === info.tilesX - 1 ? 0 : rng.choice(tabs), @@ -1514,9 +1713,9 @@ function determinePuzzleTileShapes(rng, info) { } return shapes.map(Util.encodeShape); } -const determineTilesXY = (w, h, targetTiles) => { - const w_ = w < h ? (w * h) : (w * w); - const h_ = w < h ? (h * h) : (w * h); +const determineTilesXY = (dim, targetTiles) => { + const w_ = dim.w < dim.h ? (dim.w * dim.h) : (dim.w * dim.w); + const h_ = dim.w < dim.h ? (dim.h * dim.h) : (dim.w * dim.h); let size = 0; let tiles = 0; do { @@ -1529,8 +1728,8 @@ const determineTilesXY = (w, h, targetTiles) => { tilesY: Math.round(h_ / size), }; }; -const determinePuzzleInfo = (w, h, targetTiles) => { - const { tilesX, tilesY } = determineTilesXY(w, h, targetTiles); +const determinePuzzleInfo = (dim, targetTiles) => { + const { tilesX, tilesY } = determineTilesXY(dim, targetTiles); const tiles = tilesX * tilesY; const tileSize = TILE_SIZE; const width = tilesX * tileSize; @@ -1550,14 +1749,70 @@ const determinePuzzleInfo = (w, h, targetTiles) => { }; const log$3 = logger('GameStorage.js'); -const DIRTY_GAMES = {}; +const dirtyGames = {}; function setDirty(gameId) { - DIRTY_GAMES[gameId] = true; + dirtyGames[gameId] = true; } function setClean(gameId) { - delete DIRTY_GAMES[gameId]; + delete dirtyGames[gameId]; } -function loadGames() { +function loadGamesFromDb(db) { + const gameRows = db.getMany('games'); + for (const gameRow of gameRows) { + loadGameFromDb(db, gameRow.id); + } +} +function loadGameFromDb(db, gameId) { + const gameRow = db.get('games', { id: gameId }); + let game; + try { + game = JSON.parse(gameRow.data); + } + catch { + log$3.log(`[ERR] unable to load game from db ${gameId}`); + } + if (typeof game.puzzle.data.started === 'undefined') { + game.puzzle.data.started = gameRow.created; + } + if (typeof game.puzzle.data.finished === 'undefined') { + game.puzzle.data.finished = gameRow.finished; + } + if (!Array.isArray(game.players)) { + game.players = Object.values(game.players); + } + const gameObject = storeDataToGame(game, game.creator_user_id); + GameCommon.setGame(gameObject.id, gameObject); +} +function persistGamesToDb(db) { + for (const gameId of Object.keys(dirtyGames)) { + persistGameToDb(db, gameId); + } +} +function persistGameToDb(db, gameId) { + const game = GameCommon.get(gameId); + if (!game) { + log$3.error(`[ERROR] unable to persist non existing game ${gameId}`); + return; + } + if (game.id in dirtyGames) { + setClean(game.id); + } + db.upsert('games', { + id: game.id, + creator_user_id: game.creatorUserId, + image_id: game.puzzle.info.image?.id, + created: game.puzzle.data.started, + finished: game.puzzle.data.finished, + data: gameToStoreData(game) + }, { + id: game.id, + }); + log$3.info(`[INFO] persisted game ${game.id}`); +} +/** + * @deprecated + */ +function loadGamesFromDisk() { const files = fs.readdirSync(DATA_DIR); for (const f of files) { const m = f.match(/^([a-z0-9]+)\.json$/); @@ -1565,10 +1820,13 @@ function loadGames() { continue; } const gameId = m[1]; - loadGame(gameId); + loadGameFromDisk(gameId); } } -function loadGame(gameId) { +/** + * @deprecated + */ +function loadGameFromDisk(gameId) { const file = `${DATA_DIR}/${gameId}.json`; const contents = fs.readFileSync(file, 'utf-8'); let game; @@ -1583,37 +1841,57 @@ function loadGame(gameId) { } if (typeof game.puzzle.data.finished === 'undefined') { const unfinished = game.puzzle.tiles - .map(Util.decodeTile) + .map(Util.decodePiece) .find((t) => t.owner !== -1); game.puzzle.data.finished = unfinished ? 0 : Time.timestamp(); } if (!Array.isArray(game.players)) { game.players = Object.values(game.players); } - const gameObject = { - id: game.id, - rng: { - type: game.rng ? game.rng.type : '_fake_', - obj: game.rng ? Rng.unserialize(game.rng.obj) : new Rng(0), - }, - puzzle: game.puzzle, - players: game.players, - evtInfos: {}, - scoreMode: game.scoreMode || ScoreMode.FINAL, - }; + const gameObject = storeDataToGame(game, null); GameCommon.setGame(gameObject.id, gameObject); } -function persistGames() { - for (const gameId of Object.keys(DIRTY_GAMES)) { - persistGame(gameId); +/** + * @deprecated + */ +function persistGamesToDisk() { + for (const gameId of Object.keys(dirtyGames)) { + persistGameToDisk(gameId); } } -function persistGame(gameId) { +/** + * @deprecated + */ +function persistGameToDisk(gameId) { const game = GameCommon.get(gameId); - if (game.id in DIRTY_GAMES) { + if (!game) { + log$3.error(`[ERROR] unable to persist non existing game ${gameId}`); + return; + } + if (game.id in dirtyGames) { setClean(game.id); } - fs.writeFileSync(`${DATA_DIR}/${game.id}.json`, JSON.stringify({ + fs.writeFileSync(`${DATA_DIR}/${game.id}.json`, gameToStoreData(game)); + log$3.info(`[INFO] persisted game ${game.id}`); +} +function storeDataToGame(storeData, creatorUserId) { + return { + id: storeData.id, + creatorUserId, + rng: { + type: storeData.rng ? storeData.rng.type : '_fake_', + obj: storeData.rng ? Rng.unserialize(storeData.rng.obj) : new Rng(0), + }, + puzzle: storeData.puzzle, + players: storeData.players, + evtInfos: {}, + scoreMode: DefaultScoreMode(storeData.scoreMode), + shapeMode: DefaultShapeMode(storeData.shapeMode), + snapMode: DefaultSnapMode(storeData.snapMode), + }; +} +function gameToStoreData(game) { + return JSON.stringify({ id: game.id, rng: { type: game.rng.type, @@ -1622,52 +1900,63 @@ function persistGame(gameId) { puzzle: game.puzzle, players: game.players, scoreMode: game.scoreMode, - })); - log$3.info(`[INFO] persisted game ${game.id}`); + shapeMode: game.shapeMode, + snapMode: game.snapMode, + }); } var GameStorage = { - loadGames, - loadGame, - persistGames, - persistGame, + // disk functions are deprecated + loadGamesFromDisk, + loadGameFromDisk, + persistGamesToDisk, + persistGameToDisk, + loadGamesFromDb, + loadGameFromDb, + persistGamesToDb, + persistGameToDb, setDirty, }; -async function createGameObject(gameId, targetTiles, image, ts, scoreMode) { +async function createGameObject(gameId, targetTiles, image, ts, scoreMode, shapeMode, snapMode, creatorUserId) { const seed = Util.hash(gameId + ' ' + ts); const rng = new Rng(seed); return { id: gameId, + creatorUserId, rng: { type: 'Rng', obj: rng }, - puzzle: await createPuzzle(rng, targetTiles, image, ts), + puzzle: await createPuzzle(rng, targetTiles, image, ts, shapeMode), players: [], evtInfos: {}, scoreMode, + shapeMode, + snapMode, }; } -async function createGame(gameId, targetTiles, image, ts, scoreMode) { - const gameObject = await createGameObject(gameId, targetTiles, image, ts, scoreMode); - GameLog.create(gameId); - GameLog.log(gameId, Protocol.LOG_HEADER, 1, targetTiles, image, ts, scoreMode); +async function createGame(gameId, targetTiles, image, ts, scoreMode, shapeMode, snapMode, creatorUserId) { + const gameObject = await createGameObject(gameId, targetTiles, image, ts, scoreMode, shapeMode, snapMode, creatorUserId); + GameLog.create(gameId, ts); + GameLog.log(gameId, Protocol.LOG_HEADER, 1, targetTiles, image, ts, scoreMode, shapeMode, snapMode, gameObject.creatorUserId); GameCommon.setGame(gameObject.id, gameObject); GameStorage.setDirty(gameId); } function addPlayer(gameId, playerId, ts) { - const idx = GameCommon.getPlayerIndexById(gameId, playerId); - const diff = ts - GameCommon.getStartTs(gameId); - if (idx === -1) { - GameLog.log(gameId, Protocol.LOG_ADD_PLAYER, playerId, diff); - } - else { - GameLog.log(gameId, Protocol.LOG_UPDATE_PLAYER, idx, diff); + if (GameLog.shouldLog(GameCommon.getFinishTs(gameId), ts)) { + const idx = GameCommon.getPlayerIndexById(gameId, playerId); + if (idx === -1) { + GameLog.log(gameId, Protocol.LOG_ADD_PLAYER, playerId, ts); + } + else { + GameLog.log(gameId, Protocol.LOG_UPDATE_PLAYER, idx, ts); + } } GameCommon.addPlayer(gameId, playerId, ts); GameStorage.setDirty(gameId); } function handleInput(gameId, playerId, input, ts) { - const idx = GameCommon.getPlayerIndexById(gameId, playerId); - const diff = ts - GameCommon.getStartTs(gameId); - GameLog.log(gameId, Protocol.LOG_HANDLE_INPUT, idx, input, diff); + if (GameLog.shouldLog(GameCommon.getFinishTs(gameId), ts)) { + const idx = GameCommon.getPlayerIndexById(gameId, playerId); + GameLog.log(gameId, Protocol.LOG_HANDLE_INPUT, idx, input, ts); + } const ret = GameCommon.handleInput(gameId, playerId, input, ts); GameStorage.setDirty(gameId); return ret; @@ -1677,16 +1966,6 @@ var Game = { createGame, addPlayer, handleInput, - getAllGames: GameCommon.getAllGames, - getActivePlayers: GameCommon.getActivePlayers, - getFinishedTileCount: GameCommon.getFinishedTileCount, - getImageUrl: GameCommon.getImageUrl, - getTileCount: GameCommon.getTileCount, - exists: GameCommon.exists, - playerExists: GameCommon.playerExists, - get: GameCommon.get, - getStartTs: GameCommon.getStartTs, - getFinishTs: GameCommon.getFinishTs, }; const log$2 = logger('GameSocket.js'); @@ -1730,9 +2009,6 @@ var GameSockets = { }; const log$1 = logger('Db.ts'); -// assume 32766 SQLITE_MAX_VARIABLE_NUMBER -// @see https://sqlite.org/limits.html -const SQLITE_MAX_VARIABLE_NUMBER = 32766; class Db { constructor(file, patchesDir) { this.file = file; @@ -1787,7 +2063,7 @@ class Db { let prop = '$nin'; if (where[k][prop]) { if (where[k][prop].length > 0) { - wheres.push(k + ' NOT IN (' + where[k][prop].map((_) => '?') + ')'); + wheres.push(k + ' NOT IN (' + where[k][prop].map(() => '?') + ')'); values.push(...where[k][prop]); } continue; @@ -1795,7 +2071,7 @@ class Db { prop = '$in'; if (where[k][prop]) { if (where[k][prop].length > 0) { - wheres.push(k + ' IN (' + where[k][prop].map((_) => '?') + ')'); + wheres.push(k + ' IN (' + where[k][prop].map(() => '?') + ')'); values.push(...where[k][prop]); } continue; @@ -1858,52 +2134,14 @@ class Db { } return this.get(table, check)[idcol]; // get id manually } - /** - * Inserts data into table and returns the last insert id - */ insert(table, data) { const keys = Object.keys(data); const values = keys.map(k => data[k]); const sql = 'INSERT INTO ' + table + ' (' + keys.join(',') + ')' - + ' VALUES (' + keys.map(k => '?').join(',') + ')'; + + ' VALUES (' + keys.map(() => '?').join(',') + ')'; return this.run(sql, values).lastInsertRowid; } - /** - * Inserts multiple datas into table. Returns the total number - * of changes. - */ - insertMany(table, datas) { - if (datas.length === 0) { - return 0; - } - const keys = Object.keys(datas[0]); - const runChunk = (vars, values) => { - const sql = `INSERT INTO ${table} - (${keys.join(',')}) - VALUES ${vars.join(',')}`; - return this.run(sql, values).changes; - }; - let len = 0; - let vars = []; - let values = []; - let changes = 0; - for (const data of datas) { - if (len + keys.length > SQLITE_MAX_VARIABLE_NUMBER) { - changes += runChunk(vars, values); - len = 0; - vars = []; - values = []; - } - len += keys.length; - vars.push('(' + keys.map(_ => '?').join(',') + ')'); - values.push(...keys.map(k => data[k])); - } - if (len > 0) { - changes += runChunk(vars, values); - } - return changes; - } update(table, data, whereRaw = {}) { const keys = Object.keys(data); if (keys.length === 0) { @@ -1935,6 +2173,7 @@ const log = logger('main.js'); const port = config.http.port; const hostname = config.http.hostname; const app = express(); +app.use(compression()); const storage = multer.diskStorage({ destination: UPLOAD_DIR, filename: function (req, file, cb) { @@ -1942,31 +2181,64 @@ const storage = multer.diskStorage({ } }); const upload = multer({ storage }).single('file'); +app.get('/api/me', (req, res) => { + let user = getUser(db, req); + res.send({ + id: user ? user.id : null, + created: user ? user.created : null, + }); +}); app.get('/api/conf', (req, res) => { res.send({ WS_ADDRESS: config.ws.connectstring, }); }); +app.get('/api/replay-data', async (req, res) => { + const q = req.query; + const offset = parseInt(q.offset, 10) || 0; + if (offset < 0) { + res.status(400).send({ reason: 'bad offset' }); + return; + } + const size = parseInt(q.size, 10) || 10000; + if (size < 0 || size > 10000) { + res.status(400).send({ reason: 'bad size' }); + return; + } + const gameId = q.gameId || ''; + if (!GameLog.exists(q.gameId)) { + res.status(404).send({ reason: 'no log found' }); + return; + } + const log = GameLog.get(gameId, offset); + let game = null; + if (offset === 0) { + // also need the game + game = await Game.createGameObject(gameId, log[0][2], log[0][3], // must be ImageInfo + log[0][4], log[0][5], log[0][6], log[0][7], log[0][8]); + } + res.send({ log, game: game ? Util.encodeGame(game) : null }); +}); app.get('/api/newgame-data', (req, res) => { const q = req.query; const tagSlugs = q.tags ? q.tags.split(',') : []; res.send({ images: Images.allImagesFromDb(db, tagSlugs, q.sort), - tags: db.getMany('categories', {}, [{ title: 1 }]), + tags: Images.getAllTags(db), }); }); app.get('/api/index-data', (req, res) => { const ts = Time.timestamp(); const games = [ - ...Game.getAllGames().map((game) => ({ + ...GameCommon.getAllGames().map((game) => ({ id: game.id, hasReplay: GameLog.exists(game.id), - started: Game.getStartTs(game.id), - finished: Game.getFinishTs(game.id), - tilesFinished: Game.getFinishedTileCount(game.id), - tilesTotal: Game.getTileCount(game.id), - players: Game.getActivePlayers(game.id, ts).length, - imageUrl: Game.getImageUrl(game.id), + started: GameCommon.getStartTs(game.id), + finished: GameCommon.getFinishTs(game.id), + tilesFinished: GameCommon.getFinishedPiecesCount(game.id), + tilesTotal: GameCommon.getPieceCount(game.id), + players: GameCommon.getActivePlayers(game.id, ts).length, + imageUrl: GameCommon.getImageUrl(game.id), })), ]; res.send({ @@ -1974,6 +2246,28 @@ app.get('/api/index-data', (req, res) => { gamesFinished: games.filter(g => !!g.finished), }); }); +const getOrCreateUser = (db, req) => { + let user = getUser(db, req); + if (!user) { + db.insert('users', { + 'client_id': req.headers['client-id'], + 'client_secret': req.headers['client-secret'], + 'created': Time.timestamp(), + }); + user = getUser(db, req); + } + return user; +}; +const getUser = (db, req) => { + let user = db.get('users', { + 'client_id': req.headers['client-id'], + 'client_secret': req.headers['client-secret'], + }); + if (user) { + user.id = parseInt(user.id, 10); + } + return user; +}; const setImageTags = (db, imageId, tags) => { tags.forEach((tag) => { const slug = Util.slug(tag); @@ -1986,8 +2280,18 @@ const setImageTags = (db, imageId, tags) => { } }); }; -app.post('/api/save-image', bodyParser.json(), (req, res) => { +app.post('/api/save-image', express.json(), (req, res) => { + let user = getUser(db, req); + if (!user || !user.id) { + res.status(403).send({ ok: false, error: 'forbidden' }); + return; + } const data = req.body; + let image = db.get('images', { id: data.id }); + if (parseInt(image.uploader_user_id, 10) !== user.id) { + res.status(403).send({ ok: false, error: 'forbidden' }); + return; + } db.update('images', { title: data.title, }, { @@ -2012,25 +2316,36 @@ app.post('/api/upload', (req, res) => { log.log(err); res.status(400).send("Something went wrong!"); } + const user = getOrCreateUser(db, req); + const dim = await Images.getDimensions(`${UPLOAD_DIR}/${req.file.filename}`); const imageId = db.insert('images', { + uploader_user_id: user.id, filename: req.file.filename, filename_original: req.file.originalname, title: req.body.title || '', created: Time.timestamp(), + width: dim.w, + height: dim.h, }); if (req.body.tags) { - setImageTags(db, imageId, req.body.tags); + const tags = req.body.tags.split(',').filter((tag) => !!tag); + setImageTags(db, imageId, tags); } res.send(Images.imageFromDb(db, imageId)); }); }); -app.post('/newgame', bodyParser.json(), async (req, res) => { +app.post('/api/newgame', express.json(), async (req, res) => { + let user = getOrCreateUser(db, req); + if (!user || !user.id) { + res.status(403).send({ ok: false, error: 'forbidden' }); + return; + } const gameSettings = req.body; log.log(gameSettings); const gameId = Util.uniqId(); - if (!Game.exists(gameId)) { + if (!GameCommon.exists(gameId)) { const ts = Time.timestamp(); - await Game.createGame(gameId, gameSettings.tiles, gameSettings.image, ts, gameSettings.scoreMode); + await Game.createGame(gameId, gameSettings.tiles, gameSettings.image, ts, gameSettings.scoreMode, gameSettings.shapeMode, gameSettings.snapMode, user.id); } res.send({ id: gameId }); }); @@ -2038,15 +2353,14 @@ app.use('/uploads/', express.static(UPLOAD_DIR)); app.use('/', express.static(PUBLIC_DIR)); const wss = new WebSocketServer(config.ws); const notify = (data, sockets) => { - // TODO: throttle? - for (let socket of sockets) { + for (const socket of sockets) { wss.notifyOne(data, socket); } }; wss.on('close', async ({ socket }) => { try { const proto = socket.protocol.split('|'); - const clientId = proto[0]; + // const clientId = proto[0] const gameId = proto[1]; GameSockets.removeSocket(gameId, socket); } @@ -2059,41 +2373,36 @@ wss.on('message', async ({ socket, data }) => { const proto = socket.protocol.split('|'); const clientId = proto[0]; const gameId = proto[1]; + // TODO: maybe handle different types of data + // (but atm only string comes through) const msg = JSON.parse(data); const msgType = msg[0]; switch (msgType) { - case Protocol.EV_CLIENT_INIT_REPLAY: - { - if (!GameLog.exists(gameId)) { - throw `[gamelog ${gameId} does not exist... ]`; - } - const log = GameLog.get(gameId); - const game = await Game.createGameObject(gameId, log[0][2], log[0][3], log[0][4], log[0][5] || ScoreMode.FINAL); - notify([Protocol.EV_SERVER_INIT_REPLAY, Util.encodeGame(game), log], [socket]); - } - break; case Protocol.EV_CLIENT_INIT: { - if (!Game.exists(gameId)) { + if (!GameCommon.exists(gameId)) { throw `[game ${gameId} does not exist... ]`; } const ts = Time.timestamp(); Game.addPlayer(gameId, clientId, ts); GameSockets.addSocket(gameId, socket); - const game = Game.get(gameId); + const game = GameCommon.get(gameId); + if (!game) { + throw `[game ${gameId} does not exist (anymore)... ]`; + } notify([Protocol.EV_SERVER_INIT, Util.encodeGame(game)], [socket]); } break; case Protocol.EV_CLIENT_EVENT: { - if (!Game.exists(gameId)) { + if (!GameCommon.exists(gameId)) { throw `[game ${gameId} does not exist... ]`; } const clientSeq = msg[1]; const clientEvtData = msg[2]; const ts = Time.timestamp(); let sendGame = false; - if (!Game.playerExists(gameId, clientId)) { + if (!GameCommon.playerExists(gameId, clientId)) { Game.addPlayer(gameId, clientId, ts); sendGame = true; } @@ -2102,7 +2411,10 @@ wss.on('message', async ({ socket, data }) => { sendGame = true; } if (sendGame) { - const game = Game.get(gameId); + const game = GameCommon.get(gameId); + if (!game) { + throw `[game ${gameId} does not exist (anymore)... ]`; + } notify([Protocol.EV_SERVER_INIT, Util.encodeGame(game)], [socket]); } const changes = Game.handleInput(gameId, clientId, clientEvtData, ts); @@ -2115,12 +2427,12 @@ wss.on('message', async ({ socket, data }) => { log.error(e); } }); -GameStorage.loadGames(); +GameStorage.loadGamesFromDb(db); const server = app.listen(port, hostname, () => log.log(`server running on http://${hostname}:${port}`)); wss.listen(); const memoryUsageHuman = () => { const totalHeapSize = v8.getHeapStatistics().total_available_size; - let totalHeapSizeInGB = (totalHeapSize / 1024 / 1024 / 1024).toFixed(2); + const totalHeapSizeInGB = (totalHeapSize / 1024 / 1024 / 1024).toFixed(2); log.log(`Total heap size (bytes) ${totalHeapSize}, (GB ~${totalHeapSizeInGB})`); const used = process.memoryUsage().heapUsed / 1024 / 1024; log.log(`Mem: ${Math.round(used * 100) / 100}M`); @@ -2129,7 +2441,7 @@ memoryUsageHuman(); // persist games in fixed interval const persistInterval = setInterval(() => { log.log('Persisting games...'); - GameStorage.persistGames(); + GameStorage.persistGamesToDb(db); memoryUsageHuman(); }, config.persistence.interval); const gracefulShutdown = (signal) => { @@ -2137,7 +2449,7 @@ const gracefulShutdown = (signal) => { log.log('clearing persist interval...'); clearInterval(persistInterval); log.log('persisting games...'); - GameStorage.persistGames(); + GameStorage.persistGamesToDb(db); log.log('shutting down webserver...'); server.close(); log.log('shutting down websocketserver...'); @@ -2146,12 +2458,12 @@ const gracefulShutdown = (signal) => { process.exit(); }; // used by nodemon -process.once('SIGUSR2', function () { +process.once('SIGUSR2', () => { gracefulShutdown('SIGUSR2'); }); -process.once('SIGINT', function (code) { +process.once('SIGINT', () => { gracefulShutdown('SIGINT'); }); -process.once('SIGTERM', function (code) { +process.once('SIGTERM', () => { gracefulShutdown('SIGTERM'); }); diff --git a/package-lock.json b/package-lock.json index 9d2fc65..199e26a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,6 @@ "": { "dependencies": { "better-sqlite3": "^7.4.0", - "body-parser": "^1.19.0", "exif": "^0.6.0", "express": "^4.17.1", "image-size": "^0.9.3", @@ -18,19 +17,24 @@ }, "devDependencies": { "@types/better-sqlite3": "^5.4.1", + "@types/compression": "^1.7.0", "@types/exif": "^0.6.2", "@types/express": "^4.17.11", "@types/multer": "^1.4.5", "@types/sharp": "^0.28.1", "@types/ws": "^7.4.4", + "@typescript-eslint/eslint-plugin": "^4.25.0", + "@typescript-eslint/parser": "^4.25.0", "@vitejs/plugin-vue": "^1.2.2", "@vuedx/typescript-plugin-vue": "^0.6.3", + "compression": "^1.7.4", + "eslint": "^7.27.0", "jest": "^26.6.3", "rollup": "^2.48.0", "rollup-plugin-typescript2": "^0.30.0", "rollup-plugin-vue": "^6.0.0-beta.10", "ts-node": "^9.1.1", - "typescript": "^4.2.4", + "typescript": "^4.3.2", "vite": "^2.3.2" }, "engines": { @@ -537,6 +541,62 @@ "node": ">=0.1.95" } }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz", + "integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/@intlify/core": { "version": "9.1.6", "resolved": "https://registry.npmjs.org/@intlify/core/-/core-9.1.6.tgz", @@ -1477,6 +1537,15 @@ "integrity": "sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw==", "dev": true }, + "node_modules/@types/compression": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.0.tgz", + "integrity": "sha512-3LzWUM+3k3XdWOUk/RO+uSjv7YWOatYq2QADJntK1pjkk4DfVP0KrIEPDnXRJxAAGKe0VpIPRmlINLDuCedZWw==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/connect": { "version": "3.4.34", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", @@ -1557,6 +1626,12 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, "node_modules/@types/micromatch": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.1.tgz", @@ -1660,6 +1735,229 @@ "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", "dev": true }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.25.0.tgz", + "integrity": "sha512-Qfs3dWkTMKkKwt78xp2O/KZQB8MPS1UQ5D3YW2s6LQWBE1074BE+Rym+b1pXZIX3M3fSvPUDaCvZLKV2ylVYYQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "4.25.0", + "@typescript-eslint/scope-manager": "4.25.0", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "lodash": "^4.17.15", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^4.0.0", + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.25.0.tgz", + "integrity": "sha512-f0doRE76vq7NEEU0tw+ajv6CrmPelw5wLoaghEHkA2dNLFb3T/zJQqGPQ0OYt5XlZaS13MtnN+GTPCuUVg338w==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.25.0", + "@typescript-eslint/types": "4.25.0", + "@typescript-eslint/typescript-estree": "4.25.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.25.0.tgz", + "integrity": "sha512-OZFa1SKyEJpAhDx8FcbWyX+vLwh7OEtzoo2iQaeWwxucyfbi0mT4DijbOSsTgPKzGHr6GrF2V5p/CEpUH/VBxg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "4.25.0", + "@typescript-eslint/types": "4.25.0", + "@typescript-eslint/typescript-estree": "4.25.0", + "debug": "^4.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.25.0.tgz", + "integrity": "sha512-2NElKxMb/0rya+NJG1U71BuNnp1TBd1JgzYsldsdA83h/20Tvnf/HrwhiSlNmuq6Vqa0EzidsvkTArwoq+tH6w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.25.0", + "@typescript-eslint/visitor-keys": "4.25.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.25.0.tgz", + "integrity": "sha512-+CNINNvl00OkW6wEsi32wU5MhHti2J25TJsJJqgQmJu3B3dYDBcmOxcE5w9cgoM13TrdE/5ND2HoEnBohasxRQ==", + "dev": true, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.25.0.tgz", + "integrity": "sha512-1B8U07TGNAFMxZbSpF6jqiDs1cVGO0izVkf18Q/SPcUAc9LhHxzvSowXDTvkHMWUVuPpagupaW63gB6ahTXVlg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.25.0", + "@typescript-eslint/visitor-keys": "4.25.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.25.0.tgz", + "integrity": "sha512-AmkqV9dDJVKP/TcZrbf6s6i1zYXt5Hl8qOLrRDTFfRNae4+LB8A4N3i+FLZPW85zIxRy39BgeWOfMS3HoH5ngg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.25.0", + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@vitejs/plugin-vue": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.2.2.tgz", @@ -2014,6 +2312,15 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/acorn-walk": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", @@ -2051,6 +2358,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -2199,6 +2515,15 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", @@ -2235,6 +2560,15 @@ "node": ">=0.10.0" } }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3165,6 +3499,60 @@ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3545,6 +3933,30 @@ "node": ">= 10.14.2" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/domexception": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", @@ -3631,6 +4043,18 @@ "once": "^1.4.0" } }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -3695,6 +4119,366 @@ "source-map": "~0.6.1" } }, + "node_modules/eslint": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.27.0.tgz", + "integrity": "sha512-JZuR6La2ZF0UD384lcbnd0Cgg6QJjiCwhMD6eU4h/VGPcVGwawNNzKU41tgokGXnfjOOyI6QIffthhJTPzzuRA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.1", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", + "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -3708,6 +4492,30 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, "node_modules/estraverse": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", @@ -4187,6 +4995,18 @@ "bser": "2.1.1" } }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -4264,6 +5084,25 @@ "node": ">=8" } }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "dev": true + }, "node_modules/for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -4380,6 +5219,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "node_modules/gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -4530,6 +5375,35 @@ "node": ">=4" } }, + "node_modules/globby": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", + "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/graceful-fs": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", @@ -4796,6 +5670,15 @@ } ] }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/image-size": { "version": "0.9.7", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.9.7.tgz", @@ -4810,6 +5693,31 @@ "node": ">=10.18.0" } }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/import-local": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", @@ -7048,6 +7956,12 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -7192,6 +8106,24 @@ "dev": true, "peer": true }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, "node_modules/lru_map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", @@ -7871,6 +8803,15 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -7968,6 +8909,18 @@ "node": ">=6" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -8062,6 +9015,15 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -8324,6 +9286,15 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/prompts": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", @@ -8537,6 +9508,18 @@ "node": ">=0.10.0" } }, + "node_modules/regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -8679,6 +9662,15 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -9435,6 +10427,65 @@ "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -10053,6 +11104,68 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "node_modules/table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz", + "integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/table/node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tar": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", @@ -10186,6 +11299,12 @@ "node": ">=8" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -10344,6 +11463,21 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -10421,9 +11555,9 @@ } }, "node_modules/typescript": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", - "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", + "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -10575,6 +11709,12 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, "node_modules/v8-to-istanbul": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", @@ -11448,6 +12588,46 @@ "minimist": "^1.2.0" } }, + "@eslint/eslintrc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz", + "integrity": "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } + }, "@intlify/core": { "version": "9.1.6", "resolved": "https://registry.npmjs.org/@intlify/core/-/core-9.1.6.tgz", @@ -12192,6 +13372,15 @@ "integrity": "sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw==", "dev": true }, + "@types/compression": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.0.tgz", + "integrity": "sha512-3LzWUM+3k3XdWOUk/RO+uSjv7YWOatYq2QADJntK1pjkk4DfVP0KrIEPDnXRJxAAGKe0VpIPRmlINLDuCedZWw==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, "@types/connect": { "version": "3.4.34", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", @@ -12272,6 +13461,12 @@ "@types/istanbul-lib-report": "*" } }, + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, "@types/micromatch": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.1.tgz", @@ -12375,6 +13570,141 @@ "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", "dev": true }, + "@typescript-eslint/eslint-plugin": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.25.0.tgz", + "integrity": "sha512-Qfs3dWkTMKkKwt78xp2O/KZQB8MPS1UQ5D3YW2s6LQWBE1074BE+Rym+b1pXZIX3M3fSvPUDaCvZLKV2ylVYYQ==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.25.0", + "@typescript-eslint/scope-manager": "4.25.0", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "lodash": "^4.17.15", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.25.0.tgz", + "integrity": "sha512-f0doRE76vq7NEEU0tw+ajv6CrmPelw5wLoaghEHkA2dNLFb3T/zJQqGPQ0OYt5XlZaS13MtnN+GTPCuUVg338w==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.25.0", + "@typescript-eslint/types": "4.25.0", + "@typescript-eslint/typescript-estree": "4.25.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.25.0.tgz", + "integrity": "sha512-OZFa1SKyEJpAhDx8FcbWyX+vLwh7OEtzoo2iQaeWwxucyfbi0mT4DijbOSsTgPKzGHr6GrF2V5p/CEpUH/VBxg==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "4.25.0", + "@typescript-eslint/types": "4.25.0", + "@typescript-eslint/typescript-estree": "4.25.0", + "debug": "^4.1.1" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.25.0.tgz", + "integrity": "sha512-2NElKxMb/0rya+NJG1U71BuNnp1TBd1JgzYsldsdA83h/20Tvnf/HrwhiSlNmuq6Vqa0EzidsvkTArwoq+tH6w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.25.0", + "@typescript-eslint/visitor-keys": "4.25.0" + } + }, + "@typescript-eslint/types": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.25.0.tgz", + "integrity": "sha512-+CNINNvl00OkW6wEsi32wU5MhHti2J25TJsJJqgQmJu3B3dYDBcmOxcE5w9cgoM13TrdE/5ND2HoEnBohasxRQ==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.25.0.tgz", + "integrity": "sha512-1B8U07TGNAFMxZbSpF6jqiDs1cVGO0izVkf18Q/SPcUAc9LhHxzvSowXDTvkHMWUVuPpagupaW63gB6ahTXVlg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.25.0", + "@typescript-eslint/visitor-keys": "4.25.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.25.0.tgz", + "integrity": "sha512-AmkqV9dDJVKP/TcZrbf6s6i1zYXt5Hl8qOLrRDTFfRNae4+LB8A4N3i+FLZPW85zIxRy39BgeWOfMS3HoH5ngg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.25.0", + "eslint-visitor-keys": "^2.0.0" + } + }, "@vitejs/plugin-vue": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.2.2.tgz", @@ -12674,6 +14004,13 @@ } } }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "requires": {} + }, "acorn-walk": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", @@ -12701,6 +14038,12 @@ "uri-js": "^4.2.2" } }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, "ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -12827,6 +14170,12 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", @@ -12854,6 +14203,12 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -13575,6 +14930,53 @@ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -13873,6 +15275,24 @@ "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "domexception": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", @@ -13943,6 +15363,15 @@ "once": "^1.4.0" } }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -13988,12 +15417,293 @@ "source-map": "~0.6.1" } }, + "eslint": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.27.0.tgz", + "integrity": "sha512-JZuR6La2ZF0UD384lcbnd0Cgg6QJjiCwhMD6eU4h/VGPcVGwawNNzKU41tgokGXnfjOOyI6QIffthhJTPzzuRA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.1", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "globals": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", + "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, "estraverse": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", @@ -14397,6 +16107,15 @@ "bser": "2.1.1" } }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -14461,6 +16180,22 @@ "path-exists": "^4.0.0" } }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -14546,6 +16281,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -14662,6 +16403,28 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, + "globby": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", + "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + } + } + }, "graceful-fs": { "version": "4.2.6", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", @@ -14863,6 +16626,12 @@ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, "image-size": { "version": "0.9.7", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.9.7.tgz", @@ -14871,6 +16640,24 @@ "queue": "6.0.2" } }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, "import-local": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", @@ -16578,6 +18365,12 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -16694,6 +18487,24 @@ "dev": true, "peer": true }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, "lru_map": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", @@ -17248,6 +19059,12 @@ "ee-first": "1.1.1" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -17315,6 +19132,15 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -17390,6 +19216,12 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -17582,6 +19414,12 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "prompts": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", @@ -17740,6 +19578,12 @@ "safe-regex": "^1.1.0" } }, + "regexpp": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", + "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "dev": true + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -17848,6 +19692,12 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -18447,6 +20297,49 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + } + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -18952,6 +20845,57 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz", + "integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + } + } + }, "tar": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", @@ -19053,6 +20997,12 @@ "minimatch": "^3.0.4" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -19174,6 +21124,15 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -19233,9 +21192,9 @@ } }, "typescript": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", - "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", + "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", "dev": true }, "union-value": { @@ -19352,6 +21311,12 @@ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, "v8-to-istanbul": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", diff --git a/package.json b/package.json index aef04d8..11aaf70 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,6 @@ "type": "module", "dependencies": { "better-sqlite3": "^7.4.0", - "body-parser": "^1.19.0", "exif": "^0.6.0", "express": "^4.17.1", "image-size": "^0.9.3", @@ -14,19 +13,24 @@ }, "devDependencies": { "@types/better-sqlite3": "^5.4.1", + "@types/compression": "^1.7.0", "@types/exif": "^0.6.2", "@types/express": "^4.17.11", "@types/multer": "^1.4.5", "@types/sharp": "^0.28.1", "@types/ws": "^7.4.4", + "@typescript-eslint/eslint-plugin": "^4.25.0", + "@typescript-eslint/parser": "^4.25.0", "@vitejs/plugin-vue": "^1.2.2", "@vuedx/typescript-plugin-vue": "^0.6.3", + "compression": "^1.7.4", + "eslint": "^7.27.0", "jest": "^26.6.3", "rollup": "^2.48.0", "rollup-plugin-typescript2": "^0.30.0", "rollup-plugin-vue": "^6.0.0-beta.10", "ts-node": "^9.1.1", - "typescript": "^4.2.4", + "typescript": "^4.3.2", "vite": "^2.3.2" }, "engines": { @@ -35,6 +39,7 @@ }, "scripts": { "rollup": "rollup", - "vite": "vite" + "vite": "vite", + "eslint": "eslint" } } diff --git a/rollup.server.config.js b/rollup.server.config.js index 117fee1..484815c 100644 --- a/rollup.server.config.js +++ b/rollup.server.config.js @@ -8,17 +8,18 @@ export default { format: 'es', }, external: [ - "express", - "multer", - "body-parser", - "v8", - "fs", - "ws", - "image-size", + "better-sqlite3", + "compression", "exif", + "express", + "fs", + "image-size", + "multer", + "path", "sharp", "url", - "path", + "v8", + "ws", ], plugins: [typescript()], }; diff --git a/scripts/fix_games_image_info.ts b/scripts/fix_games_image_info.ts new file mode 100644 index 0000000..49ac4ed --- /dev/null +++ b/scripts/fix_games_image_info.ts @@ -0,0 +1,90 @@ +import GameCommon from '../src/common/GameCommon' +import GameLog from '../src/server/GameLog' +import { Game } from '../src/common/Types' +import { logger } from '../src/common/Util' +import { DB_FILE, DB_PATCHES_DIR, UPLOAD_DIR } from '../src/server/Dirs' +import Db from '../src/server/Db' +import GameStorage from '../src/server/GameStorage' +import fs from 'fs' + +const log = logger('fix_games_image_info.ts') + +import Images from '../src/server/Images' + +console.log(DB_FILE) + +const db = new Db(DB_FILE, DB_PATCHES_DIR) +db.patch(true) + +// ;(async () => { +// let images = db.getMany('images') +// for (let image of images) { +// console.log(image.filename) +// let dim = await Images.getDimensions(`${UPLOAD_DIR}/${image.filename}`) +// console.log(await Images.getDimensions(`${UPLOAD_DIR}/${image.filename}`)) +// image.width = dim.w +// image.height = dim.h +// db.upsert('images', image, { id: image.id }) +// } +// })() + +function fixOne(gameId: string) { + let g = GameCommon.get(gameId) + if (!g) { + return + } + + if (!g.puzzle.info.image && g.puzzle.info.imageUrl) { + log.log('game id: ', gameId) + const parts = g.puzzle.info.imageUrl.split('/') + const fileName = parts[parts.length - 1] + const imageRow = db.get('images', {filename: fileName}) + if (!imageRow) { + return + } + + g.puzzle.info.image = Images.imageFromDb(db, imageRow.id) + + log.log(g.puzzle.info.image.title, imageRow.id) + + GameStorage.persistGameToDb(db, gameId) + } else if (g.puzzle.info.image?.id) { + const imageId = g.puzzle.info.image.id + + g.puzzle.info.image = Images.imageFromDb(db, imageId) + + log.log(g.puzzle.info.image.title, imageId) + + GameStorage.persistGameToDb(db, gameId) + } + + // fix log + const file = GameLog.filename(gameId, 0) + if (!fs.existsSync(file)) { + return + } + + const lines = fs.readFileSync(file, 'utf-8').split("\n") + const l = lines.filter(line => !!line).map(line => { + return JSON.parse(`[${line}]`) + }) + if (l && l[0] && !l[0][3].id) { + log.log(l[0][3]) + l[0][3] = g.puzzle.info.image + const newlines = l.map(ll => { + return JSON.stringify(ll).slice(1, -1) + }).join("\n") + "\n" + console.log(g.puzzle.info.image) + // process.exit(0) + fs.writeFileSync(file, newlines) + } +} + +function fix() { + GameStorage.loadGamesFromDisk() + GameCommon.getAllGames().forEach((game: Game) => { + fixOne(game.id) + }) +} + +fix() diff --git a/scripts/fix_image.ts b/scripts/fix_image.ts deleted file mode 100644 index 366ed1f..0000000 --- a/scripts/fix_image.ts +++ /dev/null @@ -1,23 +0,0 @@ -import GameCommon from '../src/common/GameCommon' -import { logger } from '../src/common/Util' -import GameStorage from '../src/server/GameStorage' - -const log = logger('fix_image.js') - -function fix(gameId) { - GameStorage.loadGame(gameId) - let changed = false - - let imgUrl = GameCommon.getImageUrl(gameId) - if (imgUrl.match(/^\/example-images\//)) { - log.log(`found bad imgUrl: ${imgUrl}`) - imgUrl = imgUrl.replace(/^\/example-images\//, '/uploads/') - GameCommon.setImageUrl(gameId, imgUrl) - changed = true - } - if (changed) { - GameStorage.persistGame(gameId) - } -} - -fix(process.argv[2]) diff --git a/scripts/fix_tiles.ts b/scripts/fix_tiles.ts index 6da6aef..a45b19b 100644 --- a/scripts/fix_tiles.ts +++ b/scripts/fix_tiles.ts @@ -1,33 +1,38 @@ import GameCommon from '../src/common/GameCommon' import { logger } from '../src/common/Util' +import Db from '../src/server/Db' +import { DB_FILE, DB_PATCHES_DIR } from '../src/server/Dirs' import GameStorage from '../src/server/GameStorage' const log = logger('fix_tiles.js') +const db = new Db(DB_FILE, DB_PATCHES_DIR) +db.patch(true) + function fix_tiles(gameId) { - GameStorage.loadGame(gameId) + GameStorage.loadGameFromDb(db, gameId) let changed = false - const tiles = GameCommon.getTilesSortedByZIndex(gameId) + const tiles = GameCommon.getPiecesSortedByZIndex(gameId) for (let tile of tiles) { if (tile.owner === -1) { - const p = GameCommon.getFinalTilePos(gameId, tile.idx) + const p = GameCommon.getFinalPiecePos(gameId, tile.idx) if (p.x === tile.pos.x && p.y === tile.pos.y) { // log.log('all good', tile.pos) } else { log.log('bad tile pos', tile.pos, 'should be: ', p) tile.pos = p - GameCommon.setTile(gameId, tile.idx, tile) + GameCommon.setPiece(gameId, tile.idx, tile) changed = true } } else if (tile.owner !== 0) { tile.owner = 0 log.log('unowning tile', tile.idx) - GameCommon.setTile(gameId, tile.idx, tile) + GameCommon.setPiece(gameId, tile.idx, tile) changed = true } } if (changed) { - GameStorage.persistGame(gameId) + GameStorage.persistGameToDb(db, gameId) } } diff --git a/scripts/import_game_logs.ts b/scripts/import_game_logs.ts deleted file mode 100644 index 8b88bb9..0000000 --- a/scripts/import_game_logs.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { DB_FILE, DB_PATCHES_DIR, DATA_DIR } from '../src/server/Dirs' -import Db from '../src/server/Db' -import fs from 'fs' -import { logger } from '../src/common/Util' - -const log = logger('import_game_logs.ts') -const db = new Db(DB_FILE, DB_PATCHES_DIR) -db.patch(true) - - -for (const file of fs.readdirSync(DATA_DIR)) { - const m = file.match(/^log_(.*)\.log$/) - if (!m) { - continue - } - - const gameId = m[1] - log.info(`Importing log for game ${file}`) - - const contents = fs.readFileSync(`${DATA_DIR}/${file}`, 'utf-8') - let t = 0 - let datas = [] - for (const line of contents.split("\n")) { - if (line === '') { - continue - } - let parsed - try { - parsed = JSON.parse(line) - } catch (e) { - log.error('bad game', e) - break - } - if (t === 0) { - t = parsed[4] - } else { - t += parsed[parsed.length - 1] - } - datas.push({ - game_id: gameId, - created: t / 1000, - entry: line, - }) - } - db.insertMany('game_log', datas) - log.info(`Done.`) -} diff --git a/scripts/import_games.ts b/scripts/import_games.ts new file mode 100644 index 0000000..f2e5cfa --- /dev/null +++ b/scripts/import_games.ts @@ -0,0 +1,27 @@ +import GameCommon from '../src/common/GameCommon' +import { Game } from '../src/common/Types' +import { logger } from '../src/common/Util' +import { DB_FILE, DB_PATCHES_DIR } from '../src/server/Dirs' +import Db from '../src/server/Db' +import GameStorage from '../src/server/GameStorage' + +const log = logger('import_games.ts') + +console.log(DB_FILE) + +const db = new Db(DB_FILE, DB_PATCHES_DIR) +db.patch(true) + +function run() { + GameStorage.loadGamesFromDisk() + GameCommon.getAllGames().forEach((game: Game) => { + if (!game.puzzle.info.image?.id) { + log.error(game.id + " has no image") + log.error(game.puzzle.info.image) + return + } + GameStorage.persistGameToDb(db, game.id) + }) +} + +run() diff --git a/scripts/import_image_sizes.ts b/scripts/import_image_sizes.ts new file mode 100644 index 0000000..9c9365c --- /dev/null +++ b/scripts/import_image_sizes.ts @@ -0,0 +1,18 @@ +import { DB_FILE, DB_PATCHES_DIR, UPLOAD_DIR } from '../src/server/Dirs' +import Db from '../src/server/Db' +import Images from '../src/server/Images' + +const db = new Db(DB_FILE, DB_PATCHES_DIR) +db.patch(true) + +;(async () => { + let images = db.getMany('images') + for (let image of images) { + console.log(image.filename) + let dim = await Images.getDimensions(`${UPLOAD_DIR}/${image.filename}`) + console.log(await Images.getDimensions(`${UPLOAD_DIR}/${image.filename}`)) + image.width = dim.w + image.height = dim.h + db.upsert('images', image, { id: image.id }) + } +})() diff --git a/scripts/lint b/scripts/lint new file mode 100755 index 0000000..055d373 --- /dev/null +++ b/scripts/lint @@ -0,0 +1,5 @@ +#!/bin/sh -e + +cd "$RUN_DIR" + +npm run eslint src diff --git a/scripts/rewrite_logs.ts b/scripts/rewrite_logs.ts deleted file mode 100644 index 0ac3c99..0000000 --- a/scripts/rewrite_logs.ts +++ /dev/null @@ -1,82 +0,0 @@ -import fs from 'fs' -import Protocol from '../src/common/Protocol' -import { logger } from '../src/common/Util' -import { DATA_DIR } from '../src/server/Dirs' - -const log = logger('rewrite_logs') - -const filename = (gameId) => `${DATA_DIR}/log_${gameId}.log` - -const rewrite = (gameId) => { - const file = filename(gameId) - log.log(file) - if (!fs.existsSync(file)) { - return [] - } - let playerIds = []; - let startTs = null - const lines = fs.readFileSync(file, 'utf-8').split("\n") - const linesNew = lines.filter(line => !!line).map((line) => { - const json = JSON.parse(line) - const m = { - createGame: Protocol.LOG_HEADER, - addPlayer: Protocol.LOG_ADD_PLAYER, - handleInput: Protocol.LOG_HANDLE_INPUT, - } - const action = json[0] - if (action in m) { - json[0] = m[action] - if (json[0] === Protocol.LOG_HANDLE_INPUT) { - const inputm = { - down: Protocol.INPUT_EV_MOUSE_DOWN, - up: Protocol.INPUT_EV_MOUSE_UP, - move: Protocol.INPUT_EV_MOUSE_MOVE, - zoomin: Protocol.INPUT_EV_ZOOM_IN, - zoomout: Protocol.INPUT_EV_ZOOM_OUT, - bg_color: Protocol.INPUT_EV_BG_COLOR, - player_color: Protocol.INPUT_EV_PLAYER_COLOR, - player_name: Protocol.INPUT_EV_PLAYER_NAME, - } - const inputa = json[2][0] - if (inputa in inputm) { - json[2][0] = inputm[inputa] - } else { - throw '[ invalid input log line: "' + line + '" ]' - } - } - } else { - throw '[ invalid general log line: "' + line + '" ]' - } - - if (json[0] === Protocol.LOG_ADD_PLAYER) { - if (playerIds.indexOf(json[1]) === -1) { - playerIds.push(json[1]) - } else { - json[0] = Protocol.LOG_UPDATE_PLAYER - json[1] = playerIds.indexOf(json[1]) - } - } - - if (json[0] === Protocol.LOG_HANDLE_INPUT) { - json[1] = playerIds.indexOf(json[1]) - if (json[1] === -1) { - throw '[ invalid player ... "' + line + '" ]' - } - } - - if (json[0] === Protocol.LOG_HEADER) { - startTs = json[json.length - 1] - json[4] = json[3] - json[3] = json[2] - json[2] = json[1] - json[1] = 1 - } else { - json[json.length - 1] = json[json.length - 1] - startTs - } - return JSON.stringify(json) - }) - - fs.writeFileSync(file, linesNew.join("\n") + "\n") -} - -rewrite(process.argv[2]) diff --git a/scripts/server b/scripts/server index e91a29c..4d1a1c9 100755 --- a/scripts/server +++ b/scripts/server @@ -1,4 +1,4 @@ #!/bin/sh # server for built files -nodemon --max-old-space-size=64 build/server/main.js -c config.json +nodemon --watch build --max-old-space-size=64 -e js build/server/main.js -c config.json diff --git a/scripts/split_logs.ts b/scripts/split_logs.ts new file mode 100644 index 0000000..5497096 --- /dev/null +++ b/scripts/split_logs.ts @@ -0,0 +1,73 @@ +import fs from 'fs' +import { logger } from '../src/common/Util' +import { DATA_DIR } from '../src/server/Dirs' +import { filename } from '../src/server/GameLog' + +const log = logger('rewrite_logs') + +interface IdxOld { + total: number + currentFile: string + perFile: number +} + +interface Idx { + gameId: string + total: number + lastTs: number + currentFile: string + perFile: number +} +const doit = (idxfile: string): void => { + const gameId: string = (idxfile.match(/^log_([a-z0-9]+)\.idx\.log$/) as any[])[1] + const idxOld: IdxOld = JSON.parse(fs.readFileSync(DATA_DIR + '/' + idxfile, 'utf-8')) + + let currentFile = filename(gameId, 0) + const idxNew: Idx = { + gameId: gameId, + total: 0, + lastTs: 0, + currentFile: currentFile, + perFile: idxOld.perFile + } + + let firstTs = 0 + while (fs.existsSync(currentFile)) { + idxNew.currentFile = currentFile + const log = fs.readFileSync(currentFile, 'utf-8').split("\n") + const newLines = [] + const lines = log.filter(line => !!line).map(line => { + return JSON.parse(line) + }) + for (const l of lines) { + if (idxNew.total === 0) { + firstTs = l[4] + idxNew.lastTs = l[4] + newLines.push(JSON.stringify(l).slice(1, -1)) + } else { + const ts = firstTs + l[l.length - 1] + const diff = ts - idxNew.lastTs + idxNew.lastTs = ts + const newL = l.slice(0, -1) + newL.push(diff) + newLines.push(JSON.stringify(newL).slice(1, -1)) + } + idxNew.total++ + } + fs.writeFileSync(idxNew.currentFile, newLines.join("\n") + "\n") + currentFile = filename(gameId, idxNew.total) + } + + fs.writeFileSync(DATA_DIR + '/' + idxfile, JSON.stringify(idxNew)) + console.log('done: ' + gameId) +} + +let indexfiles = fs.readdirSync(DATA_DIR) + .filter(f => f.toLowerCase().match(/^log_[a-z0-9]+\.idx\.log$/)) + + +;(async () => { + for (const file of indexfiles) { + await doit(file) + } +})() diff --git a/scripts/tests b/scripts/tests index a047361..ac15ff6 100755 --- a/scripts/tests +++ b/scripts/tests @@ -1,3 +1,3 @@ -#!/bin/sh +#!/bin/sh -e node --experimental-vm-modules node_modules/.bin/jest diff --git a/scripts/ts b/scripts/ts index 176a61c..8c28ec5 100755 --- a/scripts/ts +++ b/scripts/ts @@ -1,3 +1,3 @@ #!/bin/sh -e -node --experimental-specifier-resolution=node --loader ts-node/esm $@ +node --max-old-space-size=256 --experimental-specifier-resolution=node --loader ts-node/esm $@ diff --git a/src/common/GameCommon.ts b/src/common/GameCommon.ts index 8d48b70..8b7fde7 100644 --- a/src/common/GameCommon.ts +++ b/src/common/GameCommon.ts @@ -2,139 +2,35 @@ import Geometry, { Point, Rect } from './Geometry' import Protocol from './Protocol' import { Rng } from './Rng' import Time from './Time' +import { + Change, + EncodedPiece, + EvtInfo, + Game, + Input, + Piece, + PieceChange, + Player, + PlayerChange, + Puzzle, + PuzzleData, + PuzzleDataChange, + ScoreMode, + SnapMode, + Timestamp +} from './Types' import Util from './Util' -export type Timestamp = number -export type EncodedPlayer = Array -export type EncodedPiece = Array -export type EncodedPieceShape = number - -export interface Tag { - id: number - slug: string - title: string -} - -interface GameRng { - obj: Rng - type?: string -} - -interface Game { - id: string - players: Array - puzzle: Puzzle - evtInfos: Record - scoreMode?: ScoreMode - rng: GameRng -} - -export interface Image { - id: number - filename: string - file: string - url: string - title: string - tags: Array - created: number -} - -export interface GameSettings { - tiles: number - image: Image - scoreMode: ScoreMode -} - -export interface Puzzle { - tiles: Array - data: PuzzleData - info: PuzzleInfo -} - -interface PuzzleData { - started: number - finished: number - maxGroup: number - maxZ: number -} - -interface PuzzleTable { - width: number - height: number -} - -enum PieceEdge { - Flat = 0, - Out = 1, - In = -1, -} -export interface PieceShape { - top: PieceEdge - bottom: PieceEdge - left: PieceEdge - right: PieceEdge -} - -export interface Piece { - owner: string|number - idx: number - pos: Point - z: number - group: number -} - -export interface PuzzleInfo { - table: PuzzleTable - targetTiles: number, - imageUrl: string - - width: number - height: number - tileSize: number - tileDrawSize: number - tileMarginWidth: number - tileDrawOffset: number - snapDistance: number - - tiles: number - tilesX: number - tilesY: number - - shapes: Array -} - -export interface Player { - id: string - x: number - y: number - d: 0|1 - name: string|null - color: string|null - bgcolor: string|null - points: number - ts: number -} - -interface EvtInfo { - _last_mouse: Point|null - _last_mouse_down: Point|null -} - -export enum ScoreMode { - FINAL = 0, - ANY = 1, -} - const IDLE_TIMEOUT_SEC = 30 // Map const GAMES: Record = {} -function exists(gameId: string) { +function exists(gameId: string): boolean { return (!!GAMES[gameId]) || false } -function __createPlayerObject(id: string, ts: number): Player { +function __createPlayerObject(id: string, ts: Timestamp): Player { return { id: id, x: 0, @@ -154,7 +50,7 @@ function setGame(gameId: string, game: Game): void { function getPlayerIndexById(gameId: string, playerId: string): number { let i = 0; - for (let player of GAMES[gameId].players) { + for (const player of GAMES[gameId].players) { if (Util.decodePlayer(player).id === playerId) { return i } @@ -170,8 +66,11 @@ function getPlayerIdByIndex(gameId: string, playerIndex: number): string|null { return null } -function getPlayer(gameId: string, playerId: string): Player { +function getPlayer(gameId: string, playerId: string): Player|null { const idx = getPlayerIndexById(gameId, playerId) + if (idx === -1) { + return null + } return Util.decodePlayer(GAMES[gameId].players[idx]) } @@ -188,8 +87,8 @@ function setPlayer( } } -function setTile(gameId: string, tileIdx: number, tile: Piece): void { - GAMES[gameId].puzzle.tiles[tileIdx] = Util.encodeTile(tile) +function setPiece(gameId: string, pieceIdx: number, piece: Piece): void { + GAMES[gameId].puzzle.tiles[pieceIdx] = Util.encodePiece(piece) } function setPuzzleData(gameId: string, data: PuzzleData): void { @@ -211,7 +110,7 @@ function getIdlePlayers(gameId: string, ts: number): Array { return getAllPlayers(gameId).filter((p: Player) => p.ts < minTs && p.points > 0) } -function addPlayer(gameId: string, playerId: string, ts: number): void { +function addPlayer(gameId: string, playerId: string, ts: Timestamp): void { if (!playerExists(gameId, playerId)) { setPlayer(gameId, playerId, __createPlayerObject(playerId, ts)) } else { @@ -239,12 +138,16 @@ function setEvtInfo( function getAllGames(): Array { return Object.values(GAMES).sort((a: Game, b: Game) => { + const finished = isFinished(a.id) // when both have same finished state, sort by started - if (isFinished(a.id) === isFinished(b.id)) { + if (finished === isFinished(b.id)) { + if (finished) { + return b.puzzle.data.finished - a.puzzle.data.finished + } return b.puzzle.data.started - a.puzzle.data.started } // otherwise, sort: unfinished, finished - return isFinished(a.id) ? 1 : -1 + return finished ? 1 : -1 }) } @@ -254,84 +157,107 @@ function getAllPlayers(gameId: string): Array { : [] } -function get(gameId: string) { - return GAMES[gameId] +function get(gameId: string): Game|null { + return GAMES[gameId] || null } -function getTileCount(gameId: string): number { +function getPieceCount(gameId: string): number { return GAMES[gameId].puzzle.tiles.length } function getImageUrl(gameId: string): string { - return GAMES[gameId].puzzle.info.imageUrl -} - -function setImageUrl(gameId: string, imageUrl: string): void { - GAMES[gameId].puzzle.info.imageUrl = imageUrl + const imageUrl = GAMES[gameId].puzzle.info.image?.url + || GAMES[gameId].puzzle.info.imageUrl + if (!imageUrl) { + throw new Error('[2021-07-11] no image url set') + } + return imageUrl } function getScoreMode(gameId: string): ScoreMode { - return GAMES[gameId].scoreMode || ScoreMode.FINAL + return GAMES[gameId].scoreMode +} + +function getSnapMode(gameId: string): SnapMode { + return GAMES[gameId].snapMode } function isFinished(gameId: string): boolean { - return getFinishedTileCount(gameId) === getTileCount(gameId) + return getFinishedPiecesCount(gameId) === getPieceCount(gameId) } -function getFinishedTileCount(gameId: string): number { +function getFinishedPiecesCount(gameId: string): number { let count = 0 - for (let t of GAMES[gameId].puzzle.tiles) { - if (Util.decodeTile(t).owner === -1) { + for (const t of GAMES[gameId].puzzle.tiles) { + if (Util.decodePiece(t).owner === -1) { count++ } } return count } -function getTilesSortedByZIndex(gameId: string): Piece[] { - const tiles = GAMES[gameId].puzzle.tiles.map(Util.decodeTile) - return tiles.sort((t1, t2) => t1.z - t2.z) +function getPiecesSortedByZIndex(gameId: string): Piece[] { + const pieces = GAMES[gameId].puzzle.tiles.map(Util.decodePiece) + return pieces.sort((t1, t2) => t1.z - t2.z) } function changePlayer( gameId: string, playerId: string, - change: any + change: PlayerChange ): void { const player = getPlayer(gameId, playerId) - for (let k of Object.keys(change)) { + if (player === null) { + return + } + + for (const k of Object.keys(change)) { // @ts-ignore player[k] = change[k] } setPlayer(gameId, playerId, player) } -function changeData(gameId: string, change: any): void { - for (let k of Object.keys(change)) { +function changeData(gameId: string, change: PuzzleDataChange): void { + for (const k of Object.keys(change)) { // @ts-ignore GAMES[gameId].puzzle.data[k] = change[k] } } -function changeTile(gameId: string, tileIdx: number, change: any): void { - for (let k of Object.keys(change)) { - const tile = Util.decodeTile(GAMES[gameId].puzzle.tiles[tileIdx]) +function changePiece( + gameId: string, + pieceIdx: number, + change: PieceChange +): void { + for (const k of Object.keys(change)) { + const piece = Util.decodePiece(GAMES[gameId].puzzle.tiles[pieceIdx]) // @ts-ignore - tile[k] = change[k] - GAMES[gameId].puzzle.tiles[tileIdx] = Util.encodeTile(tile) + piece[k] = change[k] + GAMES[gameId].puzzle.tiles[pieceIdx] = Util.encodePiece(piece) } } -const getTile = (gameId: string, tileIdx: number): Piece => { - return Util.decodeTile(GAMES[gameId].puzzle.tiles[tileIdx]) +const getPiece = (gameId: string, pieceIdx: number): Piece => { + return Util.decodePiece(GAMES[gameId].puzzle.tiles[pieceIdx]) } -const getTileGroup = (gameId: string, tileIdx: number): number => { - const tile = getTile(gameId, tileIdx) +const getPieceGroup = (gameId: string, tileIdx: number): number => { + const tile = getPiece(gameId, tileIdx) return tile.group } -const getFinalTilePos = (gameId: string, tileIdx: number): Point => { +const isCornerPiece = (gameId: string, tileIdx: number): boolean => { + const info = GAMES[gameId].puzzle.info + return ( + tileIdx === 0 // top left corner + || tileIdx === (info.tilesX - 1) // top right corner + || tileIdx === (info.tiles - info.tilesX) // bottom left corner + || tileIdx === (info.tiles - 1) // bottom right corner + ) +} + +const getFinalPiecePos = (gameId: string, tileIdx: number): Point => { const info = GAMES[gameId].puzzle.info const boardPos = { x: (info.table.width - info.width) / 2, @@ -341,8 +267,8 @@ const getFinalTilePos = (gameId: string, tileIdx: number): Point => { return Geometry.pointAdd(boardPos, srcPos) } -const getTilePos = (gameId: string, tileIdx: number): Point => { - const tile = getTile(gameId, tileIdx) +const getPiecePos = (gameId: string, tileIdx: number): Point => { + const tile = getPiece(gameId, tileIdx) return tile.pos } @@ -361,9 +287,9 @@ const getBounds = (gameId: string): Rect => { } } -const getTileBounds = (gameId: string, tileIdx: number): Rect => { - const s = getTileSize(gameId) - const tile = getTile(gameId, tileIdx) +const getPieceBounds = (gameId: string, tileIdx: number): Rect => { + const s = getPieceSize(gameId) + const tile = getPiece(gameId, tileIdx) return { x: tile.pos.x, y: tile.pos.y, @@ -372,14 +298,13 @@ const getTileBounds = (gameId: string, tileIdx: number): Rect => { } } -const getTileZIndex = (gameId: string, tileIdx: number): number => { - const tile = getTile(gameId, tileIdx) - return tile.z +const getPieceZIndex = (gameId: string, pieceIdx: number): number => { + return getPiece(gameId, pieceIdx).z } -const getFirstOwnedTileIdx = (gameId: string, playerId: string): number => { - for (let t of GAMES[gameId].puzzle.tiles) { - const tile = Util.decodeTile(t) +const getFirstOwnedPieceIdx = (gameId: string, playerId: string): number => { + for (const t of GAMES[gameId].puzzle.tiles) { + const tile = Util.decodePiece(t) if (tile.owner === playerId) { return tile.idx } @@ -387,20 +312,23 @@ const getFirstOwnedTileIdx = (gameId: string, playerId: string): number => { return -1 } -const getFirstOwnedTile = (gameId: string, playerId: string): EncodedPiece|null => { - const idx = getFirstOwnedTileIdx(gameId, playerId) +const getFirstOwnedPiece = ( + gameId: string, + playerId: string +): EncodedPiece|null => { + const idx = getFirstOwnedPieceIdx(gameId, playerId) return idx < 0 ? null : GAMES[gameId].puzzle.tiles[idx] } -const getTileDrawOffset = (gameId: string): number => { +const getPieceDrawOffset = (gameId: string): number => { return GAMES[gameId].puzzle.info.tileDrawOffset } -const getTileDrawSize = (gameId: string): number => { +const getPieceDrawSize = (gameId: string): number => { return GAMES[gameId].puzzle.info.tileDrawSize } -const getTileSize = (gameId: string): number => { +const getPieceSize = (gameId: string): number => { return GAMES[gameId].puzzle.info.tileSize } @@ -420,12 +348,12 @@ const getMaxZIndex = (gameId: string): number => { return GAMES[gameId].puzzle.data.maxZ } -const getMaxZIndexByTileIdxs = (gameId: string, tileIdxs: Array): number => { +const getMaxZIndexByPieceIdxs = (gameId: string, pieceIdxs: Array): number => { let maxZ = 0 - for (let tileIdx of tileIdxs) { - let tileZIndex = getTileZIndex(gameId, tileIdx) - if (tileZIndex > maxZ) { - maxZ = tileZIndex + for (const pieceIdx of pieceIdxs) { + const curZ = getPieceZIndex(gameId, pieceIdx) + if (curZ > maxZ) { + maxZ = curZ } } return maxZ @@ -434,7 +362,7 @@ const getMaxZIndexByTileIdxs = (gameId: string, tileIdxs: Array): number function srcPosByTileIdx(gameId: string, tileIdx: number): Point { const info = GAMES[gameId].puzzle.info - const c = Util.coordByTileIdx(info, tileIdx) + const c = Util.coordByPieceIdx(info, tileIdx) const cx = c.x * info.tileSize const cy = c.y * info.tileSize @@ -444,7 +372,7 @@ function srcPosByTileIdx(gameId: string, tileIdx: number): Point { function getSurroundingTilesByIdx(gameId: string, tileIdx: number) { const info = GAMES[gameId].puzzle.info - const c = Util.coordByTileIdx(info, tileIdx) + const c = Util.coordByPieceIdx(info, tileIdx) return [ // top @@ -458,109 +386,117 @@ function getSurroundingTilesByIdx(gameId: string, tileIdx: number) { ] } -const setTilesZIndex = (gameId: string, tileIdxs: Array, zIndex: number): void => { - for (let tilesIdx of tileIdxs) { - changeTile(gameId, tilesIdx, { z: zIndex }) +const setPiecesZIndex = (gameId: string, tileIdxs: Array, zIndex: number): void => { + for (const tilesIdx of tileIdxs) { + changePiece(gameId, tilesIdx, { z: zIndex }) } } const moveTileDiff = (gameId: string, tileIdx: number, diff: Point): void => { - const oldPos = getTilePos(gameId, tileIdx) + const oldPos = getPiecePos(gameId, tileIdx) const pos = Geometry.pointAdd(oldPos, diff) - changeTile(gameId, tileIdx, { pos }) + changePiece(gameId, tileIdx, { pos }) } -const moveTilesDiff = ( +const movePiecesDiff = ( gameId: string, - tileIdxs: Array, + pieceIdxs: Array, diff: Point ): void => { - const tileDrawSize = getTileDrawSize(gameId) + const drawSize = getPieceDrawSize(gameId) const bounds = getBounds(gameId) const cappedDiff = diff - for (let tileIdx of tileIdxs) { - const t = getTile(gameId, tileIdx) + for (const pieceIdx of pieceIdxs) { + const t = getPiece(gameId, pieceIdx) if (t.pos.x + diff.x < bounds.x) { cappedDiff.x = Math.max(bounds.x - t.pos.x, cappedDiff.x) - } else if (t.pos.x + tileDrawSize + diff.x > bounds.x + bounds.w) { - cappedDiff.x = Math.min(bounds.x + bounds.w - t.pos.x + tileDrawSize, cappedDiff.x) + } else if (t.pos.x + drawSize + diff.x > bounds.x + bounds.w) { + cappedDiff.x = Math.min(bounds.x + bounds.w - t.pos.x + drawSize, cappedDiff.x) } if (t.pos.y + diff.y < bounds.y) { cappedDiff.y = Math.max(bounds.y - t.pos.y, cappedDiff.y) - } else if (t.pos.y + tileDrawSize + diff.y > bounds.y + bounds.h) { - cappedDiff.y = Math.min(bounds.y + bounds.h - t.pos.y + tileDrawSize, cappedDiff.y) + } else if (t.pos.y + drawSize + diff.y > bounds.y + bounds.h) { + cappedDiff.y = Math.min(bounds.y + bounds.h - t.pos.y + drawSize, cappedDiff.y) } } - for (let tileIdx of tileIdxs) { - moveTileDiff(gameId, tileIdx, cappedDiff) + for (const pieceIdx of pieceIdxs) { + moveTileDiff(gameId, pieceIdx, cappedDiff) } } -const finishTiles = (gameId: string, tileIdxs: Array): void => { - for (let tileIdx of tileIdxs) { - changeTile(gameId, tileIdx, { owner: -1, z: 1 }) +const isFinishedPiece = (gameId: string, pieceIdx: number): boolean => { + return getPieceOwner(gameId, pieceIdx) === -1 +} + +const getPieceOwner = (gameId: string, pieceIdx: number): string|number => { + return getPiece(gameId, pieceIdx).owner +} + +const finishPieces = (gameId: string, pieceIdxs: Array): void => { + for (const pieceIdx of pieceIdxs) { + changePiece(gameId, pieceIdx, { owner: -1, z: 1 }) } } const setTilesOwner = ( gameId: string, - tileIdxs: Array, + pieceIdxs: Array, owner: string|number ): void => { - for (let tileIdx of tileIdxs) { - changeTile(gameId, tileIdx, { owner }) + for (const pieceIdx of pieceIdxs) { + changePiece(gameId, pieceIdx, { owner }) } } // get all grouped tiles for a tile -function getGroupedTileIdxs(gameId: string, tileIdx: number): number[] { - const tiles = GAMES[gameId].puzzle.tiles - const tile = Util.decodeTile(tiles[tileIdx]) +function getGroupedPieceIdxs(gameId: string, pieceIdx: number): number[] { + const pieces = GAMES[gameId].puzzle.tiles + const piece = Util.decodePiece(pieces[pieceIdx]) const grouped = [] - if (tile.group) { - for (let other of tiles) { - const otherTile = Util.decodeTile(other) - if (otherTile.group === tile.group) { - grouped.push(otherTile.idx) + if (piece.group) { + for (const other of pieces) { + const otherPiece = Util.decodePiece(other) + if (otherPiece.group === piece.group) { + grouped.push(otherPiece.idx) } } } else { - grouped.push(tile.idx) + grouped.push(piece.idx) } return grouped } // Returns the index of the puzzle tile with the highest z index // that is not finished yet and that matches the position -const freeTileIdxByPos = (gameId: string, pos: Point): number => { - let info = GAMES[gameId].puzzle.info - let tiles = GAMES[gameId].puzzle.tiles +const freePieceIdxByPos = (gameId: string, pos: Point): number => { + const info = GAMES[gameId].puzzle.info + const pieces = GAMES[gameId].puzzle.tiles let maxZ = -1 - let tileIdx = -1 - for (let idx = 0; idx < tiles.length; idx++) { - const tile = Util.decodeTile(tiles[idx]) - if (tile.owner !== 0) { + let pieceIdx = -1 + for (let idx = 0; idx < pieces.length; idx++) { + const piece = Util.decodePiece(pieces[idx]) + if (piece.owner !== 0) { continue } const collisionRect: Rect = { - x: tile.pos.x, - y: tile.pos.y, + x: piece.pos.x, + y: piece.pos.y, w: info.tileSize, h: info.tileSize, } if (Geometry.pointInBounds(pos, collisionRect)) { - if (maxZ === -1 || tile.z > maxZ) { - maxZ = tile.z - tileIdx = idx + if (maxZ === -1 || piece.z > maxZ) { + maxZ = piece.z + pieceIdx = idx } } } - return tileIdx + return pieceIdx } const getPlayerBgColor = (gameId: string, playerId: string): string|null => { @@ -589,8 +525,8 @@ const areGrouped = ( tileIdx1: number, tileIdx2: number ): boolean => { - const g1 = getTileGroup(gameId, tileIdx1) - const g2 = getTileGroup(gameId, tileIdx2) + const g1 = getPieceGroup(gameId, tileIdx1) + const g2 = getPieceGroup(gameId, tileIdx2) return !!(g1 && g1 === g2) } @@ -621,47 +557,52 @@ const getPuzzleHeight = (gameId: string): number => { function handleInput( gameId: string, playerId: string, - input: any, - ts: number -): Array> { + input: Input, + ts: Timestamp, + onSnap?: (playerId: string) => void +): Array { const puzzle = GAMES[gameId].puzzle const evtInfo = getEvtInfo(gameId, playerId) - const changes = [] as Array> + const changes: Array = [] const _dataChange = (): void => { changes.push([Protocol.CHANGE_DATA, puzzle.data]) } - const _tileChange = (tileIdx: number): void => { + const _pieceChange = (pieceIdx: number): void => { changes.push([ Protocol.CHANGE_TILE, - Util.encodeTile(getTile(gameId, tileIdx)), + Util.encodePiece(getPiece(gameId, pieceIdx)), ]) } - const _tileChanges = (tileIdxs: Array): void => { - for (const tileIdx of tileIdxs) { - _tileChange(tileIdx) + const _pieceChanges = (pieceIdxs: Array): void => { + for (const pieceIdx of pieceIdxs) { + _pieceChange(pieceIdx) } } const _playerChange = (): void => { + const player = getPlayer(gameId, playerId) + if (!player) { + return + } changes.push([ Protocol.CHANGE_PLAYER, - Util.encodePlayer(getPlayer(gameId, playerId)), + Util.encodePlayer(player), ]) } // put both tiles (and their grouped tiles) in the same group const groupTiles = ( gameId: string, - tileIdx1: number, - tileIdx2: number + pieceIdx1: number, + pieceIdx2: number ): void => { - const tiles = GAMES[gameId].puzzle.tiles - const group1 = getTileGroup(gameId, tileIdx1) - const group2 = getTileGroup(gameId, tileIdx2) + const pieces = GAMES[gameId].puzzle.tiles + const group1 = getPieceGroup(gameId, pieceIdx1) + const group2 = getPieceGroup(gameId, pieceIdx2) let group const searchGroups = [] @@ -682,18 +623,18 @@ function handleInput( group = getMaxGroup(gameId) } - changeTile(gameId, tileIdx1, { group }) - _tileChange(tileIdx1) - changeTile(gameId, tileIdx2, { group }) - _tileChange(tileIdx2) + changePiece(gameId, pieceIdx1, { group }) + _pieceChange(pieceIdx1) + changePiece(gameId, pieceIdx2, { group }) + _pieceChange(pieceIdx2) // TODO: strange if (searchGroups.length > 0) { - for (const t of tiles) { - const tile = Util.decodeTile(t) - if (searchGroups.includes(tile.group)) { - changeTile(gameId, tile.idx, { group }) - _tileChange(tile.idx) + for (const p of pieces) { + const piece = Util.decodePiece(p) + if (searchGroups.includes(piece.group)) { + changePiece(gameId, piece.idx, { group }) + _pieceChange(piece.idx) } } } @@ -712,6 +653,16 @@ function handleInput( const name = `${input[1]}`.substr(0, 16) changePlayer(gameId, playerId, { name, ts }) _playerChange() + } else if (type === Protocol.INPUT_EV_MOVE) { + const w = input[1] + const h = input[2] + const player = getPlayer(gameId, playerId) + if (player) { + const x = player.x - w + const y = player.y - h + changePlayer(gameId, playerId, { ts, x, y }) + _playerChange() + } } else if (type === Protocol.INPUT_EV_MOUSE_DOWN) { const x = input[1] const y = input[2] @@ -721,15 +672,15 @@ function handleInput( _playerChange() evtInfo._last_mouse_down = pos - const tileIdxAtPos = freeTileIdxByPos(gameId, pos) + const tileIdxAtPos = freePieceIdxByPos(gameId, pos) if (tileIdxAtPos >= 0) { - let maxZ = getMaxZIndex(gameId) + 1 + const maxZ = getMaxZIndex(gameId) + 1 changeData(gameId, { maxZ }) _dataChange() - const tileIdxs = getGroupedTileIdxs(gameId, tileIdxAtPos) - setTilesZIndex(gameId, tileIdxs, getMaxZIndex(gameId)) + const tileIdxs = getGroupedPieceIdxs(gameId, tileIdxAtPos) + setPiecesZIndex(gameId, tileIdxs, getMaxZIndex(gameId)) setTilesOwner(gameId, tileIdxs, playerId) - _tileChanges(tileIdxs) + _pieceChanges(tileIdxs) } evtInfo._last_mouse = pos @@ -743,19 +694,19 @@ function handleInput( changePlayer(gameId, playerId, {x, y, ts}) _playerChange() } else { - let tileIdx = getFirstOwnedTileIdx(gameId, playerId) - if (tileIdx >= 0) { + const pieceIdx = getFirstOwnedPieceIdx(gameId, playerId) + if (pieceIdx >= 0) { // player is moving a tile (and hand) changePlayer(gameId, playerId, {x, y, ts}) _playerChange() // check if pos is on the tile, otherwise dont move // (mouse could be out of table, but tile stays on it) - const tileIdxs = getGroupedTileIdxs(gameId, tileIdx) + const pieceIdxs = getGroupedPieceIdxs(gameId, pieceIdx) let anyOk = Geometry.pointInBounds(pos, getBounds(gameId)) && Geometry.pointInBounds(evtInfo._last_mouse_down, getBounds(gameId)) - for (let idx of tileIdxs) { - const bounds = getTileBounds(gameId, idx) + for (const idx of pieceIdxs) { + const bounds = getPieceBounds(gameId, idx) if (Geometry.pointInBounds(pos, bounds)) { anyOk = true break @@ -766,9 +717,9 @@ function handleInput( const diffY = y - evtInfo._last_mouse_down.y const diff = { x: diffX, y: diffY } - moveTilesDiff(gameId, tileIdxs, diff) + movePiecesDiff(gameId, pieceIdxs, diff) - _tileChanges(tileIdxs) + _pieceChanges(pieceIdxs) } } else { // player is just moving map, so no change in position! @@ -788,26 +739,44 @@ function handleInput( evtInfo._last_mouse_down = null - let tileIdx = getFirstOwnedTileIdx(gameId, playerId) - if (tileIdx >= 0) { + const pieceIdx = getFirstOwnedPieceIdx(gameId, playerId) + if (pieceIdx >= 0) { // drop the tile(s) - let tileIdxs = getGroupedTileIdxs(gameId, tileIdx) - setTilesOwner(gameId, tileIdxs, 0) - _tileChanges(tileIdxs) + const pieceIdxs = getGroupedPieceIdxs(gameId, pieceIdx) + setTilesOwner(gameId, pieceIdxs, 0) + _pieceChanges(pieceIdxs) // Check if the tile was dropped near the final location - let tilePos = getTilePos(gameId, tileIdx) - let finalPos = getFinalTilePos(gameId, tileIdx) - if (Geometry.pointDistance(finalPos, tilePos) < puzzle.info.snapDistance) { - let diff = Geometry.pointSub(finalPos, tilePos) + const tilePos = getPiecePos(gameId, pieceIdx) + const finalPos = getFinalPiecePos(gameId, pieceIdx) + + let canSnapToFinal = false + if (getSnapMode(gameId) === SnapMode.REAL) { + // only can snap to final if any of the grouped pieces are + // corner pieces + for (const pieceIdxTmp of pieceIdxs) { + if (isCornerPiece(gameId, pieceIdxTmp)) { + canSnapToFinal = true + break + } + } + } else { + canSnapToFinal = true + } + + if ( + canSnapToFinal + && Geometry.pointDistance(finalPos, tilePos) < puzzle.info.snapDistance + ) { + const diff = Geometry.pointSub(finalPos, tilePos) // Snap the tile to the final destination - moveTilesDiff(gameId, tileIdxs, diff) - finishTiles(gameId, tileIdxs) - _tileChanges(tileIdxs) + movePiecesDiff(gameId, pieceIdxs, diff) + finishPieces(gameId, pieceIdxs) + _pieceChanges(pieceIdxs) let points = getPlayerPoints(gameId, playerId) if (getScoreMode(gameId) === ScoreMode.FINAL) { - points += tileIdxs.length + points += pieceIdxs.length } else if (getScoreMode(gameId) === ScoreMode.ANY) { points += 1 } else { @@ -818,10 +787,13 @@ function handleInput( _playerChange() // check if the puzzle is finished - if (getFinishedTileCount(gameId) === getTileCount(gameId)) { + if (getFinishedPiecesCount(gameId) === getPieceCount(gameId)) { changeData(gameId, { finished: ts }) _dataChange() } + if (onSnap) { + onSnap(playerId) + } } else { // Snap to other tiles const check = ( @@ -830,40 +802,44 @@ function handleInput( otherTileIdx: number, off: Array ): boolean => { - let info = GAMES[gameId].puzzle.info + const info = GAMES[gameId].puzzle.info if (otherTileIdx < 0) { return false } if (areGrouped(gameId, tileIdx, otherTileIdx)) { return false } - const tilePos = getTilePos(gameId, tileIdx) + const tilePos = getPiecePos(gameId, tileIdx) const dstPos = Geometry.pointAdd( - getTilePos(gameId, otherTileIdx), + getPiecePos(gameId, otherTileIdx), {x: off[0] * info.tileSize, y: off[1] * info.tileSize} ) if (Geometry.pointDistance(tilePos, dstPos) < info.snapDistance) { - let diff = Geometry.pointSub(dstPos, tilePos) - let tileIdxs = getGroupedTileIdxs(gameId, tileIdx) - moveTilesDiff(gameId, tileIdxs, diff) + const diff = Geometry.pointSub(dstPos, tilePos) + let pieceIdxs = getGroupedPieceIdxs(gameId, tileIdx) + movePiecesDiff(gameId, pieceIdxs, diff) groupTiles(gameId, tileIdx, otherTileIdx) - tileIdxs = getGroupedTileIdxs(gameId, tileIdx) - const zIndex = getMaxZIndexByTileIdxs(gameId, tileIdxs) - setTilesZIndex(gameId, tileIdxs, zIndex) - _tileChanges(tileIdxs) + pieceIdxs = getGroupedPieceIdxs(gameId, tileIdx) + if (isFinishedPiece(gameId, otherTileIdx)) { + finishPieces(gameId, pieceIdxs) + } else { + const zIndex = getMaxZIndexByPieceIdxs(gameId, pieceIdxs) + setPiecesZIndex(gameId, pieceIdxs, zIndex) + } + _pieceChanges(pieceIdxs) return true } return false } let snapped = false - for (let tileIdxTmp of getGroupedTileIdxs(gameId, tileIdx)) { - let othersIdxs = getSurroundingTilesByIdx(gameId, tileIdxTmp) + for (const pieceIdxTmp of getGroupedPieceIdxs(gameId, pieceIdx)) { + const othersIdxs = getSurroundingTilesByIdx(gameId, pieceIdxTmp) if ( - check(gameId, tileIdxTmp, othersIdxs[0], [0, 1]) // top - || check(gameId, tileIdxTmp, othersIdxs[1], [-1, 0]) // right - || check(gameId, tileIdxTmp, othersIdxs[2], [0, -1]) // bottom - || check(gameId, tileIdxTmp, othersIdxs[3], [1, 0]) // left + check(gameId, pieceIdxTmp, othersIdxs[0], [0, 1]) // top + || check(gameId, pieceIdxTmp, othersIdxs[1], [-1, 0]) // right + || check(gameId, pieceIdxTmp, othersIdxs[2], [0, -1]) // bottom + || check(gameId, pieceIdxTmp, othersIdxs[3], [1, 0]) // left ) { snapped = true break @@ -877,6 +853,16 @@ function handleInput( changePlayer(gameId, playerId, { d, ts }) _playerChange() } + + if (snapped && getSnapMode(gameId) === SnapMode.REAL) { + if (getFinishedPiecesCount(gameId) === getPieceCount(gameId)) { + changeData(gameId, { finished: ts }) + _dataChange() + } + } + if (snapped && onSnap) { + onSnap(playerId) + } } } else { changePlayer(gameId, playerId, { d, ts }) @@ -905,17 +891,15 @@ function handleInput( } export default { - __createPlayerObject, setGame, exists, playerExists, getActivePlayers, getIdlePlayers, addPlayer, - getFinishedTileCount, - getTileCount, + getFinishedPiecesCount, + getPieceCount, getImageUrl, - setImageUrl, get, getAllGames, getPlayerBgColor, @@ -925,7 +909,7 @@ export default { getPlayerIdByIndex, changePlayer, setPlayer, - setTile, + setPiece, setPuzzleData, getTableWidth, getTableHeight, @@ -933,11 +917,11 @@ export default { getRng, getPuzzleWidth, getPuzzleHeight, - getTilesSortedByZIndex, - getFirstOwnedTile, - getTileDrawOffset, - getTileDrawSize, - getFinalTilePos, + getPiecesSortedByZIndex, + getFirstOwnedPiece, + getPieceDrawOffset, + getPieceDrawSize, + getFinalPiecePos, getStartTs, getFinishTs, handleInput, diff --git a/src/common/Protocol.ts b/src/common/Protocol.ts index 868e4c9..1f868c1 100644 --- a/src/common/Protocol.ts +++ b/src/common/Protocol.ts @@ -40,10 +40,8 @@ EV_SERVER_INIT: event sent to one client after that client */ const EV_SERVER_EVENT = 1 const EV_SERVER_INIT = 4 -const EV_SERVER_INIT_REPLAY = 5 const EV_CLIENT_EVENT = 2 const EV_CLIENT_INIT = 3 -const EV_CLIENT_INIT_REPLAY = 6 const LOG_HEADER = 1 const LOG_ADD_PLAYER = 2 @@ -60,6 +58,17 @@ const INPUT_EV_PLAYER_COLOR = 7 const INPUT_EV_PLAYER_NAME = 8 const INPUT_EV_MOVE = 9 const INPUT_EV_TOGGLE_PREVIEW = 10 +const INPUT_EV_TOGGLE_SOUNDS = 11 + +const INPUT_EV_REPLAY_TOGGLE_PAUSE = 12 +const INPUT_EV_REPLAY_SPEED_UP = 13 +const INPUT_EV_REPLAY_SPEED_DOWN = 14 + +const INPUT_EV_TOGGLE_PLAYER_NAMES = 15 +const INPUT_EV_CENTER_FIT_PUZZLE = 16 + +const INPUT_EV_TOGGLE_FIXED_PIECES = 17 +const INPUT_EV_TOGGLE_LOOSE_PIECES = 18 const CHANGE_DATA = 1 const CHANGE_TILE = 2 @@ -68,10 +77,8 @@ const CHANGE_PLAYER = 3 export default { EV_SERVER_EVENT, EV_SERVER_INIT, - EV_SERVER_INIT_REPLAY, EV_CLIENT_EVENT, EV_CLIENT_INIT, - EV_CLIENT_INIT_REPLAY, LOG_HEADER, LOG_ADD_PLAYER, @@ -91,6 +98,17 @@ export default { INPUT_EV_PLAYER_NAME, INPUT_EV_TOGGLE_PREVIEW, + INPUT_EV_TOGGLE_SOUNDS, + + INPUT_EV_REPLAY_TOGGLE_PAUSE, + INPUT_EV_REPLAY_SPEED_UP, + INPUT_EV_REPLAY_SPEED_DOWN, + + INPUT_EV_TOGGLE_PLAYER_NAMES, + INPUT_EV_CENTER_FIT_PUZZLE, + + INPUT_EV_TOGGLE_FIXED_PIECES, + INPUT_EV_TOGGLE_LOOSE_PIECES, CHANGE_DATA, CHANGE_TILE, diff --git a/src/common/Rng.ts b/src/common/Rng.ts index e18f80c..349e698 100644 --- a/src/common/Rng.ts +++ b/src/common/Rng.ts @@ -1,4 +1,4 @@ -interface RngSerialized { +export interface RngSerialized { rand_high: number, rand_low: number, } @@ -15,7 +15,7 @@ export class Rng { random (min: number, max: number): number { this.rand_high = ((this.rand_high << 16) + (this.rand_high >> 16) + this.rand_low) & 0xffffffff; this.rand_low = (this.rand_low + this.rand_high) & 0xffffffff; - var n = (this.rand_high >>> 0) / 0xffffffff; + const n = (this.rand_high >>> 0) / 0xffffffff; return (min + n * (max-min+1))|0; } diff --git a/src/common/Types.ts b/src/common/Types.ts new file mode 100644 index 0000000..ccbb318 --- /dev/null +++ b/src/common/Types.ts @@ -0,0 +1,255 @@ +import { Point } from "./Geometry" +import { Rng, RngSerialized } from "./Rng" + +// @see https://stackoverflow.com/a/59906630/392905 +type ArrayLengthMutationKeys = 'splice' | 'push' | 'pop' | 'shift' | 'unshift' | number +type ArrayItems> = T extends Array ? TItems : never +export type FixedLengthArray = + Pick> + & { [Symbol.iterator]: () => IterableIterator< ArrayItems > } + +export type Timestamp = number + +export type Input = any +export type Change = Array + +export type GameEvent = Array + +export type ServerEvent = Array +export type ClientEvent = Array + +export type EncodedPlayer = FixedLengthArray<[ + string, + number, + number, + 0|1, + string|null, + string|null, + string|null, + number, + Timestamp, +]> + +export type EncodedPiece = FixedLengthArray<[ + number, + number, + number, + number, + string|number, + number, +]> + +export type EncodedPieceShape = number + +export type EncodedGame = FixedLengthArray<[ + string, + string, + RngSerialized, + Puzzle, + Array, + Record, + ScoreMode, + ShapeMode, + SnapMode, + number|null, +]> + +export interface ReplayData { + log: any[], + game: EncodedGame|null +} + +export interface Tag { + id: number + slug: string + title: string + total: number +} + +interface GameRng { + obj: Rng + type?: string +} + +export interface Game { + id: string + creatorUserId: number|null + players: Array + puzzle: Puzzle + evtInfos: Record + scoreMode: ScoreMode + shapeMode: ShapeMode + snapMode: SnapMode + rng: GameRng +} + +export interface Image { + id: number + filename: string + file: string + url: string + title: string + tags: Array + created: number +} + +export interface GameSettings { + tiles: number + image: ImageInfo + scoreMode: ScoreMode + shapeMode: ShapeMode + snapMode: SnapMode +} + +export interface Puzzle { + tiles: Array + data: PuzzleData + info: PuzzleInfo +} + +export interface PuzzleData { + started: number + finished: number + maxGroup: number + maxZ: number +} + +export interface PuzzleDataChange { + started?: number + finished?: number + maxGroup?: number + maxZ?: number +} + +interface PuzzleTable { + width: number + height: number +} + +enum PieceEdge { + Flat = 0, + Out = 1, + In = -1, +} +export interface PieceShape { + top: PieceEdge + bottom: PieceEdge + left: PieceEdge + right: PieceEdge +} + +export interface Piece { + owner: string|number + idx: number + pos: Point + z: number + group: number +} + +export interface PieceChange { + owner?: string|number + idx?: number + pos?: Point + z?: number + group?: number +} + +export interface ImageInfo +{ + id: number + uploaderUserId: number|null + filename: string + url: string + title: string + tags: Tag[] + created: Timestamp + width: number + height: number +} + +export interface PuzzleInfo { + table: PuzzleTable + targetTiles: number + imageUrl?: string // deprecated, use image.url instead + image?: ImageInfo + + width: number + height: number + tileSize: number + tileDrawSize: number + tileMarginWidth: number + tileDrawOffset: number + snapDistance: number + + tiles: number + tilesX: number + tilesY: number + + shapes: Array +} + +export interface Player { + id: string + x: number + y: number + d: 0|1 + name: string|null + color: string|null + bgcolor: string|null + points: number + ts: Timestamp +} + +export interface PlayerChange { + id?: string + x?: number + y?: number + d?: 0|1 + name?: string|null + color?: string|null + bgcolor?: string|null + points?: number + ts?: Timestamp +} + +export interface EvtInfo { + _last_mouse: Point|null + _last_mouse_down: Point|null +} + +export enum ScoreMode { + FINAL = 0, + ANY = 1, +} + +export enum ShapeMode { + NORMAL = 0, + ANY = 1, + FLAT = 2, +} + +export enum SnapMode { + NORMAL = 0, + REAL = 1, +} + +export const DefaultScoreMode = (v: any): ScoreMode => { + if (v === ScoreMode.FINAL || v === ScoreMode.ANY) { + return v + } + return ScoreMode.FINAL +} + +export const DefaultShapeMode = (v: any): ShapeMode => { + if (v === ShapeMode.NORMAL || v === ShapeMode.ANY || v === ShapeMode.FLAT) { + return v + } + return ShapeMode.NORMAL +} + +export const DefaultSnapMode = (v: any): SnapMode => { + if (v === SnapMode.NORMAL || v === SnapMode.REAL) { + return v + } + return SnapMode.NORMAL +} diff --git a/src/common/Util.ts b/src/common/Util.ts index f691b75..4de6495 100644 --- a/src/common/Util.ts +++ b/src/common/Util.ts @@ -1,15 +1,29 @@ -import { EncodedPiece, EncodedPieceShape, EncodedPlayer, Piece, PieceShape, Player } from './GameCommon' +import { PuzzleCreationInfo } from '../server/Puzzle' +import { + EncodedGame, + EncodedPiece, + EncodedPieceShape, + EncodedPlayer, + Game, + Piece, + PieceShape, + Player, + PuzzleInfo, + ScoreMode, + ShapeMode, + SnapMode +} from './Types' import { Point } from './Geometry' import { Rng } from './Rng' -const slug = (str: string) => { +const slug = (str: string): string => { let tmp = str.toLowerCase() tmp = tmp.replace(/[^a-z0-9]+/g, '-') tmp = tmp.replace(/^-|-$/, '') return tmp } -const pad = (x: any, pad: string) => { +const pad = (x: number, pad: string): string => { const str = `${x}` if (str.length >= pad.length) { return str @@ -17,8 +31,11 @@ const pad = (x: any, pad: string) => { return pad.substr(0, pad.length - str.length) + str } -export const logger = (...pre: Array) => { - const log = (m: 'log'|'info'|'error') => (...args: Array) => { +type LogArgs = Array +type LogFn = (...args: LogArgs) => void + +export const logger = (...pre: string[]): { log: LogFn, error: LogFn, info: LogFn } => { + const log = (m: 'log'|'info'|'error') => (...args: LogArgs): void => { const d = new Date() const hh = pad(d.getHours(), '00') const mm = pad(d.getMinutes(), '00') @@ -33,7 +50,9 @@ export const logger = (...pre: Array) => { } // get a unique id -export const uniqId = () => Date.now().toString(36) + Math.random().toString(36).substring(2) +export const uniqId = (): string => { + return Date.now().toString(36) + Math.random().toString(36).substring(2) +} function encodeShape(data: PieceShape): EncodedPieceShape { /* encoded in 1 byte: @@ -58,11 +77,11 @@ function decodeShape(data: EncodedPieceShape): PieceShape { } } -function encodeTile(data: Piece): EncodedPiece { +function encodePiece(data: Piece): EncodedPiece { return [data.idx, data.pos.x, data.pos.y, data.z, data.owner, data.group] } -function decodeTile(data: EncodedPiece): Piece { +function decodePiece(data: EncodedPiece): Piece { return { idx: data[0], pos: { @@ -103,25 +122,22 @@ function decodePlayer(data: EncodedPlayer): Player { } } -function encodeGame(data: any): Array { - if (Array.isArray(data)) { - return data - } +function encodeGame(data: Game): EncodedGame { return [ data.id, - data.rng.type, + data.rng.type || '', Rng.serialize(data.rng.obj), data.puzzle, data.players, data.evtInfos, data.scoreMode, + data.shapeMode, + data.snapMode, + data.creatorUserId, ] } -function decodeGame(data: any) { - if (!Array.isArray(data)) { - return data - } +function decodeGame(data: EncodedGame): Game { return { id: data[0], rng: { @@ -132,14 +148,17 @@ function decodeGame(data: any) { players: data[4], evtInfos: data[5], scoreMode: data[6], + shapeMode: data[7], + snapMode: data[8], + creatorUserId: data[9], } } -function coordByTileIdx(info: any, tileIdx: number): Point { +function coordByPieceIdx(info: PuzzleInfo|PuzzleCreationInfo, pieceIdx: number): Point { const wTiles = info.width / info.tileSize return { - x: tileIdx % wTiles, - y: Math.floor(tileIdx / wTiles), + x: pieceIdx % wTiles, + y: Math.floor(pieceIdx / wTiles), } } @@ -147,16 +166,16 @@ const hash = (str: string): number => { let hash = 0 for (let i = 0; i < str.length; i++) { - let chr = str.charCodeAt(i); + const chr = str.charCodeAt(i); hash = ((hash << 5) - hash) + chr; hash |= 0; // Convert to 32bit integer } return hash; } -function asQueryArgs(data: any) { +function asQueryArgs(data: Record): string { const q = [] - for (let k in data) { + for (const k in data) { const pair = [k, data[k]].map(encodeURIComponent) q.push(pair.join('=')) } @@ -174,8 +193,8 @@ export default { encodeShape, decodeShape, - encodeTile, - decodeTile, + encodePiece, + decodePiece, encodePlayer, decodePlayer, @@ -183,7 +202,7 @@ export default { encodeGame, decodeGame, - coordByTileIdx, + coordByPieceIdx, asQueryArgs, } diff --git a/src/dbpatches/02_gamelog.sqlite b/src/dbpatches/02_gamelog.sqlite deleted file mode 100644 index 4fe0160..0000000 --- a/src/dbpatches/02_gamelog.sqlite +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE game_log ( - game_id TEXT, - - created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - - entry TEXT NOT NULL -); diff --git a/src/dbpatches/02_image_sizes.sqlite b/src/dbpatches/02_image_sizes.sqlite new file mode 100644 index 0000000..35e0f39 --- /dev/null +++ b/src/dbpatches/02_image_sizes.sqlite @@ -0,0 +1,22 @@ +-- Add width/height to images table + +CREATE TABLE images_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + + created TIMESTAMP NOT NULL, + + filename TEXT NOT NULL UNIQUE, + filename_original TEXT NOT NULL, + title TEXT NOT NULL, + + width INTEGER NOT NULL, + height INTEGER NOT NULL +); + +INSERT INTO images_new +SELECT id, created, filename, filename_original, title, 0, 0 +FROM images; + +DROP TABLE images; + +ALTER TABLE images_new RENAME TO images; diff --git a/src/dbpatches/03_users.sqlite b/src/dbpatches/03_users.sqlite new file mode 100644 index 0000000..c71908f --- /dev/null +++ b/src/dbpatches/03_users.sqlite @@ -0,0 +1,45 @@ +CREATE TABLE users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + + created TIMESTAMP NOT NULL, + + client_id TEXT NOT NULL, + client_secret TEXT NOT NULL +); + +CREATE TABLE images_new ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + uploader_user_id INTEGER, + + created TIMESTAMP NOT NULL, + + filename TEXT NOT NULL UNIQUE, + filename_original TEXT NOT NULL, + title TEXT NOT NULL, + + width INTEGER NOT NULL, + height INTEGER NOT NULL +); + +CREATE TABLE image_x_category_new ( + image_id INTEGER NOT NULL, + category_id INTEGER NOT NULL +); + +INSERT INTO images_new +SELECT id, NULL, created, filename, filename_original, title, width, height +FROM images; + +INSERT INTO image_x_category_new +SELECT image_id, category_id +FROM image_x_category; + +PRAGMA foreign_keys = OFF; + +DROP TABLE images; +DROP TABLE image_x_category; + +ALTER TABLE images_new RENAME TO images; +ALTER TABLE image_x_category_new RENAME TO image_x_category; + +PRAGMA foreign_keys = ON; diff --git a/src/dbpatches/04_games.sqlite b/src/dbpatches/04_games.sqlite new file mode 100644 index 0000000..edde806 --- /dev/null +++ b/src/dbpatches/04_games.sqlite @@ -0,0 +1,11 @@ +CREATE TABLE games ( + id TEXT PRIMARY KEY, + + creator_user_id INTEGER, + image_id INTEGER NOT NULL, + + created TIMESTAMP NOT NULL, + finished TIMESTAMP NOT NULL, + + data TEXT NOT NULL +); diff --git a/src/frontend/App.vue b/src/frontend/App.vue index 7e13439..8a9c113 100644 --- a/src/frontend/App.vue +++ b/src/frontend/App.vue @@ -1,7 +1,7 @@ diff --git a/src/frontend/components/NewGameDialog.vue b/src/frontend/components/NewGameDialog.vue index 0eff20a..eff46a7 100644 --- a/src/frontend/components/NewGameDialog.vue +++ b/src/frontend/components/NewGameDialog.vue @@ -6,6 +6,10 @@
+
+ "{{image.title}}" + ({{image.width}} ✕ {{image.height}}) +
@@ -17,9 +21,34 @@ - +
- + + + + + + + +
+ +
+ + + + + + + +
+ @@ -36,7 +65,7 @@ @@ -127,18 +210,36 @@ export default defineComponent({ height: 90%; width: 80%; } +@media (max-width: 1400px) and (min-height: 720px), + (max-width: 1000px) { + .new-image-dialog .overlay-content { + grid-template-columns: auto; + grid-template-rows: 1fr min-content min-content; + grid-template-areas: + "image" + "settings" + "buttons"; + } + .new-image-dialog .overlay-content .area-buttons .btn br { + display: none; + } +} .new-image-dialog .area-image { grid-area: image; - margin: 20px; + margin: .5em; + border: solid 6px transparent; } .new-image-dialog .area-image.no-image { align-content: center; display: grid; text-align: center; - border: dashed 6px; + border: solid 6px; position: relative; } +.new-image-dialog .area-image.droppable { + border: dashed 6px; +} .new-image-dialog .area-image .has-image { position: relative; width: 100%; @@ -180,4 +281,16 @@ export default defineComponent({ top: 50%; transform: translate(-50%,-50%); } +.area-image .drop-target { + display: none; +} +.area-image.droppable .drop-target { + pointer-events: none; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 3; +} diff --git a/src/frontend/components/SettingsOverlay.vue b/src/frontend/components/SettingsOverlay.vue index 4a940db..b17c4dd 100644 --- a/src/frontend/components/SettingsOverlay.vue +++ b/src/frontend/components/SettingsOverlay.vue @@ -13,6 +13,28 @@ + + + + + + + + 🔉 + + 🔊 + + + + + +
@@ -26,7 +48,23 @@ export default defineComponent({ 'update:modelValue': null, }, props: { - modelValue: Object, + modelValue: { + type: Object, + required: true, + }, + }, + methods: { + updateVolume (ev: Event): void { + (this.modelValue as any).soundsVolume = (ev.target as HTMLInputElement).value + }, + decreaseVolume (): void { + const vol = parseInt(this.modelValue.soundsVolume, 10) - 5 + this.modelValue.soundsVolume = Math.max(0, vol) + }, + increaseVolume (): void { + const vol = parseInt(this.modelValue.soundsVolume, 10) + 5 + this.modelValue.soundsVolume = Math.min(100, vol) + }, }, created () { // TODO: ts type PlayerSettings @@ -36,3 +74,7 @@ export default defineComponent({ }, }) + diff --git a/src/frontend/components/TagsInput.vue b/src/frontend/components/TagsInput.vue index c6fe16a..0fbbcdc 100644 --- a/src/frontend/components/TagsInput.vue +++ b/src/frontend/components/TagsInput.vue @@ -1,19 +1,42 @@