diff --git a/dist/css/app.15c1a0ea.css b/dist/css/app.824dbe6a.css
similarity index 95%
rename from dist/css/app.15c1a0ea.css
rename to dist/css/app.824dbe6a.css
index 8fc128b..d47d4bb 100644
--- a/dist/css/app.15c1a0ea.css
+++ b/dist/css/app.824dbe6a.css
@@ -1 +1 @@
-:root{--bg-color:#282a36;--accent:#353744;--current-line:#44475a;--comment:#6272a4;--foreground:#f8f8f2;--orange:#ffb86c;--cyan:#8be9fd;--green:#50fa7b;--pink:#ff79c6;--purple:#bd93f9;--red:#f55;--yellow:#f1fa8c}body{background:var(--bg-color);margin:0}#app{height:100vh;width:100vw;font-family:Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:var(--foreground);display:grid;grid-template-areas:"header header" "filters body " "stats body " "footer body ";grid-template-columns:1fr 5fr;grid-template-rows:auto 1fr auto auto}@media only screen and (max-width:922px){#app{grid-template-areas:"header header" "filters filters" "body body ";grid-template-rows:auto auto 1fr}}@media only screen and (max-width:600px){.github-link{display:none}}header{grid-area:header;height:64px;background:var(--bg-color);color:var(--foreground)}nav{display:flex;flex-direction:row;text-align:center;vertical-align:middle}nav a{font-weight:700;color:var(--foreground)}nav a.router-link-exact-active{color:var(--orange)}.navbar-element{text-align:center;line-height:16px;padding:24px 32px}.navbar-element:hover{background:var(--current-line)}.spacer{width:100%}[data-v-037b66ea]{box-sizing:border-box}.playerTable[data-v-037b66ea]{grid-area:list;margin-right:1rem;overflow:auto;height:100%;-webkit-user-select:none;-moz-user-select:none;user-select:none}.playerHeaders[data-v-037b66ea],.playerRow[data-v-037b66ea]{box-sizing:border-box;display:grid;grid-template-columns:5ch 20ch 6ch 6ch 6ch 10ch 1fr;background:var(--bg-color);text-align:left;cursor:pointer;margin:0;transition:border .25s;height:2em}.playerHeaders[data-v-037b66ea]{position:sticky;top:0;height:3em}.playerHeaders>span[data-v-037b66ea]{padding:.5em .8em 0 .25em}.playerRow>div[data-v-037b66ea]{padding:.5em .8em 0 .25em;overflow:hidden}.playerHeaders[data-v-037b66ea],.playerRow[data-v-037b66ea]:nth-child(2n){background:var(--current-line)}.playerRow[data-v-037b66ea]:nth-child(odd){background:var(--accent)}.playerHeaders div[data-v-037b66ea]:hover,.playerRow[data-v-037b66ea]:hover{background:var(--bg-color)}.playerHeaders>div[data-v-037b66ea]:not(:last-child),.playerRow>div[data-v-037b66ea]:not(:last-child){border-right:solid var(--bg-color) 2px}.playerHeaders>span[data-v-037b66ea]:last-child{width:100%}@media only screen and (max-width:600px){.playerHeaders>span[data-v-037b66ea]:nth-child(6),.playerHeaders>span[data-v-037b66ea]:nth-child(7),.playerRow>div[data-v-037b66ea]:nth-child(6),.playerRow>div[data-v-037b66ea]:nth-child(7){display:none}.playerHeaders[data-v-037b66ea],.playerRow[data-v-037b66ea]{grid-template-columns:5ch 20ch 6ch 6ch 1fr}}.player span[data-v-037b66ea]{pointer-events:none}.selected[data-v-037b66ea]{background:var(--comment)!important}canvas[data-v-1e99590c]{background:var(--accent)}@media only screen and (max-width:922px){canvas[data-v-1e99590c]{display:none!important}}.weaponChart[data-v-53c5074f]{width:calc(min(50vw, 50vh) - 3em);height:calc(min(50vw, 50vh) - 3em)}@media only screen and (max-width:922px){canvas[data-v-53c5074f]{display:none!important}}fieldset[disabled] .multiselect{pointer-events:none}.multiselect__spinner{position:absolute;right:1px;top:1px;width:40px;height:38px;background:#fff;display:block}.multiselect__spinner:after,.multiselect__spinner:before{position:absolute;content:"";top:50%;left:50%;margin:-8px 0 0 -8px;width:16px;height:16px;border-radius:100%;border-color:#41b883 transparent transparent;border-style:solid;border-width:2px;box-shadow:0 0 0 1px transparent}.multiselect__spinner:before{animation:spinning 2.4s cubic-bezier(.41,.26,.2,.62);animation-iteration-count:infinite}.multiselect__spinner:after{animation:spinning 2.4s cubic-bezier(.51,.09,.21,.8);animation-iteration-count:infinite}.multiselect__loading-enter-active,.multiselect__loading-leave-active{transition:opacity .4s ease-in-out;opacity:1}.multiselect__loading-enter,.multiselect__loading-leave-active{opacity:0}.multiselect,.multiselect__input,.multiselect__single{font-family:inherit;font-size:16px;touch-action:manipulation}.multiselect{box-sizing:content-box;display:block;position:relative;width:100%;min-height:40px;text-align:left;color:#35495e}.multiselect *{box-sizing:border-box}.multiselect:focus{outline:none}.multiselect--disabled{background:#ededed;pointer-events:none;opacity:.6}.multiselect--active{z-index:50}.multiselect--active:not(.multiselect--above) .multiselect__current,.multiselect--active:not(.multiselect--above) .multiselect__input,.multiselect--active:not(.multiselect--above) .multiselect__tags{border-bottom-left-radius:0;border-bottom-right-radius:0}.multiselect--active .multiselect__select{transform:rotate(180deg)}.multiselect--above.multiselect--active .multiselect__current,.multiselect--above.multiselect--active .multiselect__input,.multiselect--above.multiselect--active .multiselect__tags{border-top-left-radius:0;border-top-right-radius:0}.multiselect__input,.multiselect__single{position:relative;display:inline-block;min-height:20px;line-height:20px;border:none;border-radius:5px;background:#fff;padding:0 0 0 5px;width:100%;transition:border .1s ease;box-sizing:border-box;margin-bottom:8px;vertical-align:top}.multiselect__input::-moz-placeholder{color:#35495e}.multiselect__input::placeholder{color:#35495e}.multiselect__tag~.multiselect__input,.multiselect__tag~.multiselect__single{width:auto}.multiselect__input:hover,.multiselect__single:hover{border-color:#cfcfcf}.multiselect__input:focus,.multiselect__single:focus{border-color:#a8a8a8;outline:none}.multiselect__single{padding-left:5px;margin-bottom:8px}.multiselect__tags-wrap{display:inline}.multiselect__tags{min-height:40px;display:block;padding:8px 40px 0 8px;border-radius:5px;border:1px solid #e8e8e8;background:#fff;font-size:14px}.multiselect__tag{position:relative;display:inline-block;padding:4px 26px 4px 10px;border-radius:5px;margin-right:10px;color:#fff;line-height:1;background:#41b883;margin-bottom:5px;white-space:nowrap;overflow:hidden;max-width:100%;text-overflow:ellipsis}.multiselect__tag-icon{cursor:pointer;margin-left:7px;position:absolute;right:0;top:0;bottom:0;font-weight:700;font-style:normal;width:22px;text-align:center;line-height:22px;transition:all .2s ease;border-radius:5px}.multiselect__tag-icon:after{content:"×";color:#266d4d;font-size:14px}.multiselect__tag-icon:focus:after,.multiselect__tag-icon:hover:after{color:#fff}.multiselect__current{min-height:40px;overflow:hidden;padding:8px 12px 0;padding-right:30px;white-space:nowrap;border-radius:5px;border:1px solid #e8e8e8}.multiselect__current,.multiselect__select{line-height:16px;box-sizing:border-box;display:block;margin:0;text-decoration:none;cursor:pointer}.multiselect__select{position:absolute;width:40px;height:38px;right:1px;top:1px;padding:4px 8px;text-align:center;transition:transform .2s ease}.multiselect__select:before{position:relative;right:0;top:65%;color:#999;margin-top:4px;border-style:solid;border-width:5px 5px 0 5px;border-color:#999 transparent transparent transparent;content:""}.multiselect__placeholder{color:#adadad;display:inline-block;margin-bottom:10px;padding-top:2px}.multiselect--active .multiselect__placeholder{display:none}.multiselect__content-wrapper{position:absolute;display:block;background:#fff;width:100%;max-height:240px;overflow:auto;border:1px solid #e8e8e8;border-top:none;border-bottom-left-radius:5px;border-bottom-right-radius:5px;z-index:50;-webkit-overflow-scrolling:touch}.multiselect__content{list-style:none;display:inline-block;padding:0;margin:0;min-width:100%;vertical-align:top}.multiselect--above .multiselect__content-wrapper{bottom:100%;border-bottom-left-radius:0;border-bottom-right-radius:0;border-top-left-radius:5px;border-top-right-radius:5px;border-bottom:none;border-top:1px solid #e8e8e8}.multiselect__content::-webkit-scrollbar{display:none}.multiselect__element{display:block}.multiselect__option{display:block;padding:12px;min-height:40px;line-height:16px;text-decoration:none;text-transform:none;vertical-align:middle;position:relative;cursor:pointer;white-space:nowrap}.multiselect__option:after{top:0;right:0;position:absolute;line-height:40px;padding-right:12px;padding-left:20px;font-size:13px}.multiselect__option--highlight{background:#41b883;outline:none;color:#fff}.multiselect__option--highlight:after{content:attr(data-select);background:#41b883;color:#fff}.multiselect__option--selected{background:#f3f3f3;color:#35495e;font-weight:700}.multiselect__option--selected:after{content:attr(data-selected);color:silver;background:inherit}.multiselect__option--selected.multiselect__option--highlight{background:#ff6a6a;color:#fff}.multiselect__option--selected.multiselect__option--highlight:after{background:#ff6a6a;content:attr(data-deselect);color:#fff}.multiselect--disabled .multiselect__current,.multiselect--disabled .multiselect__select{background:#ededed;color:#a6a6a6}.multiselect__option--disabled{background:#ededed!important;color:#a6a6a6!important;cursor:text;pointer-events:none}.multiselect__option--group{background:#ededed;color:#35495e}.multiselect__option--group.multiselect__option--highlight{background:#35495e;color:#fff}.multiselect__option--group.multiselect__option--highlight:after{background:#35495e}.multiselect__option--disabled.multiselect__option--highlight{background:#dedede}.multiselect__option--group-selected.multiselect__option--highlight{background:#ff6a6a;color:#fff}.multiselect__option--group-selected.multiselect__option--highlight:after{background:#ff6a6a;content:attr(data-deselect);color:#fff}.multiselect-enter-active,.multiselect-leave-active{transition:all .15s ease}.multiselect-enter,.multiselect-leave-active{opacity:0}.multiselect__strong{margin-bottom:8px;line-height:20px;display:inline-block;vertical-align:top}[dir=rtl] .multiselect{text-align:right}[dir=rtl] .multiselect__select{right:auto;left:1px}[dir=rtl] .multiselect__tags{padding:8px 8px 0 40px}[dir=rtl] .multiselect__content{text-align:right}[dir=rtl] .multiselect__option:after{right:auto;left:0}[dir=rtl] .multiselect__clear{right:auto;left:12px}[dir=rtl] .multiselect__spinner{right:auto;left:1px}@keyframes spinning{0%{transform:rotate(0)}to{transform:rotate(2turn)}}.multiselect[data-v-16cf505a]{margin:0 .5em 1em .5em}#playerView[data-v-16cf505a]{margin:0 1rem 1rem 1rem;display:grid;overflow:auto;grid-template-areas:"list chart" "list info";grid-template-columns:50% 50%;grid-template-rows:50% 50%}@media only screen and (max-width:922px){#playerView[data-v-16cf505a]{margin:0 1rem 1rem 1rem;display:grid;overflow:auto;grid-template-areas:"list list";grid-template-columns:100%;grid-template-rows:100%;width:calc(100vw - 1em);margin:0 0 1rem 1rem}.multiselect[data-v-16cf505a]{width:calc(100% - 1em)}}#filters[data-v-16cf505a]{grid-area:filters}
\ No newline at end of file
+:root{--bg-color:#282a36;--accent:#353744;--current-line:#44475a;--comment:#6272a4;--foreground:#f8f8f2;--orange:#ffb86c;--cyan:#8be9fd;--green:#50fa7b;--pink:#ff79c6;--purple:#bd93f9;--red:#f55;--yellow:#f1fa8c}body{background:var(--bg-color);margin:0}#app{height:100vh;width:100vw;font-family:Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:var(--foreground);display:grid;grid-template-areas:"header header" "filters body " "stats body " "footer body ";grid-template-columns:1fr 5fr;grid-template-rows:auto 1fr auto auto}@media only screen and (max-width:922px){#app{grid-template-areas:"header header" "filters filters" "body body ";grid-template-rows:auto auto 1fr}}@media only screen and (max-width:600px){.github-link{display:none}}header{grid-area:header;height:64px;background:var(--bg-color);color:var(--foreground)}nav{display:flex;flex-direction:row;text-align:center;vertical-align:middle}nav a{font-weight:700;color:var(--foreground)}nav a.router-link-exact-active{color:var(--orange)}.navbar-element{text-align:center;line-height:16px;padding:24px 32px}.navbar-element:hover{background:var(--current-line)}.spacer{width:100%}[data-v-037b66ea]{box-sizing:border-box}.playerTable[data-v-037b66ea]{grid-area:list;margin-right:1rem;overflow:auto;height:100%;-webkit-user-select:none;-moz-user-select:none;user-select:none}.playerHeaders[data-v-037b66ea],.playerRow[data-v-037b66ea]{box-sizing:border-box;display:grid;grid-template-columns:5ch 20ch 6ch 6ch 6ch 10ch 1fr;background:var(--bg-color);text-align:left;cursor:pointer;margin:0;transition:border .25s;height:2em}.playerHeaders[data-v-037b66ea]{position:sticky;top:0;height:3em}.playerHeaders>span[data-v-037b66ea]{padding:.5em .8em 0 .25em}.playerRow>div[data-v-037b66ea]{padding:.5em .8em 0 .25em;overflow:hidden}.playerHeaders[data-v-037b66ea],.playerRow[data-v-037b66ea]:nth-child(2n){background:var(--current-line)}.playerRow[data-v-037b66ea]:nth-child(odd){background:var(--accent)}.playerHeaders div[data-v-037b66ea]:hover,.playerRow[data-v-037b66ea]:hover{background:var(--bg-color)}.playerHeaders>div[data-v-037b66ea]:not(:last-child),.playerRow>div[data-v-037b66ea]:not(:last-child){border-right:solid var(--bg-color) 2px}.playerHeaders>span[data-v-037b66ea]:last-child{width:100%}@media only screen and (max-width:600px){.playerHeaders>span[data-v-037b66ea]:nth-child(6),.playerHeaders>span[data-v-037b66ea]:nth-child(7),.playerRow>div[data-v-037b66ea]:nth-child(6),.playerRow>div[data-v-037b66ea]:nth-child(7){display:none}.playerHeaders[data-v-037b66ea],.playerRow[data-v-037b66ea]{grid-template-columns:5ch 20ch 6ch 6ch 1fr}}.player span[data-v-037b66ea]{pointer-events:none}.selected[data-v-037b66ea]{background:var(--comment)!important}canvas[data-v-1e99590c]{background:var(--accent)}@media only screen and (max-width:922px){canvas[data-v-1e99590c]{display:none!important}}.weaponChart[data-v-53c5074f]{width:calc(min(50vw, 50vh) - 3em);height:calc(min(50vw, 50vh) - 3em)}@media only screen and (max-width:922px){canvas[data-v-53c5074f]{display:none!important}}fieldset[disabled] .multiselect{pointer-events:none}.multiselect__spinner{position:absolute;right:1px;top:1px;width:40px;height:38px;background:#fff;display:block}.multiselect__spinner:after,.multiselect__spinner:before{position:absolute;content:"";top:50%;left:50%;margin:-8px 0 0 -8px;width:16px;height:16px;border-radius:100%;border-color:#41b883 transparent transparent;border-style:solid;border-width:2px;box-shadow:0 0 0 1px transparent}.multiselect__spinner:before{animation:spinning 2.4s cubic-bezier(.41,.26,.2,.62);animation-iteration-count:infinite}.multiselect__spinner:after{animation:spinning 2.4s cubic-bezier(.51,.09,.21,.8);animation-iteration-count:infinite}.multiselect__loading-enter-active,.multiselect__loading-leave-active{transition:opacity .4s ease-in-out;opacity:1}.multiselect__loading-enter,.multiselect__loading-leave-active{opacity:0}.multiselect,.multiselect__input,.multiselect__single{font-family:inherit;font-size:16px;touch-action:manipulation}.multiselect{box-sizing:content-box;display:block;position:relative;width:100%;min-height:40px;text-align:left;color:#35495e}.multiselect *{box-sizing:border-box}.multiselect:focus{outline:none}.multiselect--disabled{background:#ededed;pointer-events:none;opacity:.6}.multiselect--active{z-index:50}.multiselect--active:not(.multiselect--above) .multiselect__current,.multiselect--active:not(.multiselect--above) .multiselect__input,.multiselect--active:not(.multiselect--above) .multiselect__tags{border-bottom-left-radius:0;border-bottom-right-radius:0}.multiselect--active .multiselect__select{transform:rotate(180deg)}.multiselect--above.multiselect--active .multiselect__current,.multiselect--above.multiselect--active .multiselect__input,.multiselect--above.multiselect--active .multiselect__tags{border-top-left-radius:0;border-top-right-radius:0}.multiselect__input,.multiselect__single{position:relative;display:inline-block;min-height:20px;line-height:20px;border:none;border-radius:5px;background:#fff;padding:0 0 0 5px;width:100%;transition:border .1s ease;box-sizing:border-box;margin-bottom:8px;vertical-align:top}.multiselect__input::-moz-placeholder{color:#35495e}.multiselect__input::placeholder{color:#35495e}.multiselect__tag~.multiselect__input,.multiselect__tag~.multiselect__single{width:auto}.multiselect__input:hover,.multiselect__single:hover{border-color:#cfcfcf}.multiselect__input:focus,.multiselect__single:focus{border-color:#a8a8a8;outline:none}.multiselect__single{padding-left:5px;margin-bottom:8px}.multiselect__tags-wrap{display:inline}.multiselect__tags{min-height:40px;display:block;padding:8px 40px 0 8px;border-radius:5px;border:1px solid #e8e8e8;background:#fff;font-size:14px}.multiselect__tag{position:relative;display:inline-block;padding:4px 26px 4px 10px;border-radius:5px;margin-right:10px;color:#fff;line-height:1;background:#41b883;margin-bottom:5px;white-space:nowrap;overflow:hidden;max-width:100%;text-overflow:ellipsis}.multiselect__tag-icon{cursor:pointer;margin-left:7px;position:absolute;right:0;top:0;bottom:0;font-weight:700;font-style:normal;width:22px;text-align:center;line-height:22px;transition:all .2s ease;border-radius:5px}.multiselect__tag-icon:after{content:"×";color:#266d4d;font-size:14px}.multiselect__tag-icon:focus:after,.multiselect__tag-icon:hover:after{color:#fff}.multiselect__current{min-height:40px;overflow:hidden;padding:8px 12px 0;padding-right:30px;white-space:nowrap;border-radius:5px;border:1px solid #e8e8e8}.multiselect__current,.multiselect__select{line-height:16px;box-sizing:border-box;display:block;margin:0;text-decoration:none;cursor:pointer}.multiselect__select{position:absolute;width:40px;height:38px;right:1px;top:1px;padding:4px 8px;text-align:center;transition:transform .2s ease}.multiselect__select:before{position:relative;right:0;top:65%;color:#999;margin-top:4px;border-style:solid;border-width:5px 5px 0 5px;border-color:#999 transparent transparent transparent;content:""}.multiselect__placeholder{color:#adadad;display:inline-block;margin-bottom:10px;padding-top:2px}.multiselect--active .multiselect__placeholder{display:none}.multiselect__content-wrapper{position:absolute;display:block;background:#fff;width:100%;max-height:240px;overflow:auto;border:1px solid #e8e8e8;border-top:none;border-bottom-left-radius:5px;border-bottom-right-radius:5px;z-index:50;-webkit-overflow-scrolling:touch}.multiselect__content{list-style:none;display:inline-block;padding:0;margin:0;min-width:100%;vertical-align:top}.multiselect--above .multiselect__content-wrapper{bottom:100%;border-bottom-left-radius:0;border-bottom-right-radius:0;border-top-left-radius:5px;border-top-right-radius:5px;border-bottom:none;border-top:1px solid #e8e8e8}.multiselect__content::-webkit-scrollbar{display:none}.multiselect__element{display:block}.multiselect__option{display:block;padding:12px;min-height:40px;line-height:16px;text-decoration:none;text-transform:none;vertical-align:middle;position:relative;cursor:pointer;white-space:nowrap}.multiselect__option:after{top:0;right:0;position:absolute;line-height:40px;padding-right:12px;padding-left:20px;font-size:13px}.multiselect__option--highlight{background:#41b883;outline:none;color:#fff}.multiselect__option--highlight:after{content:attr(data-select);background:#41b883;color:#fff}.multiselect__option--selected{background:#f3f3f3;color:#35495e;font-weight:700}.multiselect__option--selected:after{content:attr(data-selected);color:silver;background:inherit}.multiselect__option--selected.multiselect__option--highlight{background:#ff6a6a;color:#fff}.multiselect__option--selected.multiselect__option--highlight:after{background:#ff6a6a;content:attr(data-deselect);color:#fff}.multiselect--disabled .multiselect__current,.multiselect--disabled .multiselect__select{background:#ededed;color:#a6a6a6}.multiselect__option--disabled{background:#ededed!important;color:#a6a6a6!important;cursor:text;pointer-events:none}.multiselect__option--group{background:#ededed;color:#35495e}.multiselect__option--group.multiselect__option--highlight{background:#35495e;color:#fff}.multiselect__option--group.multiselect__option--highlight:after{background:#35495e}.multiselect__option--disabled.multiselect__option--highlight{background:#dedede}.multiselect__option--group-selected.multiselect__option--highlight{background:#ff6a6a;color:#fff}.multiselect__option--group-selected.multiselect__option--highlight:after{background:#ff6a6a;content:attr(data-deselect);color:#fff}.multiselect-enter-active,.multiselect-leave-active{transition:all .15s ease}.multiselect-enter,.multiselect-leave-active{opacity:0}.multiselect__strong{margin-bottom:8px;line-height:20px;display:inline-block;vertical-align:top}[dir=rtl] .multiselect{text-align:right}[dir=rtl] .multiselect__select{right:auto;left:1px}[dir=rtl] .multiselect__tags{padding:8px 8px 0 40px}[dir=rtl] .multiselect__content{text-align:right}[dir=rtl] .multiselect__option:after{right:auto;left:0}[dir=rtl] .multiselect__clear{right:auto;left:12px}[dir=rtl] .multiselect__spinner{right:auto;left:1px}@keyframes spinning{0%{transform:rotate(0)}to{transform:rotate(2turn)}}.multiselect[data-v-639162c3]{margin:0 .5em 1em .5em}.multiselect-wrapper[data-v-639162c3]{display:flex}.multiselect-wrapper button[data-v-639162c3]{margin:0 0 1em 0;font-size:16px}#playerView[data-v-639162c3]{margin:0 1rem 1rem 1rem;display:grid;overflow:auto;grid-template-areas:"list chart" "list info";grid-template-columns:50% 50%;grid-template-rows:50% 50%}@media only screen and (max-width:922px){#playerView[data-v-639162c3]{margin:0 1rem 1rem 1rem;display:grid;overflow:auto;grid-template-areas:"list list";grid-template-columns:100%;grid-template-rows:100%;width:calc(100vw - 1em);margin:0 0 1rem 1rem}.multiselect[data-v-639162c3]{width:calc(100% - 1em)}.playerChart[data-v-639162c3],.weaponChart[data-v-639162c3]{display:none}}#filters[data-v-639162c3]{grid-area:filters}
\ No newline at end of file
diff --git a/dist/index.html b/dist/index.html
index 82f0d3a..6efbd26 100644
--- a/dist/index.html
+++ b/dist/index.html
@@ -1 +1 @@
-
toneapi_webclient We're sorry but toneapi_webclient doesn't work properly without JavaScript enabled. Please enable it to continue.
\ No newline at end of file
+toneapi_webclient We're sorry but toneapi_webclient doesn't work properly without JavaScript enabled. Please enable it to continue.
\ No newline at end of file
diff --git a/dist/js/app.0ce0bd00.js b/dist/js/app.0ce0bd00.js
new file mode 100644
index 0000000..3f2818c
--- /dev/null
+++ b/dist/js/app.0ce0bd00.js
@@ -0,0 +1,2 @@
+(function(){"use strict";var e={8218:function(e,t,a){var r=a(3862),s=a(3396);const i=(0,s.uE)('TONE API
',4);function n(e,t,a,r,n,l){const o=(0,s.up)("router-link"),p=(0,s.up)("router-view");return(0,s.wg)(),(0,s.iD)(s.HY,null,[(0,s._)("header",null,[(0,s._)("nav",null,[i,(0,s.Wm)(o,{to:"/",class:"navbar-element"},{default:(0,s.w5)((()=>[(0,s.Uk)("Players")])),_:1})])]),(0,s.Wm)(p)],64)}a(7658);var l=a(1020),o=a(5130),p=a(4870);function d(e){return Object.fromEntries(Object.entries(e).filter((e=>void 0!==e[1]&&null!==e[1])))}function h(e,t){try{return e=d(e),t=d(t),o.deepStrictEqual(e,t),!0}catch{return!1}}const c=(0,l.Q_)("kill",{state:()=>({servers:[],players:[],weapons:[],maps:[],gamemodes:[],hosts:{}}),getters:{getPlayerList:e=>t=>e.players.find((e=>h(e.value.filter,t))),getWeaponList:e=>t=>e.weapons.find((e=>h(e.value.filter,t))),getServerList:e=>t=>e.servers.find((e=>h(e.value.filter,t)))},actions:{fetchPlayers(e){e=d(e);let t=this.players.find((t=>h(t.value.filter,e)));return void 0===t&&(t=(0,p.iH)({filter:e,data:{}}),this.players.push(t)),fetch("https://tone.sleepycat.date/v2/client/players?"+new URLSearchParams(e)).then((async e=>{t.value.data=await e.json()})),t},fetchWeapons(e){e=d(e);let t=this.weapons.find((t=>h(t.value.filter,e)));return t||(t=(0,p.iH)({filter:e,data:{}}),this.weapons.push(t)),fetch("https://tone.sleepycat.date/v2/client/weapons?"+new URLSearchParams(e)).then((async e=>{t.value.data=await e.json()})),t},fetchServers(e){e=d(e);let t=this.servers.find((t=>h(t.value.filter,e)));return t||(t=(0,p.iH)({filter:e,data:{}}),this.servers.push(t)),fetch("https://tone.sleepycat.date/v2/client/servers?"+new URLSearchParams(e)).then((async e=>{t.value.data=await e.json()})),t}}});var u=(0,s.aZ)({setup(e,t){const a=c();a.fetchPlayers({}),a.fetchServers({}),a.fetchWeapons({})}}),g=a(89);const m=(0,g.Z)(u,[["render",n]]);var _=m,f=a(2483);const y={id:"filters"},v={class:"multiselect-wrapper"},w={class:"multiselect-wrapper"},b={class:"multiselect-wrapper"},k={id:"playerView"};function P(e,t,a,r,i,n){const l=(0,s.up)("VueMultiselect"),o=(0,s.up)("PlayerList"),p=(0,s.up)("PlayerChart"),d=(0,s.up)("WeaponChart");return(0,s.wg)(),(0,s.iD)(s.HY,null,[(0,s._)("div",y,[(0,s._)("span",v,[(0,s.Wm)(l,{selectLabel:"",deselectLabel:"remove",placeholder:"Select server",modelValue:e.model.server,"onUpdate:modelValue":t[0]||(t[0]=t=>e.model.server=t),options:e.groupedServers,"group-values":"servers",group_label:"id","group-select":!1,"allow-empty":!0,multiple:!1,"custom-label":e=>e.name,"track-by":"name",label:"name"},null,8,["modelValue","options","custom-label"]),(0,s._)("button",{onClick:t[1]||(t[1]=t=>e.model.server=void 0)},"X")]),(0,s._)("span",w,[(0,s.Wm)(l,{selectLabel:"",deselectLabel:"remove",placeholder:"Select weapon",modelValue:e.model.weapon,"onUpdate:modelValue":t[2]||(t[2]=t=>e.model.weapon=t),"custom-label":t=>e.weaponLocale[t]||t,options:e.sortedWeaponList,"allow-empty":!0},null,8,["modelValue","custom-label","options"]),(0,s._)("button",{onClick:t[3]||(t[3]=t=>e.model.weapon=void 0)},"X")]),(0,s._)("span",b,[(0,s.Wm)(l,{"options-limit":20,selectLabel:"",deselectLabel:"remove",placeholder:"Search player",modelValue:e.playerHighlighted,"onUpdate:modelValue":t[4]||(t[4]=t=>e.playerHighlighted=t),options:e.sortedPlayerList,"allow-empty":!0,"custom-label":e=>e?.username},null,8,["modelValue","options","custom-label"]),(0,s._)("button",{onClick:t[5]||(t[5]=t=>e.playerHighlighted=void 0)},"X")])]),(0,s._)("div",k,[(0,s.Wm)(o,{filters:e.filters,onHighlightPlayer:e.highlight_player,playerHighlighted:e.playerHighlighted?.id},null,8,["filters","onHighlightPlayer","playerHighlighted"]),(0,s.Wm)(p,{filters:e.filters,onHighlightPlayer:e.highlight_player,playerHighlighted:e.playerHighlighted?.id},null,8,["filters","onHighlightPlayer","playerHighlighted"]),(0,s.Wm)(d,{filters:{player:e.playerHighlighted?.id,...e.filters},playerHighlighted:e.playerHighlighted?.id},null,8,["filters","playerHighlighted"])])],64)}var L=a(7139);const C=e=>((0,s.dD)("data-v-037b66ea"),e=e(),(0,s.Cn)(),e),x={class:"playerHeaders"},S=C((()=>(0,s._)("span",null,null,-1))),H=["onClick"];function D(e,t,a,r,i,n){return(0,s.wg)(),(0,s.iD)("div",{class:"playerTable",onKeydown:t[6]||(t[6]=(...t)=>e.selectNextPlayer&&e.selectNextPlayer(...t)),tabindex:"0"},[(0,s._)("div",x,[S,(0,s._)("span",{onClick:t[0]||(t[0]=t=>e.updateSort("username")),class:(0,L.C_)("username"==e.sortingData.argument?"selected":"")},"Username",2),(0,s._)("span",{onClick:t[1]||(t[1]=t=>e.updateSort("kills")),class:(0,L.C_)("kills"==e.sortingData.argument?"selected":"")},"K",2),(0,s._)("span",{onClick:t[2]||(t[2]=t=>e.updateSort("deaths")),class:(0,L.C_)("deaths"==e.sortingData.argument?"selected":"")},"D",2),(0,s._)("span",{onClick:t[3]||(t[3]=t=>e.updateSort("k/d")),class:(0,L.C_)("k/d"==e.sortingData.argument?"selected":"")},"K/D",2),(0,s._)("span",{onClick:t[4]||(t[4]=t=>e.updateSort("max_distance")),class:(0,L.C_)("max_distance"==e.sortingData.argument?"selected":"")},"max distance",2),(0,s._)("span",{onClick:t[5]||(t[5]=t=>e.updateSort("avg_distance")),class:(0,L.C_)("avg_distance"==e.sortingData.argument?"selected":"")},"average distance",2)]),((0,s.wg)(!0),(0,s.iD)(s.HY,null,(0,s.Ko)(e.playerList,((t,a)=>((0,s.wg)(),(0,s.iD)("div",{class:(0,L.C_)("playerRow "+(t.id===e.$props.playerHighlighted?"selected":"")),key:t.id,onClick:a=>e.$emit("highlightPlayer",t.id),ref_for:!0,ref:"player:"+t.id},[(0,s._)("div",null,[(0,s._)("span",null,(0,L.zw)(a+1),1)]),(0,s._)("div",null,[(0,s._)("span",null,(0,L.zw)(t.username),1)]),(0,s._)("div",null,[(0,s._)("span",null,(0,L.zw)(t.kills),1)]),(0,s._)("div",null,[(0,s._)("span",null,(0,L.zw)(t.deaths),1)]),(0,s._)("div",null,[(0,s._)("span",null,(0,L.zw)(Math.round(t.kills/Math.max(1,t.deaths)*100)/100),1)]),(0,s._)("div",null,[(0,s._)("span",null,(0,L.zw)(t.max_distance),1)]),(0,s._)("div",null,[(0,s._)("span",null,(0,L.zw)(Math.round(100*(t.total_distance/t.kills||0))/100),1)])],10,H)))),128))],32)}var W=(0,s.aZ)({props:{filters:{type:Object,default:()=>({})},playerHighlighted:String},emits:["highlightPlayer"],data(){return{sortingData:{direction:-1,argument:"kills"},store:c()}},computed:{players(){const{player:e,...t}=this.filters,a=this.store.getPlayerList(t)?.value.data;return a||this.store.fetchPlayers(t).value.data},playerList(){if(!this.players)return[];let e=Object.entries(this.players).map((e=>({id:e[0],...e[1]})));if("username"===this.sortingData.argument){const t=new Intl.Collator("en",{numeric:!0,sensitivity:"base"});e.sort(((e,a)=>t.compare(e.username,a.username)))}else if("k/d"===this.sortingData.argument)e.sort(((e,t)=>e.kills/Math.max(1,e.deaths)-t.kills/Math.max(1,t.deaths)));else if("avg_distance"===this.sortingData.argument)e.sort(((e,t)=>(e.total_distance/e.kills||0)-(t.total_distance/t.kills||0)));else{const t=this.sortingData.argument;e.sort(((e,a)=>e[t]-a[t]))}return this.sortingData.direction<0&&e.reverse(),e=e.slice(0,500),e}},watch:{players:{handler(e){e&&(this.sortingData.direction*=-1)},immediate:!0},playerHighlighted(e){const t=this.$refs["player:"+e];t&&t[0]&&t[0].scrollIntoView({behavior:"smooth",block:"center"})}},updated(){const e=this.$refs["player:"+this.$props.playerHighlighted];e&&e[0]&&e[0].scrollIntoView({behavior:"smooth",block:"center"})},methods:{selectNextPlayer(e){const t={Home:-1/0,End:1/0,PageDown:100,PageUp:-100,ArrowUp:-1,ArrowDown:1,ArrowRight:10,ArrowLeft:-10};if(!this.$props.playerHighlighted)return;if(!Object.keys(t).includes(e.key))return;e.preventDefault();const a=this.playerList.findIndex((e=>e.id===this.$props.playerHighlighted));let r=a+t[e.key];r>=this.playerList.length&&(r=this.playerList.length-1),r<0&&(r=0),this.$emit("highlightPlayer",this.playerList[r].id)},updateSort(e){this.sortingData.argument===e?this.sortingData.direction*=-1:this.sortingData.direction=-1,this.sortingData.argument=e}}});const O=(0,g.Z)(W,[["render",D],["__scopeId","data-v-037b66ea"]]);var V=O;const $={class:"playerChart",ref:"container"};function I(e,t,a,r,i,n){const l=(0,s.up)("Scatter");return(0,s.wg)(),(0,s.iD)("div",$,[(0,s.Wm)(l,{data:e.chart,options:e.chartOptions},null,8,["data","options"])],512)}var M=a(3254),R=a(9152),j=a(1131),A=a(5866);M.kL.register(M.f$,M.od,M.jn,M.u,M.De,R.Z,j.Z);var E=(0,s.aZ)({name:"PlayerChart",props:{filters:Object,playerHighlighted:String},data:()=>({store:c(),refreshColors:0,playerData:[]}),emits:["highlightPlayer"],components:{Scatter:A.bp},mounted(){this.refreshColors++},computed:{playerList(){const e=this.store.getPlayerList(this.filters||{})?.value.data;if(!e)return Object.entries(this.store.fetchPlayers(this.filters||{}).value.data).map((e=>({id:e[0],...e[1]})));const t=Object.entries(e).map((e=>({id:e[0],...e[1]})));return t.sort(((e,t)=>t.kills-e.kills)),t.slice(0,200)},colors(){this.refreshColors;const e={};if(this.$refs.container){const t=getComputedStyle(this.$refs.container);e.fg=t.getPropertyValue("--foreground"),e.bg=t.getPropertyValue("--bg-color"),e.orange=t.getPropertyValue("--orange"),e.cyan=t.getPropertyValue("--cyan"),e.currentLine=t.getPropertyValue("--current-line")}else e.fg="#ffffff";return e},chart(){const e=this.playerList.findIndex((e=>e.id===this.$props.playerHighlighted)),t=this.colors.cyan,a=new Array(this.playerList.length).fill(t);a[e]=this.colors.orange;const r=a,s=new Array(this.playerList.length).fill(1);s[e]=20;const i=new Array(this.playerList.length).fill(4);i[e]=30;const n=new Array(this.playerList.length).fill("circle");return n[e]="crossRot",{datasets:[{label:"Players",labels:this.playerList.map((e=>e.id))||[],borderColor:a,backgroundColor:r,pointRadius:s,pointStyle:n,hoverRadius:i,data:this.playerList.map((e=>({y:e.kills,x:e.deaths})))}]}},chartStaticOptions(){return{responsive:!0,maintainAspectRatio:!1,animation:{duration:500},layout:{autoPadding:!1},scales:{y:{title:{text:"Kills",display:!0,color:this.colors.fg},ticks:{color:this.colors.fg}},x:{title:{text:"Deaths",display:!0,color:this.colors.fg},ticks:{color:this.colors.fg}}},onClick:(e,t)=>{this.$emit("highlightPlayer",t.length>0?this.playerList[t[0].index].id:void 0)},onHover:(e,t)=>{e.native.target&&(e.native.target.style.cursor=t[0]?"pointer":"default")}}},chartStaticPlugins(){let e=0,t=0;if(this.playerList){const a=Math.max(...this.playerList.map((e=>e.deaths))),r=Math.max(...this.playerList.map((e=>e.kills)));r>a?(e=a,t=a/r*r):(t=r,e=r/a*a)}return{tooltip:{callbacks:{label:e=>{let t;return t=this.playerList?this.playerList[e.dataIndex].username:e.dataset.labels[e.dataIndex],t+=" ("+e.parsed.y+" kills "+e.parsed.x+" deaths)",t}}},annotation:{annotations:{line:{type:"line",yMin:0,xMin:0,yMax:t,xMax:e,borderWidth:2,borderColor:this.colors.orange,borderDash:[1,5]}}},legend:{display:!1}}},chartOptions(){return this.$props.playerHighlighted,{...this.chartStaticOptions,plugins:{...this.chartStaticPlugins,datalabels:{formatter:(e,t)=>this.playerList[t.dataIndex].username,backgroundColor:e=>this.$props.playerHighlighted&&this.$props.playerHighlighted===this.playerList[e.dataIndex].id?this.colors.orange:null,borderColor:this.colors.fg,borderWidth:e=>this.$props.playerHighlighted&&this.$props.playerHighlighted===this.playerList[e.dataIndex].id?1:0,borderRadius:5,display:e=>this.$props.playerHighlighted&&this.$props.playerHighlighted===this.playerList[e.dataIndex].id?"true":"auto",align:-45,anchor:"end",clamp:!0,color:e=>this.$props.playerHighlighted&&this.$props.playerHighlighted===this.playerList[e.dataIndex].id?this.colors.bg:this.colors.fg}}}}}});const T=(0,g.Z)(E,[["render",I],["__scopeId","data-v-1e99590c"]]);var Z=T;const z={class:"weaponChart",ref:"container"};function N(e,t,a,r,i,n){const l=(0,s.up)("Doughnut");return(0,s.wg)(),(0,s.iD)("div",z,[(0,s.Wm)(l,{data:e.chart,options:e.chartOptions},null,8,["data","options"])],512)}var U=JSON.parse('{"rodeo_battery_removal":"Rodeo Battery Removal","human_execution":"Human Execution","melee_pilot_kunai":"Kunai Melee","execution":"Execution","mp_weapon_car":"CAR","mp_weapon_defender":"Charge Rifle","mp_weapon_doubletake":"Double Take","mp_weapon_epg":"EPG-1","mp_weapon_hemlok_smg":"Volt","mp_weapon_lstar":"L-STAR","mp_weapon_r97":"R-97","mp_weapon_rspn101":"R-201","mp_weapon_smart_pistol":"Smart Pistol","mp_weapon_sniper":"Kraber","mp_weapon_vinson":"Flatline","mp_weapon_autopistol":"RE-45 auto","mp_weapon_alternator_smg":"Alternator","mp_weapon_frag_grenade":"Frag Grenade","mp_weapon_g2":"G2","mp_weapon_lmg":"Spitfire","mp_weapon_smr":"Sidewinder SMR","mp_weapon_softball":"Softball","mp_weapon_thermite_grenade":"Firestar","pilot_emptyhanded":"Melee","mp_weapon_mastiff":"Mastiff","mp_weapon_mgl":"MGL","mp_weapon_rspn101_og":"R-101","mp_weapon_wingman":"Wingman","invalid":"invalid","mp_weapon_arc_launcher":"Thunderbolt","mp_weapon_dmr":"DMR","mp_weapon_grenade_electric_smoke":"Electric Smoke","mp_weapon_pulse_lmg":"Cold War","mp_weapon_satchel":"Satchel","mp_weapon_shotgun":"EVA-8 Auto","mp_weapon_shotgun_pistol":"Mozambique","mp_weapon_wingman_n":"Wingman Elite","mp_weapon_grenade_gravity":"Gravity Star","mp_weapon_grenade_sonar":"Pulse Blade","mp_weapon_rocket_launcher":"Archer","outOfBounds":"OutOfBounds","mind_crime":"Mind Crime","mp_weapon_esaw":"Devotion","fall":"Fall","mp_weapon_semipistol":"P2016","mp_weapon_grenade_emp":"Arc Grenade","mp_weapon_hemlok":"Hemlok","melee_pilot_emptyhanded":"Melee","phase_shift":"Phase Shift","damagedef_suicide":"Suicide","damagedef_titan_hotdrop":"Crushed by Titanfall","mp_titanweapon_arc_cannon":"Arc Cannon","mp_weapon_peacekraber":"Peacekraber","damagedef_crush":"Crushed","mp_titanweapon_brute4_quad_rocket":"Quad Rocket Launcher","mp_weapon_turretplasma":"Antititan Turret","mp_titanweapon_xo16_vanguard":"XO-16","mp_titanweapon_sticky_40mm":"40mm Cannon","mp_titanweapon_predator_cannon":"Predator Cannon","mp_titanweapon_leadwall":"Leadwall","mp_titanweapon_sniper":"Plasma Railgun","titan_execution":"Titan Execution","titan_explosion":"Titan Explosion","auto_titan_melee":"Autotitan Melee","mp_titanweapon_vortex_shield_ion":"Vortex Shield","mp_titanweapon_heat_shield":"Heat shield","bubble_shield":"Bubble Shield","mp_titancore_salvo_core":"Salvo Core","mp_titancore_flame_wave":"Flame Wave","mp_titanweapon_flightcore_rockets":"Flight Core","mp_titancore_laser_cannon":"Laser Cannon","mp_titancore_flame_wave_secondary":"Scorched Earth","mp_titanweapon_flame_wall":"Flame Wall","mp_titanweapon_arc_wave":"Arc Wave"}');M.kL.register(M.qi,M.u,M.De,j.Z);var F=(0,s.aZ)({name:"PlayerChart",props:{filters:Object,playerHighlighted:String},emits:["highlightPlayer"],components:{Doughnut:A.$I},mounted(){this.refreshColors++},data:()=>({store:c(),refreshColors:0}),computed:{colors(){this.refreshColors;const e={};if(this.$refs.container){const t=getComputedStyle(this.$refs.container);e.fg=t.getPropertyValue("--foreground"),e.bg=t.getPropertyValue("--bg-color"),e.orange=t.getPropertyValue("--orange"),e.cyan=t.getPropertyValue("--cyan"),e.yellow=t.getPropertyValue("--yellow"),e.green=t.getPropertyValue("--green"),e.purple=t.getPropertyValue("--purple"),e.red=t.getPropertyValue("--red"),e.pink=t.getPropertyValue("--pink"),e.currentLine=t.getPropertyValue("--current-line")}else e.fg="#ffffff";return e},chart(){const e=["cyan","green","orange","pink","purple","red","yellow"],t={datasets:[{label:"Weapons",labels:this.sortedWeaponList||[],borderColor:()=>this.colors.fg,backgroundColor:t=>this.colors[e[3*t.dataIndex%e.length]],data:[]}]};return this.sortedWeaponList?(t.datasets[0].data=this.sortedWeaponList.map((e=>this.weapons?this.weapons[e].kills:0)),t):t},chartOptions(){this.$props.playerHighlighted;const e={responsive:!0,maintainAspectRatio:!0,animation:{duration:500},layout:{autoPadding:!1},plugins:{datalabels:{formatter:(e,t)=>{const a=this.sortedWeaponList[t.dataIndex];return U[a]||a},backgroundColor:e=>e.dataset.backgroundColor(e),borderColor:this.colors.fg,borderRadius:25,borderWidth:2,color:this.colors.bg,display:e=>e.dataIndex===e.dataset.labels.length-1||"auto",padding:6},tooltip:{callbacks:{label:e=>{let t;return t=this.sortedWeaponList?this.sortedWeaponList[e.dataIndex]:e.dataset.labels[e.dataIndex],t+=" ("+this.weapons[t].kills+" kills)",t}}}}};return e},weapons(){const{weapon:e,...t}=this.filters||{},a=this.store.getWeaponList(t)?.value.data;return a||this.store.fetchWeapons(t).value.data},sortedWeaponList(){if(!this.weapons)return[];const e=Object.keys(this.weapons);return e.sort(((e,t)=>Number(this.weapons[e].kills)Number(this.weapons[t].kills)?1:0)),e}}});const G=(0,g.Z)(F,[["render",N],["__scopeId","data-v-53c5074f"]]);var K=G,B=a(6368),q=(0,s.aZ)({name:"PlayerView",components:{VueMultiselect:B.ZP,PlayerList:V,PlayerChart:Z,WeaponChart:K},data(){return{model:{server:void 0,weapon:void 0},filters:{},store:c(),playerHighlighted:void 0,weaponLocale:U}},computed:{servers(){const{server:e,player:t,...a}=this.filters,r=this.store.getServerList(a)?.value.data;return r||this.store.fetchServers(a).value.data},groupedServers(){const e=[];return Object.entries(this.servers).forEach((t=>{e.find((e=>e.id===t[1].host+"sfdsdfsd"))||e.push({id:t[1].host+"sfdsdfsd",servers:[]}),e.find((e=>e.id===t[1].host+"sfdsdfsd"))?.servers.push({name:t[0],...t[1]})})),e},weapons(){const{weapon:e,player:t,...a}=this.filters,r=this.store.getWeaponList(a)?.value.data;return r||this.store.fetchWeapons(a).value.data},players(){const{player:e,...t}=this.filters,a=this.store.getPlayerList(t)?.value.data;return a||this.store.fetchPlayers(t).value.data},sortedWeaponList(){if(!this.weapons)return[];const e=Object.keys(this.weapons);return e.sort()},sortedServerList(){if(!this.servers)return[];const e=Object.keys(this.servers);return e.sort()},sortedPlayerList(){if(!this.players)return[];const e=Object.entries(this.players).map((e=>({id:e[0],...e[1]})));return e.sort(((e,t)=>e.usernamet.username?1:0))}},watch:{model:{handler(e){this.filters.server=e.server?.name,this.filters.weapon=e.weapon},deep:!0}},methods:{highlight_player(e){const t=this.players[e];this.playerHighlighted=t?{id:e,...t}:void 0}}});const X=(0,g.Z)(q,[["render",P],["__scopeId","data-v-639162c3"]]);var Y=X;const Q=[{path:"/",name:"home",component:Y}],J=(0,f.p7)({history:(0,f.PO)("/ToneAPI_webclient/"),routes:Q});var ee=J;const te=(0,l.WB)();(0,r.ri)(_).use(te).use(ee).mount("#app")}},t={};function a(r){var s=t[r];if(void 0!==s)return s.exports;var i=t[r]={exports:{}};return e[r](i,i.exports,a),i.exports}a.m=e,function(){var e=[];a.O=function(t,r,s,i){if(!r){var n=1/0;for(d=0;d=i)&&Object.keys(a.O).every((function(e){return a.O[e](r[o])}))?r.splice(o--,1):(l=!1,i0&&e[d-1][2]>i;d--)e[d]=e[d-1];e[d]=[r,s,i]}}(),function(){a.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return a.d(t,{a:t}),t}}(),function(){a.d=function(e,t){for(var r in t)a.o(t,r)&&!a.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})}}(),function(){a.g=function(){if("object"===typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"===typeof window)return window}}()}(),function(){a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}}(),function(){var e={143:0};a.O.j=function(t){return 0===e[t]};var t=function(t,r){var s,i,n=r[0],l=r[1],o=r[2],p=0;if(n.some((function(t){return 0!==e[t]}))){for(s in l)a.o(l,s)&&(a.m[s]=l[s]);if(o)var d=o(a)}for(t&&t(r);pTONE API
\", 4)\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_router_link = _resolveComponent(\"router-link\")!\n const _component_router_view = _resolveComponent(\"router-view\")!\n\n return (_openBlock(), _createElementBlock(_Fragment, null, [\n _createElementVNode(\"header\", null, [\n _createElementVNode(\"nav\", null, [\n _hoisted_1,\n _createVNode(_component_router_link, {\n to: \"/\",\n class: \"navbar-element\"\n }, {\n default: _withCtx(() => [\n _createTextVNode(\"Players\")\n ]),\n _: 1\n })\n ])\n ]),\n _createVNode(_component_router_view)\n ], 64))\n}","import { defineStore } from 'pinia'\r\nimport * as assert from 'assert'\r\nimport { Ref, ref } from 'vue'\r\n\r\nexport interface Filters {\r\n server?: string;\r\n player?: string;\r\n weapon?: string;\r\n host?: string;\r\n map?: string;\r\n gamemode?: string;\r\n}\r\n\r\nfunction removeNullEntries (a: Filters) {\r\n return Object.fromEntries(\r\n Object.entries(a).filter((e) => e[1] !== undefined && e[1] !== null)\r\n )\r\n}\r\nfunction objectEqual (a: Filters, b: Filters) {\r\n try {\r\n a = removeNullEntries(a)\r\n b = removeNullEntries(b)\r\n assert.deepStrictEqual(a, b)\r\n return true\r\n } catch {\r\n return false\r\n }\r\n}\r\n\r\nexport interface Kill {\r\n deaths: number;\r\n kills: number;\r\n // eslint-disable-next-line camelcase\r\n max_distance: number;\r\n // eslint-disable-next-line camelcase\r\n total_distance: number;\r\n}\r\nexport interface KillData {\r\n filter: Filters;\r\n data: { [key: string]: T };\r\n}\r\n\r\nexport interface Player extends Kill {\r\n username: string;\r\n // eslint-disable-next-line camelcase\r\n // deaths_while_equipped?: number;\r\n}\r\n\r\nexport interface Weapon extends Kill {\r\n // eslint-disable-next-line camelcase\r\n deaths_while_equipped: number;\r\n}\r\n\r\nexport interface Server extends Kill {\r\n host: number;\r\n}\r\n\r\n// define your typings for the store state\r\nexport interface State {\r\n servers: Ref>[];\r\n players: Ref>[];\r\n weapons: Ref>[];\r\n maps: Ref>[];\r\n gamemodes: Ref>[];\r\n hosts: { [key: number]: string };\r\n}\r\n\r\nexport const useKillStore = defineStore('kill', {\r\n state: (): State => ({\r\n servers: [],\r\n players: [],\r\n weapons: [],\r\n maps: [],\r\n gamemodes: [],\r\n hosts: {}\r\n }),\r\n getters: {\r\n getPlayerList: (state) => (filters: Filters) => {\r\n return state.players.find((e) => objectEqual(e.value.filter, filters))\r\n },\r\n getWeaponList: (state) => (filters: Filters) =>\r\n state.weapons.find((e) => objectEqual(e.value.filter, filters)),\r\n getServerList: (state) => (filters: Filters) =>\r\n state.servers.find((e) => objectEqual(e.value.filter, filters))\r\n },\r\n actions: {\r\n fetchPlayers (filter: Filters) {\r\n filter = removeNullEntries(filter)\r\n let entry = this.players.find((e) => objectEqual(e.value.filter, filter))\r\n if (entry === undefined) {\r\n entry = ref({ filter, data: {} })\r\n this.players.push(entry)\r\n }\r\n fetch(\r\n 'https://tone.sleepycat.date/v2/client/players?' +\r\n new URLSearchParams(filter as Record)\r\n ).then(async response => {\r\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\r\n entry!.value.data = await response.json()\r\n })\r\n return entry\r\n },\r\n fetchWeapons (filter: Filters) {\r\n filter = removeNullEntries(filter)\r\n let entry = this.weapons.find((e) => objectEqual(e.value.filter, filter))\r\n if (!entry) {\r\n entry = ref({ filter, data: {} })\r\n this.weapons.push(entry)\r\n }\r\n\r\n fetch(\r\n 'https://tone.sleepycat.date/v2/client/weapons?' +\r\n new URLSearchParams(filter as Record)\r\n ).then(async response => {\r\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\r\n entry!.value.data = await response.json()\r\n })\r\n return entry\r\n },\r\n fetchServers (filter: Filters) {\r\n filter = removeNullEntries(filter)\r\n let entry = this.servers.find((e) => objectEqual(e.value.filter, filter))\r\n if (!entry) {\r\n entry = ref({ filter, data: {} })\r\n this.servers.push(entry)\r\n }\r\n fetch(\r\n 'https://tone.sleepycat.date/v2/client/servers?' +\r\n new URLSearchParams(filter as Record)\r\n ).then(async response => {\r\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\r\n entry!.value.data = await response.json()\r\n })\r\n return entry\r\n }\r\n }\r\n})\r\n","\r\nimport { Player, Weapon, Server, useKillStore } from '@/stores/kill'\r\nimport { defineComponent } from 'vue'\r\n\r\nexport default defineComponent({\r\n setup (props, ctx) {\r\n const store = useKillStore()\r\n store.fetchPlayers({})\r\n store.fetchServers({})\r\n store.fetchWeapons({})\r\n }\r\n})\r\n","import { render } from \"./App.vue?vue&type=template&id=a4a5fcd4&ts=true\"\nimport script from \"./App.vue?vue&type=script&lang=ts\"\nexport * from \"./App.vue?vue&type=script&lang=ts\"\n\nimport \"./App.vue?vue&type=style&index=0&id=a4a5fcd4&lang=css\"\n\nimport exportComponent from \"C:\\\\Users\\\\legon\\\\Documents\\\\Code\\\\Tone\\\\ToneAPI_webclient\\\\node_modules\\\\vue-loader\\\\dist\\\\exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render]])\n\nexport default __exports__","import { resolveComponent as _resolveComponent, createVNode as _createVNode, createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-639162c3\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = { id: \"filters\" }\nconst _hoisted_2 = { class: \"multiselect-wrapper\" }\nconst _hoisted_3 = { class: \"multiselect-wrapper\" }\nconst _hoisted_4 = { class: \"multiselect-wrapper\" }\nconst _hoisted_5 = { id: \"playerView\" }\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_VueMultiselect = _resolveComponent(\"VueMultiselect\")!\n const _component_PlayerList = _resolveComponent(\"PlayerList\")!\n const _component_PlayerChart = _resolveComponent(\"PlayerChart\")!\n const _component_WeaponChart = _resolveComponent(\"WeaponChart\")!\n\n return (_openBlock(), _createElementBlock(_Fragment, null, [\n _createElementVNode(\"div\", _hoisted_1, [\n _createElementVNode(\"span\", _hoisted_2, [\n _createVNode(_component_VueMultiselect, {\n selectLabel: \"\",\n deselectLabel: \"remove\",\n placeholder: \"Select server\",\n modelValue: _ctx.model.server,\n \"onUpdate:modelValue\": _cache[0] || (_cache[0] = ($event: any) => ((_ctx.model.server) = $event)),\n options: _ctx.groupedServers,\n \"group-values\": \"servers\",\n group_label: \"id\",\n \"group-select\": false,\n \"allow-empty\": true,\n multiple: false,\n \"custom-label\": ((e) => e.name),\n \"track-by\": \"name\",\n label: \"name\"\n }, null, 8, [\"modelValue\", \"options\", \"custom-label\"]),\n _createElementVNode(\"button\", {\n onClick: _cache[1] || (_cache[1] = ($event: any) => (_ctx.model.server = undefined))\n }, \"X\")\n ]),\n _createElementVNode(\"span\", _hoisted_3, [\n _createVNode(_component_VueMultiselect, {\n selectLabel: \"\",\n deselectLabel: \"remove\",\n placeholder: \"Select weapon\",\n modelValue: _ctx.model.weapon,\n \"onUpdate:modelValue\": _cache[2] || (_cache[2] = ($event: any) => ((_ctx.model.weapon) = $event)),\n \"custom-label\": ((e) => _ctx.weaponLocale[e] || e),\n options: _ctx.sortedWeaponList,\n \"allow-empty\": true\n }, null, 8, [\"modelValue\", \"custom-label\", \"options\"]),\n _createElementVNode(\"button\", {\n onClick: _cache[3] || (_cache[3] = ($event: any) => (_ctx.model.weapon = undefined))\n }, \"X\")\n ]),\n _createElementVNode(\"span\", _hoisted_4, [\n _createVNode(_component_VueMultiselect, {\n \"options-limit\": 20,\n selectLabel: \"\",\n deselectLabel: \"remove\",\n placeholder: \"Search player\",\n modelValue: _ctx.playerHighlighted,\n \"onUpdate:modelValue\": _cache[4] || (_cache[4] = ($event: any) => ((_ctx.playerHighlighted) = $event)),\n options: _ctx.sortedPlayerList,\n \"allow-empty\": true,\n \"custom-label\": ((e) => e?.username)\n }, null, 8, [\"modelValue\", \"options\", \"custom-label\"]),\n _createElementVNode(\"button\", {\n onClick: _cache[5] || (_cache[5] = ($event: any) => (_ctx.playerHighlighted = undefined))\n }, \"X\")\n ])\n ]),\n _createElementVNode(\"div\", _hoisted_5, [\n _createVNode(_component_PlayerList, {\n filters: _ctx.filters,\n onHighlightPlayer: _ctx.highlight_player,\n playerHighlighted: _ctx.playerHighlighted?.id\n }, null, 8, [\"filters\", \"onHighlightPlayer\", \"playerHighlighted\"]),\n _createVNode(_component_PlayerChart, {\n filters: _ctx.filters,\n onHighlightPlayer: _ctx.highlight_player,\n playerHighlighted: _ctx.playerHighlighted?.id\n }, null, 8, [\"filters\", \"onHighlightPlayer\", \"playerHighlighted\"]),\n _createVNode(_component_WeaponChart, {\n filters: { player: _ctx.playerHighlighted?.id, ..._ctx.filters },\n playerHighlighted: _ctx.playerHighlighted?.id\n }, null, 8, [\"filters\", \"playerHighlighted\"])\n ])\n ], 64))\n}","import { createElementVNode as _createElementVNode, normalizeClass as _normalizeClass, renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, toDisplayString as _toDisplayString, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-037b66ea\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = { class: \"playerHeaders\" }\nconst _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"span\", null, null, -1))\nconst _hoisted_3 = [\"onClick\"]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"div\", {\n class: \"playerTable\",\n onKeydown: _cache[6] || (_cache[6] = \n//@ts-ignore\n(...args) => (_ctx.selectNextPlayer && _ctx.selectNextPlayer(...args))),\n tabindex: \"0\"\n }, [\n _createElementVNode(\"div\", _hoisted_1, [\n _hoisted_2,\n _createElementVNode(\"span\", {\n onClick: _cache[0] || (_cache[0] = ($event: any) => (_ctx.updateSort('username'))),\n class: _normalizeClass(_ctx.sortingData.argument == 'username' ? 'selected' : '')\n }, \"Username\", 2),\n _createElementVNode(\"span\", {\n onClick: _cache[1] || (_cache[1] = ($event: any) => (_ctx.updateSort('kills'))),\n class: _normalizeClass(_ctx.sortingData.argument == 'kills' ? 'selected' : '')\n }, \"K\", 2),\n _createElementVNode(\"span\", {\n onClick: _cache[2] || (_cache[2] = ($event: any) => (_ctx.updateSort('deaths'))),\n class: _normalizeClass(_ctx.sortingData.argument == 'deaths' ? 'selected' : '')\n }, \"D\", 2),\n _createElementVNode(\"span\", {\n onClick: _cache[3] || (_cache[3] = ($event: any) => (_ctx.updateSort('k/d'))),\n class: _normalizeClass(_ctx.sortingData.argument == 'k/d' ? 'selected' : '')\n }, \"K/D\", 2),\n _createElementVNode(\"span\", {\n onClick: _cache[4] || (_cache[4] = ($event: any) => (_ctx.updateSort('max_distance'))),\n class: _normalizeClass(_ctx.sortingData.argument == 'max_distance' ? 'selected' : '')\n }, \"max distance\", 2),\n _createElementVNode(\"span\", {\n onClick: _cache[5] || (_cache[5] = ($event: any) => (_ctx.updateSort('avg_distance'))),\n class: _normalizeClass(_ctx.sortingData.argument == 'avg_distance' ? 'selected' : '')\n }, \"average distance\", 2)\n ]),\n (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.playerList, (player, index) => {\n return (_openBlock(), _createElementBlock(\"div\", {\n class: _normalizeClass('playerRow ' + (player.id === _ctx.$props.playerHighlighted ? 'selected' : '')),\n key: player.id,\n onClick: ($event: any) => (_ctx.$emit('highlightPlayer', player.id)),\n ref_for: true,\n ref: `player:` + player.id\n }, [\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(index+1), 1)\n ]),\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(player.username), 1)\n ]),\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(player.kills), 1)\n ]),\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(player.deaths), 1)\n ]),\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(Math.round(player.kills / Math.max(1, player.deaths) * 100) / 100), 1)\n ]),\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(player.max_distance), 1)\n ]),\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(Math.round(((player.total_distance / player.kills) || 0) * 100) / 100), 1)\n ])\n ], 10, _hoisted_3))\n }), 128))\n ], 32))\n}","\r\nimport { defineComponent, PropType } from 'vue'\r\nimport { useKillStore, Player, Filters } from '@/stores/kill'\r\n\r\nexport default defineComponent({\r\n props: {\r\n filters: { type: Object as PropType, default: () => ({}) },\r\n playerHighlighted: String\r\n },\r\n emits: ['highlightPlayer'],\r\n data () {\r\n return {\r\n sortingData: { direction: -1, argument: 'kills' as keyof Player | 'k/d' | 'avg_distance' },\r\n store: useKillStore()\r\n }\r\n },\r\n computed: {\r\n players (): { [key: string]: Player } {\r\n const { player: _, ...withoutPlayer } = this.filters\r\n const data = this.store.getPlayerList(withoutPlayer)?.value.data\r\n if (!data) return this.store.fetchPlayers(withoutPlayer).value.data\r\n return data\r\n },\r\n playerList ():(Player & {id:string})[] {\r\n if (!this.players) return []\r\n let players = Object.entries(this.players).map(e => ({ id: e[0], ...e[1] }))\r\n\r\n if (this.sortingData.argument === 'username') {\r\n const collator = new Intl.Collator('en', { numeric: true, sensitivity: 'base' })\r\n players.sort((a: Player, b: Player) => {\r\n return collator.compare(a.username, b.username)\r\n })\r\n } else if (this.sortingData.argument === 'k/d') {\r\n players.sort((a: Player, b: Player) => {\r\n return a.kills / Math.max(1, a.deaths) - b.kills / Math.max(1, b.deaths)\r\n })\r\n } else if (this.sortingData.argument === 'avg_distance') {\r\n players.sort((a: Player, b: Player) => {\r\n return ((a.total_distance / a.kills) || 0) - ((b.total_distance / b.kills) || 0)\r\n })\r\n } else {\r\n const argument = this.sortingData.argument\r\n players.sort((a: Player, b: Player) => {\r\n return a[argument] - b[argument]\r\n })\r\n }\r\n\r\n if (this.sortingData.direction < 0) {\r\n players.reverse()\r\n }\r\n\r\n players = players.slice(0, 500)\r\n return players\r\n }\r\n },\r\n watch: {\r\n players: {\r\n handler (newval: { [key: string]: Player }): void {\r\n if (!newval) return\r\n this.sortingData.direction *= -1\r\n },\r\n immediate: true\r\n },\r\n playerHighlighted (newval) {\r\n const newElement = this.$refs['player:' + newval] as HTMLElement[]\r\n if (newElement && newElement[0]) { newElement[0].scrollIntoView({ behavior: 'smooth', block: 'center' }) }\r\n }\r\n },\r\n updated () {\r\n const element = this.$refs['player:' + this.$props.playerHighlighted] as HTMLElement[]\r\n if (!element || !element[0]) return\r\n element[0].scrollIntoView({ behavior: 'smooth', block: 'center' })\r\n },\r\n methods: {\r\n selectNextPlayer (e: KeyboardEvent) {\r\n const values = {\r\n Home: -Infinity,\r\n End: Infinity,\r\n PageDown: 100,\r\n PageUp: -100,\r\n ArrowUp: -1,\r\n ArrowDown: 1,\r\n ArrowRight: 10,\r\n ArrowLeft: -10\r\n } as { [key: string]: number }\r\n if (!this.$props.playerHighlighted) return\r\n if (!Object.keys(values).includes(e.key)) return\r\n e.preventDefault()\r\n const index = this.playerList.findIndex(e => e.id === this.$props.playerHighlighted)\r\n let nextIndex = (index + values[e.key])\r\n if (nextIndex >= this.playerList.length) nextIndex = this.playerList.length - 1\r\n if (nextIndex < 0) nextIndex = 0\r\n this.$emit('highlightPlayer', this.playerList[nextIndex].id)\r\n },\r\n updateSort (argument:string) {\r\n if (this.sortingData.argument === argument) {\r\n this.sortingData.direction *= -1\r\n } else {\r\n this.sortingData.direction = -1\r\n }\r\n this.sortingData.argument = argument as typeof this.sortingData.argument\r\n }\r\n }\r\n\r\n})\r\n","import { render } from \"./PlayerList.vue?vue&type=template&id=037b66ea&scoped=true&ts=true\"\nimport script from \"./PlayerList.vue?vue&type=script&lang=ts\"\nexport * from \"./PlayerList.vue?vue&type=script&lang=ts\"\n\nimport \"./PlayerList.vue?vue&type=style&index=0&id=037b66ea&scoped=true&lang=css\"\n\nimport exportComponent from \"C:\\\\Users\\\\legon\\\\Documents\\\\Code\\\\Tone\\\\ToneAPI_webclient\\\\node_modules\\\\vue-loader\\\\dist\\\\exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-037b66ea\"]])\n\nexport default __exports__","import { resolveComponent as _resolveComponent, createVNode as _createVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-1e99590c\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = {\n class: \"playerChart\",\n ref: \"container\"\n}\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_Scatter = _resolveComponent(\"Scatter\")!\n\n return (_openBlock(), _createElementBlock(\"div\", _hoisted_1, [\n _createVNode(_component_Scatter, {\n data: _ctx.chart,\n options: _ctx.chartOptions\n }, null, 8, [\"data\", \"options\"])\n ], 512))\n}","\r\nimport {\r\n Chart as ChartJS,\r\n LinearScale,\r\n PointElement,\r\n LineElement,\r\n Tooltip,\r\n Legend,\r\n CoreChartOptions,\r\n PluginChartOptions,\r\n ScaleChartOptions\r\n} from 'chart.js'\r\nimport annotationPlugin, { AnnotationPluginOptions } from 'chartjs-plugin-annotation'\r\nimport dataLabel from 'chartjs-plugin-datalabels'\r\nimport { useKillStore, Player, Filters } from '@/stores/kill'\r\n\r\nimport { Scatter } from 'vue-chartjs'\r\nimport { defineComponent, PropType } from 'vue'\r\nimport { ChartEvent } from 'chart.js/dist/core/core.plugins'\r\nimport { _DeepPartialObject } from 'chart.js/dist/types/utils'\r\n\r\nChartJS.register(LinearScale, PointElement, LineElement, Tooltip, Legend, annotationPlugin, dataLabel)\r\n\r\nexport default defineComponent({\r\n name: 'PlayerChart',\r\n props: {\r\n filters: Object as PropType,\r\n playerHighlighted: String\r\n },\r\n data: () => {\r\n return {\r\n store: useKillStore(),\r\n refreshColors: 0,\r\n playerData: []\r\n }\r\n },\r\n emits: ['highlightPlayer'],\r\n components: {\r\n Scatter\r\n },\r\n mounted () {\r\n this.refreshColors++\r\n },\r\n computed: {\r\n playerList (): (Player & {id:string})[] {\r\n const data = this.store.getPlayerList(this.filters || {})?.value.data\r\n if (!data) return Object.entries(this.store.fetchPlayers(this.filters || {}).value.data).map(e => ({ id: e[0], ...e[1] }))\r\n const cut = Object.entries(data).map(e => ({ id: e[0], ...e[1] }))\r\n cut.sort((a, b) => {\r\n return b.kills - a.kills\r\n })\r\n return cut.slice(0, 200)\r\n },\r\n colors () {\r\n // eslint-disable-next-line no-unused-expressions\r\n this.refreshColors\r\n const colors = {} as { [key: string]: string }\r\n if (this.$refs.container) {\r\n const style = getComputedStyle(this.$refs.container as Element)\r\n colors.fg = style.getPropertyValue('--foreground')\r\n colors.bg = style.getPropertyValue('--bg-color')\r\n colors.orange = style.getPropertyValue('--orange')\r\n colors.cyan = style.getPropertyValue('--cyan')\r\n colors.currentLine = style.getPropertyValue('--current-line')\r\n } else {\r\n colors.fg = '#ffffff'\r\n }\r\n return colors\r\n },\r\n\r\n chart () {\r\n const playerIndex = this.playerList.findIndex(e => e.id === this.$props.playerHighlighted)\r\n const defaultColor = this.colors.cyan\r\n const borderColor = new Array(this.playerList.length).fill(defaultColor)\r\n borderColor[playerIndex] = this.colors.orange\r\n const backgroundColor = borderColor\r\n const pointRadius = new Array(this.playerList.length).fill(1)\r\n pointRadius[playerIndex] = 20\r\n const hoverRadius = new Array(this.playerList.length).fill(4)\r\n hoverRadius[playerIndex] = 30\r\n const pointStyle = new Array(this.playerList.length).fill('circle')\r\n pointStyle[playerIndex] = 'crossRot'\r\n return {\r\n datasets: [\r\n {\r\n label: 'Players',\r\n labels: this.playerList.map(e => e.id) || [] as string[],\r\n borderColor,\r\n backgroundColor,\r\n pointRadius,\r\n pointStyle,\r\n hoverRadius,\r\n data: this.playerList.map((player) => ({ y: player.kills, x: player.deaths }))\r\n }\r\n ]\r\n }\r\n },\r\n chartStaticOptions () {\r\n return {\r\n responsive: true,\r\n maintainAspectRatio: false,\r\n animation: { duration: 500 },\r\n layout: { autoPadding: false },\r\n scales: {\r\n y: {\r\n title: {\r\n text: 'Kills',\r\n display: true,\r\n color: this.colors.fg\r\n },\r\n ticks: {\r\n color: this.colors.fg\r\n }\r\n },\r\n x: {\r\n title: {\r\n text: 'Deaths',\r\n display: true,\r\n color: this.colors.fg\r\n },\r\n ticks: {\r\n color: this.colors.fg\r\n }\r\n }\r\n },\r\n onClick: (e: ChartEvent, element: any) => {\r\n this.$emit('highlightPlayer', element.length > 0 ? this.playerList[element[0].index].id : undefined)\r\n },\r\n onHover: (e: any, element: any) => {\r\n if (!e.native.target) return\r\n (e.native.target as HTMLElement).style.cursor = element[0] ? 'pointer' : 'default'\r\n }\r\n }\r\n },\r\n chartStaticPlugins () {\r\n let endX = 0\r\n let endY = 0\r\n if (this.playerList) {\r\n const maxX = Math.max(...this.playerList.map(e => e.deaths))\r\n const maxY = Math.max(...this.playerList.map(e => e.kills))\r\n if (maxY > maxX) {\r\n endX = maxX\r\n endY = (maxX / maxY) * maxY\r\n } else {\r\n endY = maxY\r\n endX = (maxY / maxX) * maxX\r\n }\r\n }\r\n return {\r\n tooltip: {\r\n callbacks: {\r\n label: (ctx: any) => {\r\n let label: string\r\n if (!this.playerList) {\r\n label = ctx.dataset.labels[ctx.dataIndex]\r\n } else {\r\n label = this.playerList[ctx.dataIndex].username\r\n }\r\n label += ' (' + ctx.parsed.y + ' kills ' + ctx.parsed.x + ' deaths)'\r\n return label\r\n }\r\n }\r\n },\r\n annotation: {\r\n annotations: {\r\n line: {\r\n type: 'line',\r\n yMin: 0,\r\n xMin: 0,\r\n yMax: endY,\r\n xMax: endX,\r\n borderWidth: 2,\r\n borderColor: this.colors.orange,\r\n borderDash: [1, 5]\r\n }\r\n }\r\n } as _DeepPartialObject,\r\n legend: { display: false }\r\n }\r\n },\r\n chartOptions (): _DeepPartialObject & PluginChartOptions<'scatter'> & ScaleChartOptions<'scatter'>> {\r\n // eslint-disable-next-line no-unused-expressions\r\n this.$props.playerHighlighted\r\n return {\r\n ...this.chartStaticOptions,\r\n plugins: {\r\n ...this.chartStaticPlugins,\r\n datalabels: {\r\n formatter: (value: any, context: any) => {\r\n return this.playerList[context.dataIndex].username\r\n },\r\n backgroundColor: (context: any) => (this.$props.playerHighlighted && this.$props.playerHighlighted === this.playerList[context.dataIndex].id) ? this.colors.orange : null,\r\n borderColor: this.colors.fg,\r\n borderWidth: (context: any) => (this.$props.playerHighlighted && this.$props.playerHighlighted === this.playerList[context.dataIndex].id) ? 1 : 0,\r\n borderRadius: 5,\r\n display: (context: any) => (this.$props.playerHighlighted && this.$props.playerHighlighted === this.playerList[context.dataIndex].id) ? 'true' : 'auto',\r\n align: -45,\r\n anchor: 'end',\r\n clamp: true,\r\n color: (context: any) => (this.$props.playerHighlighted && this.$props.playerHighlighted === this.playerList[context.dataIndex].id) ? this.colors.bg : this.colors.fg\r\n }\r\n }\r\n }\r\n }\r\n }\r\n})\r\n","import { render } from \"./PlayerChart.vue?vue&type=template&id=1e99590c&scoped=true&ts=true\"\nimport script from \"./PlayerChart.vue?vue&type=script&lang=ts\"\nexport * from \"./PlayerChart.vue?vue&type=script&lang=ts\"\n\nimport \"./PlayerChart.vue?vue&type=style&index=0&id=1e99590c&scoped=true&lang=css\"\n\nimport exportComponent from \"C:\\\\Users\\\\legon\\\\Documents\\\\Code\\\\Tone\\\\ToneAPI_webclient\\\\node_modules\\\\vue-loader\\\\dist\\\\exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-1e99590c\"]])\n\nexport default __exports__","import { resolveComponent as _resolveComponent, createVNode as _createVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-53c5074f\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = {\n class: \"weaponChart\",\n ref: \"container\"\n}\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_Doughnut = _resolveComponent(\"Doughnut\")!\n\n return (_openBlock(), _createElementBlock(\"div\", _hoisted_1, [\n _createVNode(_component_Doughnut, {\n data: _ctx.chart,\n options: _ctx.chartOptions\n }, null, 8, [\"data\", \"options\"])\n ], 512))\n}","\r\nimport { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'\r\nimport dataLabel from 'chartjs-plugin-datalabels'\r\nimport { Weapon, Filters, useKillStore } from '@/stores/kill'\r\nimport { Doughnut } from 'vue-chartjs'\r\nimport { defineComponent, PropType } from 'vue'\r\nimport weapons from '../stores/weapons.json'\r\n\r\nChartJS.register(ArcElement, Tooltip, Legend, dataLabel)\r\n\r\nexport default defineComponent({\r\n name: 'PlayerChart',\r\n props: {\r\n filters: Object as PropType,\r\n playerHighlighted: String\r\n },\r\n emits: ['highlightPlayer'],\r\n components: {\r\n Doughnut\r\n },\r\n mounted () {\r\n this.refreshColors++\r\n },\r\n data: () => {\r\n return {\r\n store: useKillStore(),\r\n refreshColors: 0\r\n }\r\n },\r\n computed: {\r\n colors () {\r\n // eslint-disable-next-line no-unused-expressions\r\n this.refreshColors\r\n const colors = {} as { [key: string]: string }\r\n if (this.$refs.container) {\r\n const style = getComputedStyle(this.$refs.container as Element)\r\n colors.fg = style.getPropertyValue('--foreground')\r\n colors.bg = style.getPropertyValue('--bg-color')\r\n colors.orange = style.getPropertyValue('--orange')\r\n colors.cyan = style.getPropertyValue('--cyan')\r\n colors.yellow = style.getPropertyValue('--yellow')\r\n colors.green = style.getPropertyValue('--green')\r\n colors.purple = style.getPropertyValue('--purple')\r\n colors.red = style.getPropertyValue('--red')\r\n colors.pink = style.getPropertyValue('--pink')\r\n colors.currentLine = style.getPropertyValue('--current-line')\r\n } else {\r\n colors.fg = '#ffffff'\r\n }\r\n return colors\r\n },\r\n chart () {\r\n const colors = [\r\n 'cyan',\r\n 'green',\r\n 'orange',\r\n 'pink',\r\n 'purple',\r\n 'red',\r\n 'yellow'\r\n ]\r\n const chartData = {\r\n datasets: [\r\n {\r\n label: 'Weapons',\r\n labels: this.sortedWeaponList || ([] as string[]),\r\n borderColor: () => this.colors.fg,\r\n backgroundColor: (context: any) => {\r\n return this.colors[\r\n colors[(context.dataIndex * 3) % colors.length]\r\n ]\r\n },\r\n data: [] as number[]\r\n }\r\n ]\r\n }\r\n if (!this.sortedWeaponList) {\r\n return chartData\r\n }\r\n chartData.datasets[0].data = this.sortedWeaponList.map((e) => {\r\n if (!this.weapons) {\r\n return 0\r\n }\r\n return this.weapons[e].kills\r\n })\r\n return chartData\r\n },\r\n chartOptions () {\r\n // eslint-disable-next-line no-unused-expressions\r\n this.$props.playerHighlighted\r\n const options = {\r\n responsive: true,\r\n maintainAspectRatio: true,\r\n animation: { duration: 500 },\r\n layout: { autoPadding: false },\r\n plugins: {\r\n datalabels: {\r\n formatter: (value: any, context: any) => {\r\n const weaponId = this.sortedWeaponList[context.dataIndex]\r\n // if (!(weapons as {[key:string]:string})[weaponId]) console.log(weaponId)\r\n return (weapons as {[key:string]:string})[weaponId] || weaponId\r\n },\r\n backgroundColor: (context: any) => {\r\n return context.dataset.backgroundColor(context)\r\n },\r\n borderColor: this.colors.fg,\r\n borderRadius: 25,\r\n borderWidth: 2,\r\n color: this.colors.bg,\r\n display: (context: any) => {\r\n return context.dataIndex === context.dataset.labels.length - 1\r\n ? true\r\n : 'auto'\r\n },\r\n padding: 6\r\n },\r\n tooltip: {\r\n callbacks: {\r\n label: (ctx: any) => {\r\n let label: string\r\n if (!this.sortedWeaponList) {\r\n label = ctx.dataset.labels[ctx.dataIndex]\r\n } else {\r\n label = this.sortedWeaponList[ctx.dataIndex]\r\n }\r\n label += ' (' + this.weapons[label].kills + ' kills)'\r\n return label\r\n }\r\n }\r\n }\r\n }\r\n }\r\n return options\r\n },\r\n weapons (): { [key: string]: Weapon } {\r\n const { weapon: _, ...withoutWeapon } = this.filters || {}\r\n const data = this.store.getWeaponList(withoutWeapon)?.value.data\r\n if (!data) return this.store.fetchWeapons(withoutWeapon).value.data\r\n return data\r\n },\r\n sortedWeaponList (): string[] {\r\n if (!this.weapons) return []\r\n const weapons = Object.keys(this.weapons)\r\n weapons.sort((a, b) => {\r\n if (Number(this.weapons[a].kills) < Number(this.weapons[b].kills)) {\r\n return -1\r\n }\r\n if (Number(this.weapons[a].kills) > Number(this.weapons[b].kills)) {\r\n return 1\r\n }\r\n return 0\r\n })\r\n return weapons\r\n }\r\n }\r\n})\r\n","import { render } from \"./WeaponChart.vue?vue&type=template&id=53c5074f&scoped=true&ts=true\"\nimport script from \"./WeaponChart.vue?vue&type=script&lang=ts\"\nexport * from \"./WeaponChart.vue?vue&type=script&lang=ts\"\n\nimport \"./WeaponChart.vue?vue&type=style&index=0&id=53c5074f&scoped=true&lang=css\"\n\nimport exportComponent from \"C:\\\\Users\\\\legon\\\\Documents\\\\Code\\\\Tone\\\\ToneAPI_webclient\\\\node_modules\\\\vue-loader\\\\dist\\\\exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-53c5074f\"]])\n\nexport default __exports__","\r\nimport { Player, Weapon, Server, useKillStore, Filters } from '@/stores/kill'\r\nimport PlayerList from '@/components/PlayerList.vue'\r\nimport PlayerChart from '@/components/PlayerChart.vue'\r\nimport WeaponChart from '@/components/WeaponChart.vue'\r\nimport { defineComponent } from 'vue'\r\nimport VueMultiselect from 'vue-multiselect'\r\nimport 'vue-multiselect/dist/vue-multiselect.css'\r\nimport weapons from '../stores/weapons.json'\r\n\r\nexport default defineComponent({\r\n name: 'PlayerView',\r\n components: {\r\n VueMultiselect, PlayerList, PlayerChart, WeaponChart\r\n },\r\n\r\n data () {\r\n return {\r\n model: { server: undefined, weapon: undefined } as unknown as { weapon: Weapon | Weapon[] | undefined, server: (Server & { name?: string }) | (Server & { name?: string })[] | undefined },\r\n filters: {} as Filters,\r\n store: useKillStore(),\r\n playerHighlighted: undefined as (Player & { id: string }) | undefined,\r\n weaponLocale: weapons as { [key: string]: string }\r\n }\r\n },\r\n computed: {\r\n servers (): { [key: string]: Server } {\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n const { server: _, player: _1, ...withoutServer } = this.filters\r\n const data = this.store.getServerList(withoutServer)?.value.data\r\n if (!data) return this.store.fetchServers(withoutServer).value.data\r\n return data\r\n },\r\n groupedServers () {\r\n const hosts = [] as { id: string, servers: (Server & { name?: string })[] }[]\r\n Object.entries(this.servers).forEach((e) => {\r\n if (!hosts.find(host => host.id === e[1].host + 'sfdsdfsd')) hosts.push({ id: e[1].host + 'sfdsdfsd', servers: [] as Server[] })\r\n hosts.find(host => host.id === e[1].host + 'sfdsdfsd')?.servers.push({ name: e[0], ...e[1] })\r\n })\r\n return hosts\r\n },\r\n weapons (): { [key: string]: Weapon } {\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n const { weapon: _, player: _1, ...withoutWeapons } = this.filters\r\n const data = this.store.getWeaponList(withoutWeapons)?.value.data\r\n if (!data) return this.store.fetchWeapons(withoutWeapons).value.data\r\n return data\r\n },\r\n players (): { [key: string]: Player } {\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n const { player: _, ...withoutPlayers } = this.filters\r\n const data = this.store.getPlayerList(withoutPlayers)?.value.data\r\n if (!data) return this.store.fetchPlayers(withoutPlayers).value.data\r\n return data\r\n },\r\n sortedWeaponList (): string[] {\r\n if (!this.weapons) return []\r\n const weapons = Object.keys(this.weapons)\r\n return weapons.sort()\r\n },\r\n sortedServerList (): string[] {\r\n if (!this.servers) return []\r\n const servers = Object.keys(this.servers)\r\n return servers.sort()\r\n },\r\n sortedPlayerList (): Player[] {\r\n if (!this.players) return []\r\n const players = Object.entries(this.players).map(e => ({ id: e[0], ...e[1] }))\r\n return players.sort((a: Player, b: Player) => {\r\n if (a.username < b.username) {\r\n return -1\r\n }\r\n if (a.username > b.username) {\r\n return 1\r\n }\r\n return 0\r\n })\r\n }\r\n },\r\n watch: {\r\n model: {\r\n handler (newModel) {\r\n this.filters.server = newModel.server?.name\r\n this.filters.weapon = newModel.weapon\r\n },\r\n deep: true\r\n }\r\n },\r\n methods: {\r\n highlight_player (playerid: string) {\r\n const player = this.players[playerid]\r\n if (player) {\r\n this.playerHighlighted = { id: playerid, ...player }\r\n return\r\n }\r\n this.playerHighlighted = undefined\r\n }\r\n }\r\n})\r\n","import { render } from \"./PlayerView.vue?vue&type=template&id=639162c3&scoped=true&ts=true\"\nimport script from \"./PlayerView.vue?vue&type=script&lang=ts\"\nexport * from \"./PlayerView.vue?vue&type=script&lang=ts\"\n\nimport \"./PlayerView.vue?vue&type=style&index=0&id=639162c3&scoped=true&lang=css\"\n\nimport exportComponent from \"C:\\\\Users\\\\legon\\\\Documents\\\\Code\\\\Tone\\\\ToneAPI_webclient\\\\node_modules\\\\vue-loader\\\\dist\\\\exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-639162c3\"]])\n\nexport default __exports__","import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'\r\nimport HomeView from '../views/HomeView.vue'\r\nimport PlayerView from '../views/PlayerView.vue'\r\n\r\nconst routes: Array = [\r\n {\r\n path: '/',\r\n name: 'home',\r\n component: PlayerView\r\n }\r\n // {\r\n // path: '/players',\r\n // name: 'players',\r\n // component: PlayerView\r\n // },\r\n // {\r\n // path: '/about',\r\n // name: 'about',\r\n // // route level code-splitting\r\n // // this generates a separate chunk (about.[hash].js) for this route\r\n // // which is lazy-loaded when the route is visited.\r\n // component: () => import(/* webpackChunkName: \"about\" */ '../views/AboutView.vue')\r\n // }\r\n]\r\n\r\nconst router = createRouter({\r\n history: createWebHistory(process.env.BASE_URL),\r\n routes\r\n})\r\n\r\nexport default router\r\n","import { createApp } from 'vue'\r\nimport App from './App.vue'\r\nimport router from './router'\r\nimport { createPinia } from 'pinia'\r\n\r\nconst pinia = createPinia()\r\n\r\ncreateApp(App).use(pinia).use(router).mount('#app')\r\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n","var deferred = [];\n__webpack_require__.O = function(result, chunkIds, fn, priority) {\n\tif(chunkIds) {\n\t\tpriority = priority || 0;\n\t\tfor(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];\n\t\tdeferred[i] = [chunkIds, fn, priority];\n\t\treturn;\n\t}\n\tvar notFulfilled = Infinity;\n\tfor (var i = 0; i < deferred.length; i++) {\n\t\tvar chunkIds = deferred[i][0];\n\t\tvar fn = deferred[i][1];\n\t\tvar priority = deferred[i][2];\n\t\tvar fulfilled = true;\n\t\tfor (var j = 0; j < chunkIds.length; j++) {\n\t\t\tif ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every(function(key) { return __webpack_require__.O[key](chunkIds[j]); })) {\n\t\t\t\tchunkIds.splice(j--, 1);\n\t\t\t} else {\n\t\t\t\tfulfilled = false;\n\t\t\t\tif(priority < notFulfilled) notFulfilled = priority;\n\t\t\t}\n\t\t}\n\t\tif(fulfilled) {\n\t\t\tdeferred.splice(i--, 1)\n\t\t\tvar r = fn();\n\t\t\tif (r !== undefined) result = r;\n\t\t}\n\t}\n\treturn result;\n};","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = function(module) {\n\tvar getter = module && module.__esModule ?\n\t\tfunction() { return module['default']; } :\n\t\tfunction() { return module; };\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// no baseURI\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t143: 0\n};\n\n// no chunk on demand loading\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\n__webpack_require__.O.j = function(chunkId) { return installedChunks[chunkId] === 0; };\n\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = function(parentChunkLoadingFunction, data) {\n\tvar chunkIds = data[0];\n\tvar moreModules = data[1];\n\tvar runtime = data[2];\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0;\n\tif(chunkIds.some(function(id) { return installedChunks[id] !== 0; })) {\n\t\tfor(moduleId in moreModules) {\n\t\t\tif(__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t\t}\n\t\t}\n\t\tif(runtime) var result = runtime(__webpack_require__);\n\t}\n\tif(parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\tfor(;i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {\n\t\t\tinstalledChunks[chunkId][0]();\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\treturn __webpack_require__.O(result);\n}\n\nvar chunkLoadingGlobal = self[\"webpackChunktoneapi_webclient\"] = self[\"webpackChunktoneapi_webclient\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));","// startup\n// Load entry module and return exports\n// This entry module depends on other loaded chunks and execution need to be delayed\nvar __webpack_exports__ = __webpack_require__.O(undefined, [998], function() { return __webpack_require__(8218); })\n__webpack_exports__ = __webpack_require__.O(__webpack_exports__);\n"],"names":["_hoisted_1","_createStaticVNode","render","_ctx","_cache","$props","$setup","$data","$options","_component_router_link","_resolveComponent","_component_router_view","_openBlock","_createElementBlock","_Fragment","_createElementVNode","_createVNode","to","class","default","_withCtx","_createTextVNode","_","removeNullEntries","a","Object","fromEntries","entries","filter","e","undefined","objectEqual","b","assert","deepStrictEqual","useKillStore","defineStore","state","servers","players","weapons","maps","gamemodes","hosts","getters","getPlayerList","filters","find","value","getWeaponList","getServerList","actions","fetchPlayers","entry","this","ref","data","push","fetch","URLSearchParams","then","async","response","json","fetchWeapons","fetchServers","defineComponent","setup","props","ctx","store","__exports__","id","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_component_VueMultiselect","_component_PlayerList","_component_PlayerChart","_component_WeaponChart","selectLabel","deselectLabel","placeholder","modelValue","model","server","$event","options","groupedServers","group_label","multiple","name","label","onClick","weapon","weaponLocale","sortedWeaponList","playerHighlighted","sortedPlayerList","username","onHighlightPlayer","highlight_player","player","_withScopeId","n","_pushScopeId","_popScopeId","onKeydown","args","selectNextPlayer","tabindex","updateSort","_normalizeClass","sortingData","argument","_renderList","playerList","index","key","$emit","ref_for","_toDisplayString","kills","deaths","Math","round","max","max_distance","total_distance","type","String","emits","direction","computed","withoutPlayer","map","collator","Intl","Collator","numeric","sensitivity","sort","compare","reverse","slice","watch","handler","newval","immediate","newElement","$refs","scrollIntoView","behavior","block","updated","element","methods","values","Home","Infinity","End","PageDown","PageUp","ArrowUp","ArrowDown","ArrowRight","ArrowLeft","keys","includes","preventDefault","findIndex","nextIndex","length","_component_Scatter","chart","chartOptions","ChartJS","LinearScale","PointElement","LineElement","Tooltip","Legend","annotationPlugin","dataLabel","refreshColors","playerData","components","Scatter","mounted","cut","colors","container","style","getComputedStyle","fg","getPropertyValue","bg","orange","cyan","currentLine","playerIndex","defaultColor","borderColor","Array","fill","backgroundColor","pointRadius","hoverRadius","pointStyle","datasets","labels","y","x","chartStaticOptions","responsive","maintainAspectRatio","animation","duration","layout","autoPadding","scales","title","text","display","color","ticks","onHover","native","target","cursor","chartStaticPlugins","endX","endY","maxX","maxY","tooltip","callbacks","dataIndex","dataset","parsed","annotation","annotations","line","yMin","xMin","yMax","xMax","borderWidth","borderDash","legend","plugins","datalabels","formatter","context","borderRadius","align","anchor","clamp","_component_Doughnut","ArcElement","Doughnut","yellow","green","purple","red","pink","chartData","weaponId","padding","withoutWeapon","Number","VueMultiselect","PlayerList","PlayerChart","WeaponChart","_1","withoutServer","forEach","host","withoutWeapons","withoutPlayers","sortedServerList","newModel","deep","playerid","routes","path","component","PlayerView","router","createRouter","history","createWebHistory","process","pinia","createPinia","createApp","App","use","mount","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","exports","module","__webpack_modules__","m","deferred","O","result","chunkIds","fn","priority","notFulfilled","i","fulfilled","j","every","splice","r","getter","__esModule","d","definition","o","defineProperty","enumerable","get","g","globalThis","Function","window","obj","prop","prototype","hasOwnProperty","call","installedChunks","chunkId","webpackJsonpCallback","parentChunkLoadingFunction","moreModules","runtime","some","chunkLoadingGlobal","self","bind","__webpack_exports__"],"sourceRoot":""}
\ No newline at end of file
diff --git a/dist/js/app.48e40867.js b/dist/js/app.48e40867.js
deleted file mode 100644
index d867492..0000000
--- a/dist/js/app.48e40867.js
+++ /dev/null
@@ -1,2 +0,0 @@
-(function(){"use strict";var e={4545:function(e,t,a){var r=a(3862),s=a(3396);const i=(0,s.uE)('TONE API
',4);function n(e,t,a,r,n,l){const o=(0,s.up)("router-link"),p=(0,s.up)("router-view");return(0,s.wg)(),(0,s.iD)(s.HY,null,[(0,s._)("header",null,[(0,s._)("nav",null,[i,(0,s.Wm)(o,{to:"/",class:"navbar-element"},{default:(0,s.w5)((()=>[(0,s.Uk)("Players")])),_:1})])]),(0,s.Wm)(p)],64)}a(7658);var l=a(1020),o=a(5130),p=a(4870);function d(e){return Object.fromEntries(Object.entries(e).filter((e=>void 0!==e[1]&&null!==e[1])))}function h(e,t){try{return e=d(e),t=d(t),o.deepStrictEqual(e,t),!0}catch{return!1}}const c=(0,l.Q_)("kill",{state:()=>({servers:[],players:[],weapons:[],maps:[],gamemodes:[],hosts:{}}),getters:{getPlayerList:e=>t=>e.players.find((e=>h(e.value.filter,t))),getWeaponList:e=>t=>e.weapons.find((e=>h(e.value.filter,t))),getServerList:e=>t=>e.servers.find((e=>h(e.value.filter,t)))},actions:{fetchPlayers(e){e=d(e);let t=this.players.find((t=>h(t.value.filter,e)));return void 0===t&&(t=(0,p.iH)({filter:e,data:{}}),this.players.push(t)),fetch("https://tone.sleepycat.date/v2/client/players?"+new URLSearchParams(e)).then((async e=>{t.value.data=await e.json()})),t},fetchWeapons(e){e=d(e);let t=this.weapons.find((t=>h(t.value.filter,e)));return t||(t=(0,p.iH)({filter:e,data:{}}),this.weapons.push(t)),fetch("https://tone.sleepycat.date/v2/client/weapons?"+new URLSearchParams(e)).then((async e=>{t.value.data=await e.json()})),t},fetchServers(e){e=d(e);let t=this.servers.find((t=>h(t.value.filter,e)));return t||(t=(0,p.iH)({filter:e,data:{}}),this.servers.push(t)),fetch("https://tone.sleepycat.date/v2/client/servers?"+new URLSearchParams(e)).then((async e=>{t.value.data=await e.json()})),t}}});var u=(0,s.aZ)({setup(e,t){const a=c();a.fetchPlayers({}),a.fetchServers({}),a.fetchWeapons({})}}),g=a(89);const m=(0,g.Z)(u,[["render",n]]);var _=m,f=a(2483);const y={id:"filters"},v={id:"playerView"};function w(e,t,a,r,i,n){const l=(0,s.up)("VueMultiselect"),o=(0,s.up)("PlayerList"),p=(0,s.up)("PlayerChart"),d=(0,s.up)("WeaponChart");return(0,s.wg)(),(0,s.iD)(s.HY,null,[(0,s._)("div",y,[(0,s.Wm)(l,{selectLabel:"",deselectLabel:"remove",placeholder:"Select server",modelValue:e.model.server,"onUpdate:modelValue":t[0]||(t[0]=t=>e.model.server=t),options:e.groupedServers,"group-values":"servers",group_label:"id","group-select":!1,"allow-empty":!0,multiple:!1,"custom-label":e=>e.name,"track-by":"name",label:"name"},null,8,["modelValue","options","custom-label"]),(0,s.Wm)(l,{selectLabel:"",deselectLabel:"remove",placeholder:"Select weapon",modelValue:e.model.weapon,"onUpdate:modelValue":t[1]||(t[1]=t=>e.model.weapon=t),"custom-label":t=>e.weaponLocale[t]||t,options:e.sortedWeaponList,"allow-empty":!0},null,8,["modelValue","custom-label","options"]),(0,s.Wm)(l,{"options-limit":20,selectLabel:"",deselectLabel:"remove",placeholder:"Search player",modelValue:e.playerHighlighted,"onUpdate:modelValue":t[2]||(t[2]=t=>e.playerHighlighted=t),options:e.sortedPlayerList,"allow-empty":!0,"custom-label":e=>e?.username},null,8,["modelValue","options","custom-label"])]),(0,s._)("div",v,[(0,s.Wm)(o,{filters:e.filters,onHighlightPlayer:e.highlight_player,playerHighlighted:e.playerHighlighted?.id},null,8,["filters","onHighlightPlayer","playerHighlighted"]),(0,s.Wm)(p,{filters:e.filters,onHighlightPlayer:e.highlight_player,playerHighlighted:e.playerHighlighted?.id},null,8,["filters","onHighlightPlayer","playerHighlighted"]),(0,s.Wm)(d,{filters:{player:e.playerHighlighted?.id,...e.filters},playerHighlighted:e.playerHighlighted?.id},null,8,["filters","playerHighlighted"])])],64)}var b=a(7139);const k=e=>((0,s.dD)("data-v-037b66ea"),e=e(),(0,s.Cn)(),e),P={class:"playerHeaders"},L=k((()=>(0,s._)("span",null,null,-1))),C=["onClick"];function x(e,t,a,r,i,n){return(0,s.wg)(),(0,s.iD)("div",{class:"playerTable",onKeydown:t[6]||(t[6]=(...t)=>e.selectNextPlayer&&e.selectNextPlayer(...t)),tabindex:"0"},[(0,s._)("div",P,[L,(0,s._)("span",{onClick:t[0]||(t[0]=t=>e.updateSort("username")),class:(0,b.C_)("username"==e.sortingData.argument?"selected":"")},"Username",2),(0,s._)("span",{onClick:t[1]||(t[1]=t=>e.updateSort("kills")),class:(0,b.C_)("kills"==e.sortingData.argument?"selected":"")},"K",2),(0,s._)("span",{onClick:t[2]||(t[2]=t=>e.updateSort("deaths")),class:(0,b.C_)("deaths"==e.sortingData.argument?"selected":"")},"D",2),(0,s._)("span",{onClick:t[3]||(t[3]=t=>e.updateSort("k/d")),class:(0,b.C_)("k/d"==e.sortingData.argument?"selected":"")},"K/D",2),(0,s._)("span",{onClick:t[4]||(t[4]=t=>e.updateSort("max_distance")),class:(0,b.C_)("max_distance"==e.sortingData.argument?"selected":"")},"max distance",2),(0,s._)("span",{onClick:t[5]||(t[5]=t=>e.updateSort("avg_distance")),class:(0,b.C_)("avg_distance"==e.sortingData.argument?"selected":"")},"average distance",2)]),((0,s.wg)(!0),(0,s.iD)(s.HY,null,(0,s.Ko)(e.playerList,((t,a)=>((0,s.wg)(),(0,s.iD)("div",{class:(0,b.C_)("playerRow "+(t.id===e.$props.playerHighlighted?"selected":"")),key:t.id,onClick:a=>e.$emit("highlightPlayer",t.id),ref_for:!0,ref:"player:"+t.id},[(0,s._)("div",null,[(0,s._)("span",null,(0,b.zw)(a+1),1)]),(0,s._)("div",null,[(0,s._)("span",null,(0,b.zw)(t.username),1)]),(0,s._)("div",null,[(0,s._)("span",null,(0,b.zw)(t.kills),1)]),(0,s._)("div",null,[(0,s._)("span",null,(0,b.zw)(t.deaths),1)]),(0,s._)("div",null,[(0,s._)("span",null,(0,b.zw)(Math.round(t.kills/Math.max(1,t.deaths)*100)/100),1)]),(0,s._)("div",null,[(0,s._)("span",null,(0,b.zw)(t.max_distance),1)]),(0,s._)("div",null,[(0,s._)("span",null,(0,b.zw)(Math.round(100*(t.total_distance/t.kills||0))/100),1)])],10,C)))),128))],32)}var S=(0,s.aZ)({props:{filters:{type:Object,default:()=>({})},playerHighlighted:String},emits:["highlightPlayer"],data(){return{sortingData:{direction:-1,argument:"kills"},store:c()}},computed:{players(){const{player:e,...t}=this.filters,a=this.store.getPlayerList(t)?.value.data;return a||this.store.fetchPlayers(t).value.data},playerList(){if(!this.players)return[];let e=Object.entries(this.players).map((e=>({id:e[0],...e[1]})));if("username"===this.sortingData.argument){const t=new Intl.Collator("en",{numeric:!0,sensitivity:"base"});e.sort(((e,a)=>t.compare(e.username,a.username)))}else if("k/d"===this.sortingData.argument)e.sort(((e,t)=>e.kills/Math.max(1,e.deaths)-t.kills/Math.max(1,t.deaths)));else if("avg_distance"===this.sortingData.argument)e.sort(((e,t)=>(e.total_distance/e.kills||0)-(t.total_distance/t.kills||0)));else{const t=this.sortingData.argument;e.sort(((e,a)=>e[t]-a[t]))}return this.sortingData.direction<0&&e.reverse(),e=e.slice(0,500),e}},watch:{players:{handler(e){e&&(this.sortingData.direction*=-1)},immediate:!0},playerHighlighted(e){const t=this.$refs["player:"+e];t&&t[0]&&t[0].scrollIntoView({behavior:"smooth",block:"center"})}},updated(){const e=this.$refs["player:"+this.$props.playerHighlighted];e&&e[0]&&e[0].scrollIntoView({behavior:"smooth",block:"center"})},methods:{selectNextPlayer(e){const t={Home:-1/0,End:1/0,PageDown:100,PageUp:-100,ArrowUp:-1,ArrowDown:1,ArrowRight:10,ArrowLeft:-10};if(!this.$props.playerHighlighted)return;if(!Object.keys(t).includes(e.key))return;e.preventDefault();const a=this.playerList.findIndex((e=>e.id===this.$props.playerHighlighted));let r=a+t[e.key];r>=this.playerList.length&&(r=this.playerList.length-1),r<0&&(r=0),this.$emit("highlightPlayer",this.playerList[r].id)},updateSort(e){this.sortingData.argument===e?this.sortingData.direction*=-1:this.sortingData.direction=-1,this.sortingData.argument=e}}});const H=(0,g.Z)(S,[["render",x],["__scopeId","data-v-037b66ea"]]);var D=H;const W={class:"playerChart",ref:"container"};function O(e,t,a,r,i,n){const l=(0,s.up)("Scatter");return(0,s.wg)(),(0,s.iD)("div",W,[(0,s.Wm)(l,{data:e.chart,options:e.chartOptions},null,8,["data","options"])],512)}var V=a(3254),$=a(9152),I=a(1131),M=a(5866);V.kL.register(V.f$,V.od,V.jn,V.u,V.De,$.Z,I.Z);var R=(0,s.aZ)({name:"PlayerChart",props:{filters:Object,playerHighlighted:String},data:()=>({store:c(),refreshColors:0,playerData:[]}),emits:["highlightPlayer"],components:{Scatter:M.bp},mounted(){this.refreshColors++},computed:{playerList(){const e=this.store.getPlayerList(this.filters||{})?.value.data;if(!e)return Object.entries(this.store.fetchPlayers(this.filters||{}).value.data).map((e=>({id:e[0],...e[1]})));const t=Object.entries(e).map((e=>({id:e[0],...e[1]})));return t.sort(((e,t)=>t.kills-e.kills)),t.slice(0,200)},colors(){this.refreshColors;const e={};if(this.$refs.container){const t=getComputedStyle(this.$refs.container);e.fg=t.getPropertyValue("--foreground"),e.bg=t.getPropertyValue("--bg-color"),e.orange=t.getPropertyValue("--orange"),e.cyan=t.getPropertyValue("--cyan"),e.currentLine=t.getPropertyValue("--current-line")}else e.fg="#ffffff";return e},chart(){const e=this.playerList.findIndex((e=>e.id===this.$props.playerHighlighted)),t=this.colors.cyan,a=new Array(this.playerList.length).fill(t);a[e]=this.colors.orange;const r=a,s=new Array(this.playerList.length).fill(1);s[e]=20;const i=new Array(this.playerList.length).fill(4);i[e]=30;const n=new Array(this.playerList.length).fill("circle");return n[e]="crossRot",{datasets:[{label:"Players",labels:this.playerList.map((e=>e.id))||[],borderColor:a,backgroundColor:r,pointRadius:s,pointStyle:n,hoverRadius:i,data:this.playerList.map((e=>({y:e.kills,x:e.deaths})))}]}},chartStaticOptions(){return{responsive:!0,maintainAspectRatio:!1,animation:{duration:500},layout:{autoPadding:!1},scales:{y:{title:{text:"Kills",display:!0,color:this.colors.fg},ticks:{color:this.colors.fg}},x:{title:{text:"Deaths",display:!0,color:this.colors.fg},ticks:{color:this.colors.fg}}},onClick:(e,t)=>{this.$emit("highlightPlayer",t.length>0?this.playerList[t[0].index].id:void 0)},onHover:(e,t)=>{e.native.target&&(e.native.target.style.cursor=t[0]?"pointer":"default")}}},chartStaticPlugins(){let e=0,t=0;if(this.playerList){const a=Math.max(...this.playerList.map((e=>e.deaths))),r=Math.max(...this.playerList.map((e=>e.kills)));r>a?(e=a,t=a/r*r):(t=r,e=r/a*a)}return{tooltip:{callbacks:{label:e=>{let t;return t=this.playerList?this.playerList[e.dataIndex].username:e.dataset.labels[e.dataIndex],t+=" ("+e.parsed.y+" kills "+e.parsed.x+" deaths)",t}}},annotation:{annotations:{line:{type:"line",yMin:0,xMin:0,yMax:t,xMax:e,borderWidth:2,borderColor:this.colors.orange,borderDash:[1,5]}}},legend:{display:!1}}},chartOptions(){return this.$props.playerHighlighted,{...this.chartStaticOptions,plugins:{...this.chartStaticPlugins,datalabels:{formatter:(e,t)=>this.playerList[t.dataIndex].username,backgroundColor:e=>this.$props.playerHighlighted&&this.$props.playerHighlighted===this.playerList[e.dataIndex].id?this.colors.orange:null,borderColor:this.colors.fg,borderWidth:e=>this.$props.playerHighlighted&&this.$props.playerHighlighted===this.playerList[e.dataIndex].id?1:0,borderRadius:5,display:e=>this.$props.playerHighlighted&&this.$props.playerHighlighted===this.playerList[e.dataIndex].id?"true":"auto",align:-45,anchor:"end",clamp:!0,color:e=>this.$props.playerHighlighted&&this.$props.playerHighlighted===this.playerList[e.dataIndex].id?this.colors.bg:this.colors.fg}}}}}});const j=(0,g.Z)(R,[["render",O],["__scopeId","data-v-1e99590c"]]);var A=j;const E={class:"weaponChart",ref:"container"};function T(e,t,a,r,i,n){const l=(0,s.up)("Doughnut");return(0,s.wg)(),(0,s.iD)("div",E,[(0,s.Wm)(l,{data:e.chart,options:e.chartOptions},null,8,["data","options"])],512)}var Z=JSON.parse('{"rodeo_battery_removal":"Rodeo Battery Removal","human_execution":"Human Execution","melee_pilot_kunai":"Kunai Melee","execution":"Execution","mp_weapon_car":"CAR","mp_weapon_defender":"Charge Rifle","mp_weapon_doubletake":"Double Take","mp_weapon_epg":"EPG-1","mp_weapon_hemlok_smg":"Volt","mp_weapon_lstar":"L-STAR","mp_weapon_r97":"R-97","mp_weapon_rspn101":"R-201","mp_weapon_smart_pistol":"Smart Pistol","mp_weapon_sniper":"Kraber","mp_weapon_vinson":"Flatline","mp_weapon_autopistol":"RE-45 auto","mp_weapon_alternator_smg":"Alternator","mp_weapon_frag_grenade":"Frag Grenade","mp_weapon_g2":"G2","mp_weapon_lmg":"Spitfire","mp_weapon_smr":"Sidewinder SMR","mp_weapon_softball":"Softball","mp_weapon_thermite_grenade":"Firestar","pilot_emptyhanded":"Melee","mp_weapon_mastiff":"Mastiff","mp_weapon_mgl":"MGL","mp_weapon_rspn101_og":"R-101","mp_weapon_wingman":"Wingman","invalid":"invalid","mp_weapon_arc_launcher":"Thunderbolt","mp_weapon_dmr":"DMR","mp_weapon_grenade_electric_smoke":"Electric Smoke","mp_weapon_pulse_lmg":"Cold War","mp_weapon_satchel":"Satchel","mp_weapon_shotgun":"EVA-8 Auto","mp_weapon_shotgun_pistol":"Mozambique","mp_weapon_wingman_n":"Wingman Elite","mp_weapon_grenade_gravity":"Gravity Star","mp_weapon_grenade_sonar":"Pulse Blade","mp_weapon_rocket_launcher":"Archer","outOfBounds":"OutOfBounds","mind_crime":"Mind Crime","mp_weapon_esaw":"Devotion","fall":"Fall","mp_weapon_semipistol":"P2016","mp_weapon_grenade_emp":"Arc Grenade","mp_weapon_hemlok":"Hemlok","melee_pilot_emptyhanded":"Melee","phase_shift":"Phase Shift","damagedef_suicide":"Suicide","damagedef_titan_hotdrop":"Crushed by Titanfall","mp_titanweapon_arc_cannon":"Arc Cannon","mp_weapon_peacekraber":"Peacekraber","damagedef_crush":"Crushed","mp_titanweapon_brute4_quad_rocket":"Quad Rocket Launcher","mp_weapon_turretplasma":"Antititan Turret","mp_titanweapon_xo16_vanguard":"XO-16","mp_titanweapon_sticky_40mm":"40mm Cannon","mp_titanweapon_predator_cannon":"Predator Cannon","mp_titanweapon_leadwall":"Leadwall","mp_titanweapon_sniper":"Plasma Railgun","titan_execution":"Titan Execution","titan_explosion":"Titan Explosion","auto_titan_melee":"Autotitan Melee","mp_titanweapon_vortex_shield_ion":"Vortex Shield","mp_titanweapon_heat_shield":"Heat shield","bubble_shield":"Bubble Shield","mp_titancore_salvo_core":"Salvo Core","mp_titancore_flame_wave":"Flame Wave","mp_titanweapon_flightcore_rockets":"Flight Core","mp_titancore_laser_cannon":"Laser Cannon","mp_titancore_flame_wave_secondary":"Scorched Earth","mp_titanweapon_flame_wall":"Flame Wall","mp_titanweapon_arc_wave":"Arc Wave"}');V.kL.register(V.qi,V.u,V.De,I.Z);var z=(0,s.aZ)({name:"PlayerChart",props:{filters:Object,playerHighlighted:String},emits:["highlightPlayer"],components:{Doughnut:M.$I},mounted(){this.refreshColors++},data:()=>({store:c(),refreshColors:0}),computed:{colors(){this.refreshColors;const e={};if(this.$refs.container){const t=getComputedStyle(this.$refs.container);e.fg=t.getPropertyValue("--foreground"),e.bg=t.getPropertyValue("--bg-color"),e.orange=t.getPropertyValue("--orange"),e.cyan=t.getPropertyValue("--cyan"),e.yellow=t.getPropertyValue("--yellow"),e.green=t.getPropertyValue("--green"),e.purple=t.getPropertyValue("--purple"),e.red=t.getPropertyValue("--red"),e.pink=t.getPropertyValue("--pink"),e.currentLine=t.getPropertyValue("--current-line")}else e.fg="#ffffff";return e},chart(){const e=["cyan","green","orange","pink","purple","red","yellow"],t={datasets:[{label:"Weapons",labels:this.sortedWeaponList||[],borderColor:()=>this.colors.fg,backgroundColor:t=>this.colors[e[3*t.dataIndex%e.length]],data:[]}]};return this.sortedWeaponList?(t.datasets[0].data=this.sortedWeaponList.map((e=>this.weapons?this.weapons[e].kills:0)),t):t},chartOptions(){this.$props.playerHighlighted;const e={responsive:!0,maintainAspectRatio:!0,animation:{duration:500},layout:{autoPadding:!1},plugins:{datalabels:{formatter:(e,t)=>{const a=this.sortedWeaponList[t.dataIndex];return Z[a]||a},backgroundColor:e=>e.dataset.backgroundColor(e),borderColor:this.colors.fg,borderRadius:25,borderWidth:2,color:this.colors.bg,display:e=>e.dataIndex===e.dataset.labels.length-1||"auto",padding:6},tooltip:{callbacks:{label:e=>{let t;return t=this.sortedWeaponList?this.sortedWeaponList[e.dataIndex]:e.dataset.labels[e.dataIndex],t+=" ("+this.weapons[t].kills+" kills)",t}}}}};return e},weapons(){const{weapon:e,...t}=this.filters||{},a=this.store.getWeaponList(t)?.value.data;return a||this.store.fetchWeapons(t).value.data},sortedWeaponList(){if(!this.weapons)return[];const e=Object.keys(this.weapons);return e.sort(((e,t)=>Number(this.weapons[e].kills)Number(this.weapons[t].kills)?1:0)),e}}});const N=(0,g.Z)(z,[["render",T],["__scopeId","data-v-53c5074f"]]);var U=N,F=a(6368),G=(0,s.aZ)({name:"PlayerView",components:{VueMultiselect:F.ZP,PlayerList:D,PlayerChart:A,WeaponChart:U},data(){return{model:{server:void 0,weapon:void 0},filters:{},store:c(),playerHighlighted:void 0,weaponLocale:Z}},computed:{servers(){const{server:e,player:t,...a}=this.filters,r=this.store.getServerList(a)?.value.data;return r||this.store.fetchServers(a).value.data},groupedServers(){const e=[];return Object.entries(this.servers).forEach((t=>{e.find((e=>e.id===t[1].host+"sfdsdfsd"))||e.push({id:t[1].host+"sfdsdfsd",servers:[]}),e.find((e=>e.id===t[1].host+"sfdsdfsd"))?.servers.push({name:t[0],...t[1]})})),e},weapons(){const{weapon:e,player:t,...a}=this.filters,r=this.store.getWeaponList(a)?.value.data;return r||this.store.fetchWeapons(a).value.data},players(){const{player:e,...t}=this.filters,a=this.store.getPlayerList(t)?.value.data;return a||this.store.fetchPlayers(t).value.data},sortedWeaponList(){if(!this.weapons)return[];const e=Object.keys(this.weapons);return e.sort()},sortedServerList(){if(!this.servers)return[];const e=Object.keys(this.servers);return e.sort()},sortedPlayerList(){if(!this.players)return[];const e=Object.entries(this.players).map((e=>({id:e[0],...e[1]})));return e.sort(((e,t)=>e.usernamet.username?1:0))}},watch:{model:{handler(e){this.filters.server=e.server?.name,this.filters.weapon=e.weapon},deep:!0}},methods:{highlight_player(e){const t=this.players[e];this.playerHighlighted=t?{id:e,...t}:void 0}}});const K=(0,g.Z)(G,[["render",w],["__scopeId","data-v-16cf505a"]]);var B=K;const q=[{path:"/",name:"home",component:B}],Y=(0,f.p7)({history:(0,f.PO)("/ToneAPI_webclient/"),routes:q});var Q=Y;const J=(0,l.WB)();(0,r.ri)(_).use(J).use(Q).mount("#app")}},t={};function a(r){var s=t[r];if(void 0!==s)return s.exports;var i=t[r]={exports:{}};return e[r](i,i.exports,a),i.exports}a.m=e,function(){var e=[];a.O=function(t,r,s,i){if(!r){var n=1/0;for(d=0;d=i)&&Object.keys(a.O).every((function(e){return a.O[e](r[o])}))?r.splice(o--,1):(l=!1,i0&&e[d-1][2]>i;d--)e[d]=e[d-1];e[d]=[r,s,i]}}(),function(){a.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return a.d(t,{a:t}),t}}(),function(){a.d=function(e,t){for(var r in t)a.o(t,r)&&!a.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})}}(),function(){a.g=function(){if("object"===typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"===typeof window)return window}}()}(),function(){a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}}(),function(){var e={143:0};a.O.j=function(t){return 0===e[t]};var t=function(t,r){var s,i,n=r[0],l=r[1],o=r[2],p=0;if(n.some((function(t){return 0!==e[t]}))){for(s in l)a.o(l,s)&&(a.m[s]=l[s]);if(o)var d=o(a)}for(t&&t(r);pTONE API
\", 4)\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_router_link = _resolveComponent(\"router-link\")!\n const _component_router_view = _resolveComponent(\"router-view\")!\n\n return (_openBlock(), _createElementBlock(_Fragment, null, [\n _createElementVNode(\"header\", null, [\n _createElementVNode(\"nav\", null, [\n _hoisted_1,\n _createVNode(_component_router_link, {\n to: \"/\",\n class: \"navbar-element\"\n }, {\n default: _withCtx(() => [\n _createTextVNode(\"Players\")\n ]),\n _: 1\n })\n ])\n ]),\n _createVNode(_component_router_view)\n ], 64))\n}","import { defineStore } from 'pinia'\r\nimport * as assert from 'assert'\r\nimport { Ref, ref } from 'vue'\r\n\r\nexport interface Filters {\r\n server?: string;\r\n player?: string;\r\n weapon?: string;\r\n host?: string;\r\n map?: string;\r\n gamemode?: string;\r\n}\r\n\r\nfunction removeNullEntries (a: Filters) {\r\n return Object.fromEntries(\r\n Object.entries(a).filter((e) => e[1] !== undefined && e[1] !== null)\r\n )\r\n}\r\nfunction objectEqual (a: Filters, b: Filters) {\r\n try {\r\n a = removeNullEntries(a)\r\n b = removeNullEntries(b)\r\n assert.deepStrictEqual(a, b)\r\n return true\r\n } catch {\r\n return false\r\n }\r\n}\r\n\r\nexport interface Kill {\r\n deaths: number;\r\n kills: number;\r\n // eslint-disable-next-line camelcase\r\n max_distance: number;\r\n // eslint-disable-next-line camelcase\r\n total_distance: number;\r\n}\r\nexport interface KillData {\r\n filter: Filters;\r\n data: { [key: string]: T };\r\n}\r\n\r\nexport interface Player extends Kill {\r\n username: string;\r\n // eslint-disable-next-line camelcase\r\n // deaths_while_equipped?: number;\r\n}\r\n\r\nexport interface Weapon extends Kill {\r\n // eslint-disable-next-line camelcase\r\n deaths_while_equipped: number;\r\n}\r\n\r\nexport interface Server extends Kill {\r\n host: number;\r\n}\r\n\r\n// define your typings for the store state\r\nexport interface State {\r\n servers: Ref>[];\r\n players: Ref>[];\r\n weapons: Ref>[];\r\n maps: Ref>[];\r\n gamemodes: Ref>[];\r\n hosts: { [key: number]: string };\r\n}\r\n\r\nexport const useKillStore = defineStore('kill', {\r\n state: (): State => ({\r\n servers: [],\r\n players: [],\r\n weapons: [],\r\n maps: [],\r\n gamemodes: [],\r\n hosts: {}\r\n }),\r\n getters: {\r\n getPlayerList: (state) => (filters: Filters) => {\r\n return state.players.find((e) => objectEqual(e.value.filter, filters))\r\n },\r\n getWeaponList: (state) => (filters: Filters) =>\r\n state.weapons.find((e) => objectEqual(e.value.filter, filters)),\r\n getServerList: (state) => (filters: Filters) =>\r\n state.servers.find((e) => objectEqual(e.value.filter, filters))\r\n },\r\n actions: {\r\n fetchPlayers (filter: Filters) {\r\n filter = removeNullEntries(filter)\r\n let entry = this.players.find((e) => objectEqual(e.value.filter, filter))\r\n if (entry === undefined) {\r\n entry = ref({ filter, data: {} })\r\n this.players.push(entry)\r\n }\r\n fetch(\r\n 'https://tone.sleepycat.date/v2/client/players?' +\r\n new URLSearchParams(filter as Record)\r\n ).then(async response => {\r\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\r\n entry!.value.data = await response.json()\r\n })\r\n return entry\r\n },\r\n fetchWeapons (filter: Filters) {\r\n filter = removeNullEntries(filter)\r\n let entry = this.weapons.find((e) => objectEqual(e.value.filter, filter))\r\n if (!entry) {\r\n entry = ref({ filter, data: {} })\r\n this.weapons.push(entry)\r\n }\r\n\r\n fetch(\r\n 'https://tone.sleepycat.date/v2/client/weapons?' +\r\n new URLSearchParams(filter as Record)\r\n ).then(async response => {\r\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\r\n entry!.value.data = await response.json()\r\n })\r\n return entry\r\n },\r\n fetchServers (filter: Filters) {\r\n filter = removeNullEntries(filter)\r\n let entry = this.servers.find((e) => objectEqual(e.value.filter, filter))\r\n if (!entry) {\r\n entry = ref({ filter, data: {} })\r\n this.servers.push(entry)\r\n }\r\n fetch(\r\n 'https://tone.sleepycat.date/v2/client/servers?' +\r\n new URLSearchParams(filter as Record)\r\n ).then(async response => {\r\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\r\n entry!.value.data = await response.json()\r\n })\r\n return entry\r\n }\r\n }\r\n})\r\n","\r\nimport { Player, Weapon, Server, useKillStore } from '@/stores/kill'\r\nimport { defineComponent } from 'vue'\r\n\r\nexport default defineComponent({\r\n setup (props, ctx) {\r\n const store = useKillStore()\r\n store.fetchPlayers({})\r\n store.fetchServers({})\r\n store.fetchWeapons({})\r\n }\r\n})\r\n","import { render } from \"./App.vue?vue&type=template&id=a4a5fcd4&ts=true\"\nimport script from \"./App.vue?vue&type=script&lang=ts\"\nexport * from \"./App.vue?vue&type=script&lang=ts\"\n\nimport \"./App.vue?vue&type=style&index=0&id=a4a5fcd4&lang=css\"\n\nimport exportComponent from \"C:\\\\Users\\\\legon\\\\Documents\\\\Code\\\\Tone\\\\ToneAPI_webclient\\\\node_modules\\\\vue-loader\\\\dist\\\\exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render]])\n\nexport default __exports__","import { resolveComponent as _resolveComponent, createVNode as _createVNode, createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-16cf505a\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = { id: \"filters\" }\nconst _hoisted_2 = { id: \"playerView\" }\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_VueMultiselect = _resolveComponent(\"VueMultiselect\")!\n const _component_PlayerList = _resolveComponent(\"PlayerList\")!\n const _component_PlayerChart = _resolveComponent(\"PlayerChart\")!\n const _component_WeaponChart = _resolveComponent(\"WeaponChart\")!\n\n return (_openBlock(), _createElementBlock(_Fragment, null, [\n _createElementVNode(\"div\", _hoisted_1, [\n _createVNode(_component_VueMultiselect, {\n selectLabel: \"\",\n deselectLabel: \"remove\",\n placeholder: \"Select server\",\n modelValue: _ctx.model.server,\n \"onUpdate:modelValue\": _cache[0] || (_cache[0] = ($event: any) => ((_ctx.model.server) = $event)),\n options: _ctx.groupedServers,\n \"group-values\": \"servers\",\n group_label: \"id\",\n \"group-select\": false,\n \"allow-empty\": true,\n multiple: false,\n \"custom-label\": ((e) => e.name),\n \"track-by\": \"name\",\n label: \"name\"\n }, null, 8, [\"modelValue\", \"options\", \"custom-label\"]),\n _createVNode(_component_VueMultiselect, {\n selectLabel: \"\",\n deselectLabel: \"remove\",\n placeholder: \"Select weapon\",\n modelValue: _ctx.model.weapon,\n \"onUpdate:modelValue\": _cache[1] || (_cache[1] = ($event: any) => ((_ctx.model.weapon) = $event)),\n \"custom-label\": ((e) => _ctx.weaponLocale[e] || e),\n options: _ctx.sortedWeaponList,\n \"allow-empty\": true\n }, null, 8, [\"modelValue\", \"custom-label\", \"options\"]),\n _createVNode(_component_VueMultiselect, {\n \"options-limit\": 20,\n selectLabel: \"\",\n deselectLabel: \"remove\",\n placeholder: \"Search player\",\n modelValue: _ctx.playerHighlighted,\n \"onUpdate:modelValue\": _cache[2] || (_cache[2] = ($event: any) => ((_ctx.playerHighlighted) = $event)),\n options: _ctx.sortedPlayerList,\n \"allow-empty\": true,\n \"custom-label\": ((e) => e?.username)\n }, null, 8, [\"modelValue\", \"options\", \"custom-label\"])\n ]),\n _createElementVNode(\"div\", _hoisted_2, [\n _createVNode(_component_PlayerList, {\n filters: _ctx.filters,\n onHighlightPlayer: _ctx.highlight_player,\n playerHighlighted: _ctx.playerHighlighted?.id\n }, null, 8, [\"filters\", \"onHighlightPlayer\", \"playerHighlighted\"]),\n _createVNode(_component_PlayerChart, {\n filters: _ctx.filters,\n onHighlightPlayer: _ctx.highlight_player,\n playerHighlighted: _ctx.playerHighlighted?.id\n }, null, 8, [\"filters\", \"onHighlightPlayer\", \"playerHighlighted\"]),\n _createVNode(_component_WeaponChart, {\n filters: {player: _ctx.playerHighlighted?.id, ..._ctx.filters},\n playerHighlighted: _ctx.playerHighlighted?.id\n }, null, 8, [\"filters\", \"playerHighlighted\"])\n ])\n ], 64))\n}","import { createElementVNode as _createElementVNode, normalizeClass as _normalizeClass, renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, toDisplayString as _toDisplayString, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-037b66ea\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = { class: \"playerHeaders\" }\nconst _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"span\", null, null, -1))\nconst _hoisted_3 = [\"onClick\"]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"div\", {\n class: \"playerTable\",\n onKeydown: _cache[6] || (_cache[6] = \n//@ts-ignore\n(...args) => (_ctx.selectNextPlayer && _ctx.selectNextPlayer(...args))),\n tabindex: \"0\"\n }, [\n _createElementVNode(\"div\", _hoisted_1, [\n _hoisted_2,\n _createElementVNode(\"span\", {\n onClick: _cache[0] || (_cache[0] = ($event: any) => (_ctx.updateSort('username'))),\n class: _normalizeClass(_ctx.sortingData.argument == 'username' ? 'selected' : '')\n }, \"Username\", 2),\n _createElementVNode(\"span\", {\n onClick: _cache[1] || (_cache[1] = ($event: any) => (_ctx.updateSort('kills'))),\n class: _normalizeClass(_ctx.sortingData.argument == 'kills' ? 'selected' : '')\n }, \"K\", 2),\n _createElementVNode(\"span\", {\n onClick: _cache[2] || (_cache[2] = ($event: any) => (_ctx.updateSort('deaths'))),\n class: _normalizeClass(_ctx.sortingData.argument == 'deaths' ? 'selected' : '')\n }, \"D\", 2),\n _createElementVNode(\"span\", {\n onClick: _cache[3] || (_cache[3] = ($event: any) => (_ctx.updateSort('k/d'))),\n class: _normalizeClass(_ctx.sortingData.argument == 'k/d' ? 'selected' : '')\n }, \"K/D\", 2),\n _createElementVNode(\"span\", {\n onClick: _cache[4] || (_cache[4] = ($event: any) => (_ctx.updateSort('max_distance'))),\n class: _normalizeClass(_ctx.sortingData.argument == 'max_distance' ? 'selected' : '')\n }, \"max distance\", 2),\n _createElementVNode(\"span\", {\n onClick: _cache[5] || (_cache[5] = ($event: any) => (_ctx.updateSort('avg_distance'))),\n class: _normalizeClass(_ctx.sortingData.argument == 'avg_distance' ? 'selected' : '')\n }, \"average distance\", 2)\n ]),\n (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.playerList, (player, index) => {\n return (_openBlock(), _createElementBlock(\"div\", {\n class: _normalizeClass('playerRow ' + (player.id === _ctx.$props.playerHighlighted ? 'selected' : '')),\n key: player.id,\n onClick: ($event: any) => (_ctx.$emit('highlightPlayer', player.id)),\n ref_for: true,\n ref: `player:` + player.id\n }, [\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(index+1), 1)\n ]),\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(player.username), 1)\n ]),\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(player.kills), 1)\n ]),\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(player.deaths), 1)\n ]),\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(Math.round(player.kills / Math.max(1, player.deaths) * 100) / 100), 1)\n ]),\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(player.max_distance), 1)\n ]),\n _createElementVNode(\"div\", null, [\n _createElementVNode(\"span\", null, _toDisplayString(Math.round(((player.total_distance / player.kills) || 0) * 100) / 100), 1)\n ])\n ], 10, _hoisted_3))\n }), 128))\n ], 32))\n}","\r\nimport { defineComponent, PropType } from 'vue'\r\nimport { useKillStore, Player, Filters } from '@/stores/kill'\r\n\r\nexport default defineComponent({\r\n props: {\r\n filters: { type: Object as PropType, default: () => ({}) },\r\n playerHighlighted: String\r\n },\r\n emits: ['highlightPlayer'],\r\n data () {\r\n return {\r\n sortingData: { direction: -1, argument: 'kills' as keyof Player | 'k/d' | 'avg_distance' },\r\n store: useKillStore()\r\n }\r\n },\r\n computed: {\r\n players (): { [key: string]: Player } {\r\n const { player: _, ...withoutPlayer } = this.filters\r\n const data = this.store.getPlayerList(withoutPlayer)?.value.data\r\n if (!data) return this.store.fetchPlayers(withoutPlayer).value.data\r\n return data\r\n },\r\n playerList ():(Player & {id:string})[] {\r\n if (!this.players) return []\r\n let players = Object.entries(this.players).map(e => ({ id: e[0], ...e[1] }))\r\n\r\n if (this.sortingData.argument === 'username') {\r\n const collator = new Intl.Collator('en', { numeric: true, sensitivity: 'base' })\r\n players.sort((a: Player, b: Player) => {\r\n return collator.compare(a.username, b.username)\r\n })\r\n } else if (this.sortingData.argument === 'k/d') {\r\n players.sort((a: Player, b: Player) => {\r\n return a.kills / Math.max(1, a.deaths) - b.kills / Math.max(1, b.deaths)\r\n })\r\n } else if (this.sortingData.argument === 'avg_distance') {\r\n players.sort((a: Player, b: Player) => {\r\n return ((a.total_distance / a.kills) || 0) - ((b.total_distance / b.kills) || 0)\r\n })\r\n } else {\r\n const argument = this.sortingData.argument\r\n players.sort((a: Player, b: Player) => {\r\n return a[argument] - b[argument]\r\n })\r\n }\r\n\r\n if (this.sortingData.direction < 0) {\r\n players.reverse()\r\n }\r\n\r\n players = players.slice(0, 500)\r\n return players\r\n }\r\n },\r\n watch: {\r\n players: {\r\n handler (newval: { [key: string]: Player }): void {\r\n if (!newval) return\r\n this.sortingData.direction *= -1\r\n },\r\n immediate: true\r\n },\r\n playerHighlighted (newval) {\r\n const newElement = this.$refs['player:' + newval] as HTMLElement[]\r\n if (newElement && newElement[0]) { newElement[0].scrollIntoView({ behavior: 'smooth', block: 'center' }) }\r\n }\r\n },\r\n updated () {\r\n const element = this.$refs['player:' + this.$props.playerHighlighted] as HTMLElement[]\r\n if (!element || !element[0]) return\r\n element[0].scrollIntoView({ behavior: 'smooth', block: 'center' })\r\n },\r\n methods: {\r\n selectNextPlayer (e: KeyboardEvent) {\r\n const values = {\r\n Home: -Infinity,\r\n End: Infinity,\r\n PageDown: 100,\r\n PageUp: -100,\r\n ArrowUp: -1,\r\n ArrowDown: 1,\r\n ArrowRight: 10,\r\n ArrowLeft: -10\r\n } as { [key: string]: number }\r\n if (!this.$props.playerHighlighted) return\r\n if (!Object.keys(values).includes(e.key)) return\r\n e.preventDefault()\r\n const index = this.playerList.findIndex(e => e.id === this.$props.playerHighlighted)\r\n let nextIndex = (index + values[e.key])\r\n if (nextIndex >= this.playerList.length) nextIndex = this.playerList.length - 1\r\n if (nextIndex < 0) nextIndex = 0\r\n this.$emit('highlightPlayer', this.playerList[nextIndex].id)\r\n },\r\n updateSort (argument:string) {\r\n if (this.sortingData.argument === argument) {\r\n this.sortingData.direction *= -1\r\n } else {\r\n this.sortingData.direction = -1\r\n }\r\n this.sortingData.argument = argument as typeof this.sortingData.argument\r\n }\r\n }\r\n\r\n})\r\n","import { render } from \"./PlayerList.vue?vue&type=template&id=037b66ea&scoped=true&ts=true\"\nimport script from \"./PlayerList.vue?vue&type=script&lang=ts\"\nexport * from \"./PlayerList.vue?vue&type=script&lang=ts\"\n\nimport \"./PlayerList.vue?vue&type=style&index=0&id=037b66ea&scoped=true&lang=css\"\n\nimport exportComponent from \"C:\\\\Users\\\\legon\\\\Documents\\\\Code\\\\Tone\\\\ToneAPI_webclient\\\\node_modules\\\\vue-loader\\\\dist\\\\exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-037b66ea\"]])\n\nexport default __exports__","import { resolveComponent as _resolveComponent, createVNode as _createVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-1e99590c\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = {\n class: \"playerChart\",\n ref: \"container\"\n}\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_Scatter = _resolveComponent(\"Scatter\")!\n\n return (_openBlock(), _createElementBlock(\"div\", _hoisted_1, [\n _createVNode(_component_Scatter, {\n data: _ctx.chart,\n options: _ctx.chartOptions\n }, null, 8, [\"data\", \"options\"])\n ], 512))\n}","\r\nimport {\r\n Chart as ChartJS,\r\n LinearScale,\r\n PointElement,\r\n LineElement,\r\n Tooltip,\r\n Legend,\r\n CoreChartOptions,\r\n PluginChartOptions,\r\n ScaleChartOptions\r\n} from 'chart.js'\r\nimport annotationPlugin, { AnnotationPluginOptions } from 'chartjs-plugin-annotation'\r\nimport dataLabel from 'chartjs-plugin-datalabels'\r\nimport { useKillStore, Player, Filters } from '@/stores/kill'\r\n\r\nimport { Scatter } from 'vue-chartjs'\r\nimport { defineComponent, PropType } from 'vue'\r\nimport { ChartEvent } from 'chart.js/dist/core/core.plugins'\r\nimport { _DeepPartialObject } from 'chart.js/dist/types/utils'\r\n\r\nChartJS.register(LinearScale, PointElement, LineElement, Tooltip, Legend, annotationPlugin, dataLabel)\r\n\r\nexport default defineComponent({\r\n name: 'PlayerChart',\r\n props: {\r\n filters: Object as PropType,\r\n playerHighlighted: String\r\n },\r\n data: () => {\r\n return {\r\n store: useKillStore(),\r\n refreshColors: 0,\r\n playerData: []\r\n }\r\n },\r\n emits: ['highlightPlayer'],\r\n components: {\r\n Scatter\r\n },\r\n mounted () {\r\n this.refreshColors++\r\n },\r\n computed: {\r\n playerList (): (Player & {id:string})[] {\r\n const data = this.store.getPlayerList(this.filters || {})?.value.data\r\n if (!data) return Object.entries(this.store.fetchPlayers(this.filters || {}).value.data).map(e => ({ id: e[0], ...e[1] }))\r\n const cut = Object.entries(data).map(e => ({ id: e[0], ...e[1] }))\r\n cut.sort((a, b) => {\r\n return b.kills - a.kills\r\n })\r\n return cut.slice(0, 200)\r\n },\r\n colors () {\r\n // eslint-disable-next-line no-unused-expressions\r\n this.refreshColors\r\n const colors = {} as { [key: string]: string }\r\n if (this.$refs.container) {\r\n const style = getComputedStyle(this.$refs.container as Element)\r\n colors.fg = style.getPropertyValue('--foreground')\r\n colors.bg = style.getPropertyValue('--bg-color')\r\n colors.orange = style.getPropertyValue('--orange')\r\n colors.cyan = style.getPropertyValue('--cyan')\r\n colors.currentLine = style.getPropertyValue('--current-line')\r\n } else {\r\n colors.fg = '#ffffff'\r\n }\r\n return colors\r\n },\r\n\r\n chart () {\r\n const playerIndex = this.playerList.findIndex(e => e.id === this.$props.playerHighlighted)\r\n const defaultColor = this.colors.cyan\r\n const borderColor = new Array(this.playerList.length).fill(defaultColor)\r\n borderColor[playerIndex] = this.colors.orange\r\n const backgroundColor = borderColor\r\n const pointRadius = new Array(this.playerList.length).fill(1)\r\n pointRadius[playerIndex] = 20\r\n const hoverRadius = new Array(this.playerList.length).fill(4)\r\n hoverRadius[playerIndex] = 30\r\n const pointStyle = new Array(this.playerList.length).fill('circle')\r\n pointStyle[playerIndex] = 'crossRot'\r\n return {\r\n datasets: [\r\n {\r\n label: 'Players',\r\n labels: this.playerList.map(e => e.id) || [] as string[],\r\n borderColor,\r\n backgroundColor,\r\n pointRadius,\r\n pointStyle,\r\n hoverRadius,\r\n data: this.playerList.map((player) => ({ y: player.kills, x: player.deaths }))\r\n }\r\n ]\r\n }\r\n },\r\n chartStaticOptions () {\r\n return {\r\n responsive: true,\r\n maintainAspectRatio: false,\r\n animation: { duration: 500 },\r\n layout: { autoPadding: false },\r\n scales: {\r\n y: {\r\n title: {\r\n text: 'Kills',\r\n display: true,\r\n color: this.colors.fg\r\n },\r\n ticks: {\r\n color: this.colors.fg\r\n }\r\n },\r\n x: {\r\n title: {\r\n text: 'Deaths',\r\n display: true,\r\n color: this.colors.fg\r\n },\r\n ticks: {\r\n color: this.colors.fg\r\n }\r\n }\r\n },\r\n onClick: (e: ChartEvent, element: any) => {\r\n this.$emit('highlightPlayer', element.length > 0 ? this.playerList[element[0].index].id : undefined)\r\n },\r\n onHover: (e: any, element: any) => {\r\n if (!e.native.target) return\r\n (e.native.target as HTMLElement).style.cursor = element[0] ? 'pointer' : 'default'\r\n }\r\n }\r\n },\r\n chartStaticPlugins () {\r\n let endX = 0\r\n let endY = 0\r\n if (this.playerList) {\r\n const maxX = Math.max(...this.playerList.map(e => e.deaths))\r\n const maxY = Math.max(...this.playerList.map(e => e.kills))\r\n if (maxY > maxX) {\r\n endX = maxX\r\n endY = (maxX / maxY) * maxY\r\n } else {\r\n endY = maxY\r\n endX = (maxY / maxX) * maxX\r\n }\r\n }\r\n return {\r\n tooltip: {\r\n callbacks: {\r\n label: (ctx: any) => {\r\n let label: string\r\n if (!this.playerList) {\r\n label = ctx.dataset.labels[ctx.dataIndex]\r\n } else {\r\n label = this.playerList[ctx.dataIndex].username\r\n }\r\n label += ' (' + ctx.parsed.y + ' kills ' + ctx.parsed.x + ' deaths)'\r\n return label\r\n }\r\n }\r\n },\r\n annotation: {\r\n annotations: {\r\n line: {\r\n type: 'line',\r\n yMin: 0,\r\n xMin: 0,\r\n yMax: endY,\r\n xMax: endX,\r\n borderWidth: 2,\r\n borderColor: this.colors.orange,\r\n borderDash: [1, 5]\r\n }\r\n }\r\n } as _DeepPartialObject,\r\n legend: { display: false }\r\n }\r\n },\r\n chartOptions (): _DeepPartialObject & PluginChartOptions<'scatter'> & ScaleChartOptions<'scatter'>> {\r\n // eslint-disable-next-line no-unused-expressions\r\n this.$props.playerHighlighted\r\n return {\r\n ...this.chartStaticOptions,\r\n plugins: {\r\n ...this.chartStaticPlugins,\r\n datalabels: {\r\n formatter: (value: any, context: any) => {\r\n return this.playerList[context.dataIndex].username\r\n },\r\n backgroundColor: (context: any) => (this.$props.playerHighlighted && this.$props.playerHighlighted === this.playerList[context.dataIndex].id) ? this.colors.orange : null,\r\n borderColor: this.colors.fg,\r\n borderWidth: (context: any) => (this.$props.playerHighlighted && this.$props.playerHighlighted === this.playerList[context.dataIndex].id) ? 1 : 0,\r\n borderRadius: 5,\r\n display: (context: any) => (this.$props.playerHighlighted && this.$props.playerHighlighted === this.playerList[context.dataIndex].id) ? 'true' : 'auto',\r\n align: -45,\r\n anchor: 'end',\r\n clamp: true,\r\n color: (context: any) => (this.$props.playerHighlighted && this.$props.playerHighlighted === this.playerList[context.dataIndex].id) ? this.colors.bg : this.colors.fg\r\n }\r\n }\r\n }\r\n }\r\n }\r\n})\r\n","import { render } from \"./PlayerChart.vue?vue&type=template&id=1e99590c&scoped=true&ts=true\"\nimport script from \"./PlayerChart.vue?vue&type=script&lang=ts\"\nexport * from \"./PlayerChart.vue?vue&type=script&lang=ts\"\n\nimport \"./PlayerChart.vue?vue&type=style&index=0&id=1e99590c&scoped=true&lang=css\"\n\nimport exportComponent from \"C:\\\\Users\\\\legon\\\\Documents\\\\Code\\\\Tone\\\\ToneAPI_webclient\\\\node_modules\\\\vue-loader\\\\dist\\\\exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-1e99590c\"]])\n\nexport default __exports__","import { resolveComponent as _resolveComponent, createVNode as _createVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-53c5074f\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = {\n class: \"weaponChart\",\n ref: \"container\"\n}\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_Doughnut = _resolveComponent(\"Doughnut\")!\n\n return (_openBlock(), _createElementBlock(\"div\", _hoisted_1, [\n _createVNode(_component_Doughnut, {\n data: _ctx.chart,\n options: _ctx.chartOptions\n }, null, 8, [\"data\", \"options\"])\n ], 512))\n}","\r\nimport { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'\r\nimport dataLabel from 'chartjs-plugin-datalabels'\r\nimport { Weapon, Filters, useKillStore } from '@/stores/kill'\r\nimport { Doughnut } from 'vue-chartjs'\r\nimport { defineComponent, PropType } from 'vue'\r\nimport weapons from '../stores/weapons.json'\r\n\r\nChartJS.register(ArcElement, Tooltip, Legend, dataLabel)\r\n\r\nexport default defineComponent({\r\n name: 'PlayerChart',\r\n props: {\r\n filters: Object as PropType,\r\n playerHighlighted: String\r\n },\r\n emits: ['highlightPlayer'],\r\n components: {\r\n Doughnut\r\n },\r\n mounted () {\r\n this.refreshColors++\r\n },\r\n data: () => {\r\n return {\r\n store: useKillStore(),\r\n refreshColors: 0\r\n }\r\n },\r\n computed: {\r\n colors () {\r\n // eslint-disable-next-line no-unused-expressions\r\n this.refreshColors\r\n const colors = {} as { [key: string]: string }\r\n if (this.$refs.container) {\r\n const style = getComputedStyle(this.$refs.container as Element)\r\n colors.fg = style.getPropertyValue('--foreground')\r\n colors.bg = style.getPropertyValue('--bg-color')\r\n colors.orange = style.getPropertyValue('--orange')\r\n colors.cyan = style.getPropertyValue('--cyan')\r\n colors.yellow = style.getPropertyValue('--yellow')\r\n colors.green = style.getPropertyValue('--green')\r\n colors.purple = style.getPropertyValue('--purple')\r\n colors.red = style.getPropertyValue('--red')\r\n colors.pink = style.getPropertyValue('--pink')\r\n colors.currentLine = style.getPropertyValue('--current-line')\r\n } else {\r\n colors.fg = '#ffffff'\r\n }\r\n return colors\r\n },\r\n chart () {\r\n const colors = [\r\n 'cyan',\r\n 'green',\r\n 'orange',\r\n 'pink',\r\n 'purple',\r\n 'red',\r\n 'yellow'\r\n ]\r\n const chartData = {\r\n datasets: [\r\n {\r\n label: 'Weapons',\r\n labels: this.sortedWeaponList || ([] as string[]),\r\n borderColor: () => this.colors.fg,\r\n backgroundColor: (context: any) => {\r\n return this.colors[\r\n colors[(context.dataIndex * 3) % colors.length]\r\n ]\r\n },\r\n data: [] as number[]\r\n }\r\n ]\r\n }\r\n if (!this.sortedWeaponList) {\r\n return chartData\r\n }\r\n chartData.datasets[0].data = this.sortedWeaponList.map((e) => {\r\n if (!this.weapons) {\r\n return 0\r\n }\r\n return this.weapons[e].kills\r\n })\r\n return chartData\r\n },\r\n chartOptions () {\r\n // eslint-disable-next-line no-unused-expressions\r\n this.$props.playerHighlighted\r\n const options = {\r\n responsive: true,\r\n maintainAspectRatio: true,\r\n animation: { duration: 500 },\r\n layout: { autoPadding: false },\r\n plugins: {\r\n datalabels: {\r\n formatter: (value: any, context: any) => {\r\n const weaponId = this.sortedWeaponList[context.dataIndex]\r\n // if (!(weapons as {[key:string]:string})[weaponId]) console.log(weaponId)\r\n return (weapons as {[key:string]:string})[weaponId] || weaponId\r\n },\r\n backgroundColor: (context: any) => {\r\n return context.dataset.backgroundColor(context)\r\n },\r\n borderColor: this.colors.fg,\r\n borderRadius: 25,\r\n borderWidth: 2,\r\n color: this.colors.bg,\r\n display: (context: any) => {\r\n return context.dataIndex === context.dataset.labels.length - 1\r\n ? true\r\n : 'auto'\r\n },\r\n padding: 6\r\n },\r\n tooltip: {\r\n callbacks: {\r\n label: (ctx: any) => {\r\n let label: string\r\n if (!this.sortedWeaponList) {\r\n label = ctx.dataset.labels[ctx.dataIndex]\r\n } else {\r\n label = this.sortedWeaponList[ctx.dataIndex]\r\n }\r\n label += ' (' + this.weapons[label].kills + ' kills)'\r\n return label\r\n }\r\n }\r\n }\r\n }\r\n }\r\n return options\r\n },\r\n weapons (): { [key: string]: Weapon } {\r\n const { weapon: _, ...withoutWeapon } = this.filters || {}\r\n const data = this.store.getWeaponList(withoutWeapon)?.value.data\r\n if (!data) return this.store.fetchWeapons(withoutWeapon).value.data\r\n return data\r\n },\r\n sortedWeaponList (): string[] {\r\n if (!this.weapons) return []\r\n const weapons = Object.keys(this.weapons)\r\n weapons.sort((a, b) => {\r\n if (Number(this.weapons[a].kills) < Number(this.weapons[b].kills)) {\r\n return -1\r\n }\r\n if (Number(this.weapons[a].kills) > Number(this.weapons[b].kills)) {\r\n return 1\r\n }\r\n return 0\r\n })\r\n return weapons\r\n }\r\n }\r\n})\r\n","import { render } from \"./WeaponChart.vue?vue&type=template&id=53c5074f&scoped=true&ts=true\"\nimport script from \"./WeaponChart.vue?vue&type=script&lang=ts\"\nexport * from \"./WeaponChart.vue?vue&type=script&lang=ts\"\n\nimport \"./WeaponChart.vue?vue&type=style&index=0&id=53c5074f&scoped=true&lang=css\"\n\nimport exportComponent from \"C:\\\\Users\\\\legon\\\\Documents\\\\Code\\\\Tone\\\\ToneAPI_webclient\\\\node_modules\\\\vue-loader\\\\dist\\\\exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-53c5074f\"]])\n\nexport default __exports__","\r\nimport { Player, Weapon, Server, useKillStore, Filters } from '@/stores/kill'\r\nimport PlayerList from '@/components/PlayerList.vue'\r\nimport PlayerChart from '@/components/PlayerChart.vue'\r\nimport WeaponChart from '@/components/WeaponChart.vue'\r\nimport { defineComponent } from 'vue'\r\nimport VueMultiselect from 'vue-multiselect'\r\nimport 'vue-multiselect/dist/vue-multiselect.css'\r\nimport weapons from '../stores/weapons.json'\r\n\r\nexport default defineComponent({\r\n name: 'PlayerView',\r\n components: {\r\n VueMultiselect, PlayerList, PlayerChart, WeaponChart\r\n },\r\n\r\n data () {\r\n return {\r\n model: { server: undefined, weapon: undefined } as unknown as {weapon:Weapon | Weapon[], server: (Server& {name?:string}) | (Server& {name?:string})[]},\r\n filters: {} as Filters,\r\n store: useKillStore(),\r\n playerHighlighted: undefined as (Player & {id:string}) | undefined,\r\n weaponLocale: weapons as {[key:string]:string}\r\n }\r\n },\r\n computed: {\r\n servers (): { [key: string]: Server } {\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n const { server: _, player: _1, ...withoutServer } = this.filters\r\n const data = this.store.getServerList(withoutServer)?.value.data\r\n if (!data) return this.store.fetchServers(withoutServer).value.data\r\n return data\r\n },\r\n groupedServers () {\r\n const hosts = [] as {id:string, servers:(Server& {name?:string})[] }[]\r\n Object.entries(this.servers).forEach((e) => {\r\n if (!hosts.find(host => host.id === e[1].host + 'sfdsdfsd')) hosts.push({ id: e[1].host + 'sfdsdfsd', servers: [] as Server[] })\r\n hosts.find(host => host.id === e[1].host + 'sfdsdfsd')?.servers.push({ name: e[0], ...e[1] })\r\n })\r\n return hosts\r\n },\r\n weapons (): { [key: string]: Weapon } {\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n const { weapon: _, player: _1, ...withoutWeapons } = this.filters\r\n const data = this.store.getWeaponList(withoutWeapons)?.value.data\r\n if (!data) return this.store.fetchWeapons(withoutWeapons).value.data\r\n return data\r\n },\r\n players (): { [key: string]: Player } {\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n const { player: _, ...withoutPlayers } = this.filters\r\n const data = this.store.getPlayerList(withoutPlayers)?.value.data\r\n if (!data) return this.store.fetchPlayers(withoutPlayers).value.data\r\n return data\r\n },\r\n sortedWeaponList (): string[] {\r\n if (!this.weapons) return []\r\n const weapons = Object.keys(this.weapons)\r\n return weapons.sort()\r\n },\r\n sortedServerList ():string[] {\r\n if (!this.servers) return []\r\n const servers = Object.keys(this.servers)\r\n return servers.sort()\r\n },\r\n sortedPlayerList (): Player[] {\r\n if (!this.players) return []\r\n const players = Object.entries(this.players).map(e => ({ id: e[0], ...e[1] }))\r\n return players.sort((a: Player, b: Player) => {\r\n if (a.username < b.username) {\r\n return -1\r\n }\r\n if (a.username > b.username) {\r\n return 1\r\n }\r\n return 0\r\n })\r\n }\r\n },\r\n watch: {\r\n model: {\r\n handler (newModel) {\r\n this.filters.server = newModel.server?.name\r\n this.filters.weapon = newModel.weapon\r\n },\r\n deep: true\r\n }\r\n },\r\n methods: {\r\n highlight_player (playerid:string) {\r\n const player = this.players[playerid]\r\n if (player) {\r\n this.playerHighlighted = { id: playerid, ...player }\r\n return\r\n }\r\n this.playerHighlighted = undefined\r\n }\r\n }\r\n})\r\n","import { render } from \"./PlayerView.vue?vue&type=template&id=16cf505a&scoped=true&ts=true\"\nimport script from \"./PlayerView.vue?vue&type=script&lang=ts\"\nexport * from \"./PlayerView.vue?vue&type=script&lang=ts\"\n\nimport \"./PlayerView.vue?vue&type=style&index=0&id=16cf505a&scoped=true&lang=css\"\n\nimport exportComponent from \"C:\\\\Users\\\\legon\\\\Documents\\\\Code\\\\Tone\\\\ToneAPI_webclient\\\\node_modules\\\\vue-loader\\\\dist\\\\exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-16cf505a\"]])\n\nexport default __exports__","import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'\r\nimport HomeView from '../views/HomeView.vue'\r\nimport PlayerView from '../views/PlayerView.vue'\r\n\r\nconst routes: Array = [\r\n {\r\n path: '/',\r\n name: 'home',\r\n component: PlayerView\r\n }\r\n // {\r\n // path: '/players',\r\n // name: 'players',\r\n // component: PlayerView\r\n // },\r\n // {\r\n // path: '/about',\r\n // name: 'about',\r\n // // route level code-splitting\r\n // // this generates a separate chunk (about.[hash].js) for this route\r\n // // which is lazy-loaded when the route is visited.\r\n // component: () => import(/* webpackChunkName: \"about\" */ '../views/AboutView.vue')\r\n // }\r\n]\r\n\r\nconst router = createRouter({\r\n history: createWebHistory(process.env.BASE_URL),\r\n routes\r\n})\r\n\r\nexport default router\r\n","import { createApp } from 'vue'\r\nimport App from './App.vue'\r\nimport router from './router'\r\nimport { createPinia } from 'pinia'\r\n\r\nconst pinia = createPinia()\r\n\r\ncreateApp(App).use(pinia).use(router).mount('#app')\r\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n","var deferred = [];\n__webpack_require__.O = function(result, chunkIds, fn, priority) {\n\tif(chunkIds) {\n\t\tpriority = priority || 0;\n\t\tfor(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];\n\t\tdeferred[i] = [chunkIds, fn, priority];\n\t\treturn;\n\t}\n\tvar notFulfilled = Infinity;\n\tfor (var i = 0; i < deferred.length; i++) {\n\t\tvar chunkIds = deferred[i][0];\n\t\tvar fn = deferred[i][1];\n\t\tvar priority = deferred[i][2];\n\t\tvar fulfilled = true;\n\t\tfor (var j = 0; j < chunkIds.length; j++) {\n\t\t\tif ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every(function(key) { return __webpack_require__.O[key](chunkIds[j]); })) {\n\t\t\t\tchunkIds.splice(j--, 1);\n\t\t\t} else {\n\t\t\t\tfulfilled = false;\n\t\t\t\tif(priority < notFulfilled) notFulfilled = priority;\n\t\t\t}\n\t\t}\n\t\tif(fulfilled) {\n\t\t\tdeferred.splice(i--, 1)\n\t\t\tvar r = fn();\n\t\t\tif (r !== undefined) result = r;\n\t\t}\n\t}\n\treturn result;\n};","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = function(module) {\n\tvar getter = module && module.__esModule ?\n\t\tfunction() { return module['default']; } :\n\t\tfunction() { return module; };\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// no baseURI\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t143: 0\n};\n\n// no chunk on demand loading\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\n__webpack_require__.O.j = function(chunkId) { return installedChunks[chunkId] === 0; };\n\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = function(parentChunkLoadingFunction, data) {\n\tvar chunkIds = data[0];\n\tvar moreModules = data[1];\n\tvar runtime = data[2];\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0;\n\tif(chunkIds.some(function(id) { return installedChunks[id] !== 0; })) {\n\t\tfor(moduleId in moreModules) {\n\t\t\tif(__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t\t}\n\t\t}\n\t\tif(runtime) var result = runtime(__webpack_require__);\n\t}\n\tif(parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\tfor(;i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {\n\t\t\tinstalledChunks[chunkId][0]();\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\treturn __webpack_require__.O(result);\n}\n\nvar chunkLoadingGlobal = self[\"webpackChunktoneapi_webclient\"] = self[\"webpackChunktoneapi_webclient\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));","// startup\n// Load entry module and return exports\n// This entry module depends on other loaded chunks and execution need to be delayed\nvar __webpack_exports__ = __webpack_require__.O(undefined, [998], function() { return __webpack_require__(4545); })\n__webpack_exports__ = __webpack_require__.O(__webpack_exports__);\n"],"names":["_hoisted_1","_createStaticVNode","render","_ctx","_cache","$props","$setup","$data","$options","_component_router_link","_resolveComponent","_component_router_view","_openBlock","_createElementBlock","_Fragment","_createElementVNode","_createVNode","to","class","default","_withCtx","_createTextVNode","_","removeNullEntries","a","Object","fromEntries","entries","filter","e","undefined","objectEqual","b","assert","deepStrictEqual","useKillStore","defineStore","state","servers","players","weapons","maps","gamemodes","hosts","getters","getPlayerList","filters","find","value","getWeaponList","getServerList","actions","fetchPlayers","entry","this","ref","data","push","fetch","URLSearchParams","then","async","response","json","fetchWeapons","fetchServers","defineComponent","setup","props","ctx","store","__exports__","id","_hoisted_2","_component_VueMultiselect","_component_PlayerList","_component_PlayerChart","_component_WeaponChart","selectLabel","deselectLabel","placeholder","modelValue","model","server","$event","options","groupedServers","group_label","multiple","name","label","weapon","weaponLocale","sortedWeaponList","playerHighlighted","sortedPlayerList","username","onHighlightPlayer","highlight_player","player","_withScopeId","n","_pushScopeId","_popScopeId","_hoisted_3","onKeydown","args","selectNextPlayer","tabindex","onClick","updateSort","_normalizeClass","sortingData","argument","_renderList","playerList","index","key","$emit","ref_for","_toDisplayString","kills","deaths","Math","round","max","max_distance","total_distance","type","String","emits","direction","computed","withoutPlayer","map","collator","Intl","Collator","numeric","sensitivity","sort","compare","reverse","slice","watch","handler","newval","immediate","newElement","$refs","scrollIntoView","behavior","block","updated","element","methods","values","Home","Infinity","End","PageDown","PageUp","ArrowUp","ArrowDown","ArrowRight","ArrowLeft","keys","includes","preventDefault","findIndex","nextIndex","length","_component_Scatter","chart","chartOptions","ChartJS","LinearScale","PointElement","LineElement","Tooltip","Legend","annotationPlugin","dataLabel","refreshColors","playerData","components","Scatter","mounted","cut","colors","container","style","getComputedStyle","fg","getPropertyValue","bg","orange","cyan","currentLine","playerIndex","defaultColor","borderColor","Array","fill","backgroundColor","pointRadius","hoverRadius","pointStyle","datasets","labels","y","x","chartStaticOptions","responsive","maintainAspectRatio","animation","duration","layout","autoPadding","scales","title","text","display","color","ticks","onHover","native","target","cursor","chartStaticPlugins","endX","endY","maxX","maxY","tooltip","callbacks","dataIndex","dataset","parsed","annotation","annotations","line","yMin","xMin","yMax","xMax","borderWidth","borderDash","legend","plugins","datalabels","formatter","context","borderRadius","align","anchor","clamp","_component_Doughnut","ArcElement","Doughnut","yellow","green","purple","red","pink","chartData","weaponId","padding","withoutWeapon","Number","VueMultiselect","PlayerList","PlayerChart","WeaponChart","_1","withoutServer","forEach","host","withoutWeapons","withoutPlayers","sortedServerList","newModel","deep","playerid","routes","path","component","PlayerView","router","createRouter","history","createWebHistory","process","pinia","createPinia","createApp","App","use","mount","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","exports","module","__webpack_modules__","m","deferred","O","result","chunkIds","fn","priority","notFulfilled","i","fulfilled","j","every","splice","r","getter","__esModule","d","definition","o","defineProperty","enumerable","get","g","globalThis","Function","window","obj","prop","prototype","hasOwnProperty","call","installedChunks","chunkId","webpackJsonpCallback","parentChunkLoadingFunction","moreModules","runtime","some","chunkLoadingGlobal","self","bind","__webpack_exports__"],"sourceRoot":""}
\ No newline at end of file