// ==UserScript==
// @name GeoHeatmap
// @namespace https://greasyfork.org/users/1179204
// @version 2.0.6
// @description map visualization of your geoguessr activities
// @author KaKa
// @match *://map-making.app/maps/*
// @require https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js
// @require https://cdn.jsdelivr.net/npm/sweetalert2@11
// @license BSD
// @icon https://www.svgrepo.com/show/185727/map-position.svg
// @grant GM_xmlhttpRequest
// @grant GM_setClipboard
// @grant GM_addStyle
// ==/UserScript==
(function(){
const IS_FRIENDS_ACTIVITIES_INCLUDED = "NO" // If you want to focus only on your own activities, please replace "YES" with "NO"
/* ############################################################################### */
/* ##### DON'T MODIFY ANYTHING BELOW HERE UNLESS YOU KNOW WHAT YOU ARE DOING ##### */
/* ############################################################################### */
let pinSvg=`<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><title>70 Basic icons by Xicons.co</title><path d="M24,1.32c-9.92,0-18,7.8-18,17.38A16.83,16.83,0,0,0,9.57,29.09l12.84,16.8a2,2,0,0,0,3.18,0l12.84-16.8A16.84,16.84,0,0,0,42,18.7C42,9.12,33.92,1.32,24,1.32Z" fill="#a9a3a2"></path><path d="M25.37,12.13a7,7,0,1,0,5.5,5.5A7,7,0,0,0,25.37,12.13Z" fill="#f3edec"></path></g></svg>`
let linkSvg=`<svg fill="#d3cfcf" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="29px" height="29px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve" stroke="#d3cfcf"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <path d="M78.746,33.028L61.62,17.213c-0.368-0.336-0.85-0.713-1.349-0.713H42.634c-5.407,0-9.134,2.81-9.134,6.877V28.5h-3.358 c-4.946,0-8.642,3.124-8.642,7.369V75.87c0,4.492,4.077,7.63,8.642,7.63h29.231c4.677,0,8.127-3.288,8.127-7.63V71.5h4.365 c4.41,0,7.635-3.513,7.635-8.122V35.055c0-0.029,0.242-0.057,0.241-0.085c0.001-0.03,0.134-0.059,0.134-0.089 C79.875,34.041,79.48,33.324,78.746,33.028z M61.5,23.165L72.649,32.5H61.5V23.165z M63.5,75.87c0,2.363-1.938,3.63-4.127,3.63 H30.142c-2.323,0-4.642-1.381-4.642-3.63V35.869c0-2.6,3.095-3.369,4.642-3.369H45.5v15.381c0,1.104,1.396,1.619,2.5,1.619h15.5 V75.87z M61.216,45.5H49.5v-9.878L61.216,45.5z M71.865,67.5H67.5V47.547c0-0.562,0.014-1.097-0.4-1.476l-17.43-16.059 c-0.324-0.667-0.94-1.132-1.732-1.132c-0.036,0-0.039-0.182-0.075-0.18c-0.038-0.002-0.044-0.201-0.083-0.201H37.5v-5.123 c0-2.063,3.02-2.877,5.134-2.877H57.5v14.381c0,1.104,1.396,1.619,2.5,1.619h15.5v26.878C75.5,65.776,74.068,67.5,71.865,67.5z"></path> </g> </g></svg>`
let earthSvg=`<svg viewBox="0 0 1024 1024" class="icon" version="1.1" xmlns="http://www.w3.org/2000/svg" width="64px" height="64px" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path d="M800.3741 715.205382l-26.369787 44.840142a25.935191 25.935191 0 0 0-3.579031 13.140156v14.520639a45.364215 45.364215 0 0 0 5.611409 21.84487l13.485277 24.529143 31.175914-66.467714 5.867054-64.588723a1.712822 1.712822 0 0 0-1.70004-1.866209 28.402165 28.402165 0 0 0-24.490796 14.047696zM183.962749 302.798783h-7.043021l-14.060478 16.335719 10.570923 31.482688 0.677459 2.096289a12.386003 12.386003 0 0 0 17.153783 7.362578 19.927532 19.927532 0 0 0 11.043866-21.090717l-3.195563-20.068137zM169.352634 731.247109h24.452449a16.616928 16.616928 0 0 1 15.965034 11.900277l3.553466 11.887495A20.643338 20.643338 0 0 0 229.454786 769.491609c7.413707 1.278225 15.696606 2.735402 17.42221 2.735402s12.501043 7.963343 21.72983 15.134187a17.217694 17.217694 0 0 1 2.466975 24.938175l-2.083508 2.403064q-0.268427 0.306774-0.562419 0.600765l-22.113297 22.35616L193.012584 801.447241l-29.309706-61.226991a6.263304 6.263304 0 0 1 5.649756-8.973141zM315.862814 146.484615l-30.089423 37.375307a11.248382 11.248382 0 0 1-0.805282 0.894758L265.193964 204.516042a11.248382 11.248382 0 0 0-1.112056 1.278226l-18.930516 25.807368a11.248382 11.248382 0 0 0-2.070725 8.244553l3.834676 26.676561a11.248382 11.248382 0 0 1 0 3.323386l-0.102258 0.62633a11.248382 11.248382 0 0 0 18.010194 10.634834l72.526502-56.114089a11.248382 11.248382 0 0 0 4.37153-9.062617c-0.153387-10.507012-0.421814-32.28797 0.089476-34.320348s25.82015-21.576442 36.250468-29.527004a11.2356 11.2356 0 0 0 4.42266-8.947577v-15.006365a11.248382 11.248382 0 0 0-16.616929-9.880681l-46.565746 25.411118a11.248382 11.248382 0 0 0-3.438426 2.824878z" fill="#2FA65B"></path><path d="M509.194385 93.374356a5.483586 5.483586 0 0 0-0.703024 4.831691c3.208345 9.791206 13.804833 44.520586 5.176812 50.553809-10.072415 7.043021-27.187851 21.359144-16.105638 31.214261s-45.300303-27.622448-60.408926 9.855117-34.21809 46.425142-33.233857 64.537594 15.09584 0 21.141846 0 6.966328 32.262406-17.115436 42.33482-73.497953-23.161442-66.467714 14.060478 26.178053 56.587032 6.046006 64.435336-20.132048 58.38933 2.019596 51.346309 34.307566-3.016612 34.307566-13.089027 11.00552-58.38933 24.081764-51.346309 29.194665 1.278225 32.211276 11.069431-18.125234 23.161442 3.016612 25.168255c14.418381 1.367701 19.467371-18.32975 21.231322-30.996962a5.483586 5.483586 0 0 1 8.947576-3.425644c9.100964 7.669352 25.359989 7.669352 26.676562 7.4904 10.826568-1.546653 31.712769-29.399181 32.722566-32.466922 0.383468-1.150403 2.671491-6.109917 5.355764-11.798019 6.135481-13.012333 12.015317-20.886201 25.564506-25.564505l9.714512-1.81508a15.172534 15.172534 0 0 0 2.876006-0.140605 5.496369 5.496369 0 0 1 2.901572 0.447379l28.721721 15.236445a5.496369 5.496369 0 0 1 1.086492 9.369391c-9.484431 7.26032-25.564505 19.556847-31.840591 24.375756-9.177657 7.043021-26.293094 0.217298-29.309706 17.115436s-2.019596 19.173379 9.062617 26.178054c7.988908 5.112901 25.423901-1.994031 34.512083-6.391127a5.483586 5.483586 0 0 1 7.669351 3.425644l6.570078 22.458418a5.496369 5.496369 0 0 1-4.077539 6.902417l-37.822685 8.449069-43.843127 8.321246a68.257229 68.257229 0 0 1-32.224059-1.648911l-21.934345-6.544513a5.496369 5.496369 0 0 0-0.830847-0.178951l-27.699141-3.834676a82.995166 82.995166 0 0 0-52.931308 10.455882l-37.324178 21.72983a5.509151 5.509151 0 0 0-0.805282 0.562419l-1.431612 1.278225a198.124916 198.124916 0 0 0-56.587033 79.697345l-0.306774 0.805282a71.209929 71.209929 0 0 0-1.955684 45.786029l7.388142 25.181038a99.062458 99.062458 0 0 0 29.143536 46.01611l0.715806 0.639112a100.979796 100.979796 0 0 0 56.996064 25.065998l25.845715 2.55645a36.173775 36.173775 0 0 0 31.508253-12.93564 5.496369 5.496369 0 0 1 4.333184-1.994031l14.201082 0.268427a46.75748 46.75748 0 0 1 44.367199 35.061719l6.889634 26.702126a5.496369 5.496369 0 0 0 1.278226 2.364717l21.44862 23.174224a32.224059 32.224059 0 0 1 7.004674 31.840591l-1.393266 4.665522a40.583652 40.583652 0 0 0 10.302496 41.619015L600.613056 887.088333a5.496369 5.496369 0 0 0 1.482741 1.022581l37.899379 17.895153a5.496369 5.496369 0 0 0 3.476773 0.409032l35.176759-7.375359a5.496369 5.496369 0 0 0 4.115886-3.745201l23.340393-75.082952 17.294388-48.649253a172.113032 172.113032 0 0 0 9.177657-73.868638l-1.201532-12.782253a116.535797 116.535797 0 0 1 5.04899-46.540182L754.153475 583.139148a5.496369 5.496369 0 0 1 0.383467-0.894758l28.721722-54.068929a5.496369 5.496369 0 0 0-5.803143-7.988908L740.617069 526.628809a42.462643 42.462643 0 0 1-18.764347-0.933105L674.750121 512.568331a5.496369 5.496369 0 0 1-3.131652-2.313588L641.771909 463.995771l-0.217298-0.357903a5.496369 5.496369 0 0 1 8.385158-6.800159l37.96329 32.364664a5.496369 5.496369 0 0 0 2.121854 1.124838l37.196355 10.085198a5.496369 5.496369 0 0 0 5.112901-1.278226L759.266376 474.860686a5.496369 5.496369 0 0 0 1.469959-2.185766l16.847009-45.84994a5.496369 5.496369 0 0 0-0.230081-4.320401l-5.534715-11.286729a5.496369 5.496369 0 0 0-4.320402-3.042176L718.056393 402.640958a5.496369 5.496369 0 0 1-3.400079-1.700039l-10.813786-11.504028a5.496369 5.496369 0 0 1 2.313588-8.947577l12.322092-3.988062a5.496369 5.496369 0 0 1 1.188749-0.242863l72.718235-6.697901a5.496369 5.496369 0 0 1 5.023426 2.339153L821.899414 407.280916a5.496369 5.496369 0 0 0 2.198547 1.853427L867.711007 429.483689a5.406893 5.406893 0 0 1 0.651895 0.357903c3.272257 2.109072 31.073656 20.170395 31.073656 23.953941V425.265545a5.44524 5.44524 0 0 0-0.153387-1.278225l-11.2356-46.016109a122.581803 122.581803 0 0 1-3.400079-23.902813L883.254226 320.834541a5.496369 5.496369 0 0 0-1.13762-3.118869L752.325613 149.130542a5.496369 5.496369 0 0 0-2.697056-1.891774L525.594015 76.489a5.496369 5.496369 0 0 0-6.173828 2.109071z" fill="#178E3B"></path><path d="M511.993698 965.558582a453.233114 453.233114 0 0 1-176.395086-870.637574 453.233114 453.233114 0 0 1 352.790173 835.013436 450.318761 450.318761 0 0 1-176.395087 35.624138z m0-852.576251c-220.250995 0-399.445395 179.1944-399.445395 399.445395s179.1944 399.445395 399.445395 399.445395 399.445395-179.1944 399.445395-399.445395-179.181618-399.445395-399.445395-399.445395z" fill="#203529"></path><path d="M642.359893 920.002634a19.019992 19.019992 0 0 1-8.11673-1.81508l-37.899379-17.895154a18.866605 18.866605 0 0 1-5.112902-3.540684l-54.733605-53.238082A53.685461 53.685461 0 0 1 522.794702 788.077004l1.469959-4.512135a18.828258 18.828258 0 0 0-4.090321-18.585395l-21.44862-23.174224a18.968863 18.968863 0 0 1-4.435442-8.103948l-6.889634-26.702126a33.438373 33.438373 0 0 0-31.636075-24.989304l-10.583705-0.204516a49.505664 49.505664 0 0 1-40.558088 14.827413l-25.845715-2.556451a113.65979 113.65979 0 0 1-64.57594-28.402165l-0.715806-0.639113a112.381565 112.381565 0 0 1-33.093252-52.304977l-7.388142-25.181038a84.107222 84.107222 0 0 1 2.313587-54.52909l0.306775-0.805282a212.1087 212.1087 0 0 1 60.43449-85.104238l1.431612-1.278225a18.956081 18.956081 0 0 1 2.748185-1.942903l5.598626-3.246692c-10.622052 0.140605-19.735798-6.672336-23.928377-18.534266-6.391126-17.895154-1.278225-50.809454 20.783943-59.41191l0.332339-0.140605c-0.447379-3.23391-2.812096-9.778423-4.614394-14.75072a215.866683 215.866683 0 0 1-10.085197-34.512082c-2.249676-11.913059-0.242863-21.065152 5.982094-27.200633 10.225802-10.110762 25.98632-6.915199 41.184418-3.834676 9.637818 1.968467 21.627571 4.409877 27.277328 2.04516a18.917734 18.917734 0 0 0 9.497213-8.845319 16.847009 16.847009 0 0 1-11.35064-1.380483c-6.391126-3.182781-9.867899-9.573907-10.391971-18.994427-0.7925-14.201083 6.391126-24.28628 13.958219-34.882768 6.058788-8.500198 13.613099-19.083903 20.221524-35.483533 6.902416-17.115436 21.461402-26.139707 41.005467-25.411118a79.249966 79.249966 0 0 1 17.166565 2.735402c3.310603-7.439271 10.149109-14.916889 20.681685-22.63737 0.319556-5.112901-1.70004-18.406444-7.822739-37.068532a19.019992 19.019992 0 0 1 2.415846-16.616929l10.225802-14.776284a18.828258 18.828258 0 0 1 21.244104-7.273102l224.034542 70.749769a18.828258 18.828258 0 0 1 9.292697 6.493384l129.778212 168.649041a18.815476 18.815476 0 0 1 3.911369 10.72431l1.41883 33.233857a109.4033 109.4033 0 0 0 3.016611 21.244104l11.235601 46.01611a18.892169 18.892169 0 0 1 0.536854 4.48657v28.887891a13.421365 13.421365 0 0 1-25.628416 5.573062c-3.706853-3.374515-14.277776-10.928826-25.679546-18.304185l-43.114538-20.119266a18.943298 18.943298 0 0 1-7.554311-6.391126l-21.870435-31.597729L722.197843 389.475238l0.191734 0.204516 46.591311 5.112901a18.828258 18.828258 0 0 1 14.891324 10.468665l5.534715 11.286729a19.00721 19.00721 0 0 1 0.779718 14.852978l-16.847009 45.84994a18.981645 18.981645 0 0 1-5.112901 7.503182L741.371222 509.193816a18.866605 18.866605 0 0 1-9.561125 4.627176 29.105189 29.105189 0 0 0 6.506167-0.39625l36.825669-6.455038A18.917734 18.917734 0 0 1 795.056683 534.46433l-28.389383 53.442598-17.511686 54.631348a102.539231 102.539231 0 0 0-4.461006 41.184418l1.201531 12.782252a186.787058 186.787058 0 0 1-9.893463 79.620652L718.836111 824.455295l-23.2637 74.827307a18.930516 18.930516 0 0 1-14.175518 12.897293l-35.17676 7.37536a18.815476 18.815476 0 0 1-3.86024 0.447379z m-33.336115-43.459659l34.294784 16.246243 28.005916-5.867054 21.95991-70.634728 0.166169-0.51129L710.693816 767.126892a159.778158 159.778158 0 0 0 8.461851-68.103842l-1.201532-12.782252a129.241356 129.241356 0 0 1 5.624191-51.908728L741.371222 579.036045a18.968863 18.968863 0 0 1 1.278225-3.093305l21.116282-39.740024-20.835072 3.655724a56.241912 56.241912 0 0 1-24.695312-1.278225l-47.115384-13.16572a18.892169 18.892169 0 0 1-10.801003-7.950561l-29.84656-46.195061c-0.255645-0.39625-0.498508-0.805282-0.728588-1.278226a18.917734 18.917734 0 0 1 28.887891-23.429869l36.608371 31.214261 31.303737 8.487416 22.305031-20.157612 15.006364-40.839298-2.134636-4.345966-45.172481-5.010643a18.930516 18.930516 0 0 1-11.721325-5.867054l-10.813786-11.504027a18.917734 18.917734 0 0 1 7.988908-30.933051l12.322091-3.988063a18.930516 18.930516 0 0 1 4.077539-0.843629l72.718235-6.6979a18.943298 18.943298 0 0 1 17.30717 8.218988l23.289265 33.642889 41.670143 19.441806a18.956081 18.956081 0 0 1 2.262459 1.278226c1.060927 0.677459 5.189595 3.361732 10.149109 6.736247l-10.788222-44.137118a136.335507 136.335507 0 0 1-3.757982-26.472046l-1.278225-30.7541-126.7616-164.750454-216.020069-68.231664-4.665522 6.749029c13.919873 44.367199 6.800158 56.446428-1.086492 61.955579s-11.580721 9.612254-13.152938 11.887494c6.97911 7.669352 3.527902 14.840195 2.21133 16.974832-0.945887 1.559435-6.237739 9.113746-17.064307 5.509151-1.124838-0.370685-2.377499-0.869193-3.962499-1.482741-29.552568-11.504027-36.582807-5.752014-39.791152 2.185765-7.797174 19.35233-16.731969 31.878938-23.2637 41.031031-1.41883 1.994031-2.658709 3.7452-3.732418 5.317417a16.962049 16.962049 0 0 1 2.466975-0.178952c6.391126 0 14.060478 4.090321 16.335719 15.556002 3.131652 15.619913-3.566248 42.258127-28.274343 52.586187-13.267978 5.547498-29.05406 2.32637-42.986716-0.51129a124.575834 124.575834 0 0 0-15.786082-2.556451c0.063911 0.62633 0.178952 1.380483 0.345121 2.288024a190.596169 190.596169 0 0 0 8.947577 30.408979c3.489555 9.650601 6.237739 17.281606 6.276086 24.848699 0 6.46782-2.224112 18.21471-17.498904 24.17124-1.278225 0.485726-3.757982 3.438426-5.253506 9.30548-1.751169 6.889634-1.073709 13.191285 0 16.220678a148.031268 148.031268 0 0 1 20.720032-4.499353l2.978265-0.485725c1.776733-14.060478 9.049835-48.201875 24.51636-57.430661a18.764347 18.764347 0 0 1 18.904952-0.511291c3.34895 1.802298 7.797174 2.236894 12.501043 2.709838 7.26032 0.715806 18.853823 1.853427 24.40132 11.964188a18.904952 18.904952 0 0 1 30.843576-11.273946c3.655724 3.093305 11.887495 4.269272 15.88834 4.37153 5.534715-2.927136 19.032774-18.674871 22.535111-24.490796 0.549637-1.380483 1.840644-4.307619 5.521934-12.130358 7.298666-15.49209 15.415397-26.344223 33.336114-32.56918a13.459712 13.459712 0 0 1 1.942903-0.51129l9.714512-1.81508a13.408583 13.408583 0 0 1 3.157216-0.204516l0.613548-0.063911a18.904952 18.904952 0 0 1 9.970157 1.53387l0.7925 0.383468 28.440512 15.09584a18.917734 18.917734 0 0 1 3.23391 32.032326c-9.471649 7.247537-25.564505 19.544064-31.815027 24.362973-6.07157 4.665522-12.871728 5.752014-18.316968 6.621207a36.493331 36.493331 0 0 0-5.700884 1.188749 7.298666 7.298666 0 0 0-0.242863 1.009798 68.346705 68.346705 0 0 0-1.278225 9.522779 44.622844 44.622844 0 0 0 3.834675 2.55645c1.955685 0.217298 9.088182-0.562419 22.074951-6.774594a18.904952 18.904952 0 0 1 26.293093 11.772455l6.570078 22.458418a18.917734 18.917734 0 0 1-14.060478 23.762207l-37.822685 8.449069-0.421815 0.089476-43.843126 8.321247a82.023715 82.023715 0 0 1-38.564056-1.981249l-21.359145-6.391127-27.085593-3.706853a69.90614 69.90614 0 0 0-44.367199 8.768625l-36.838452 21.384709-0.894758 0.754153a185.189276 185.189276 0 0 0-52.752356 74.290452l-0.306774 0.805282a57.520137 57.520137 0 0 0-1.610564 37.183573l7.388142 25.181038a85.564399 85.564399 0 0 0 25.19382 39.829499l0.715806 0.639113a86.919318 86.919318 0 0 0 49.416189 21.729829l25.845714 2.556451a22.714063 22.714063 0 0 0 19.825274-8.129513 18.815476 18.815476 0 0 1 14.942454-6.851287l14.201082 0.268427a60.357797 60.357797 0 0 1 57.111105 45.121352l6.391126 24.759223 20.093702 21.72983a45.683771 45.683771 0 0 1 9.919028 45.108569L548.359207 796.33434a26.983335 26.983335 0 0 0 6.889634 27.852528zM449.13058 411.588535l17.626726 2.415846a18.994427 18.994427 0 0 1 2.83766 0.613548l21.934346 6.544513a55.065944 55.065944 0 0 0 25.884061 1.278226l43.638611-8.295682 29.399181-6.557296-1.661693-5.67532c-17.243259 6.902416-30.051076 7.4904-38.98587 1.802297-17.038743-10.852132-18.713218-19.467371-15.070276-39.855063a33.233857 33.233857 0 0 1 1.981249-6.915199c-3.285039 4.154232-6.263304 7.515965-6.518949 7.797174-14.610115 16.450759-23.071966 19.326766-28.120956 20.055355A61.661587 61.661587 0 0 1 475.500367 380.655484c-5.803143 22.790756-17.562815 29.360834-26.369787 30.933051z m-41.567886-34.908332c-4.76778 8.819754-10.225802 30.677406-10.225802 36.915146v0.102258a97.068427 97.068427 0 0 1 34.333131-4.218144 18.470355 18.470355 0 0 1-9.394956-8.346811c-4.358748-8.270117-0.600766-16.143985 2.198548-21.256886h-0.242863a69.561019 69.561019 0 0 1-16.668058-3.246692z m153.923887-9.356609z m-217.374989-5.176812z m201.346044-18.559831a23.37874 23.37874 0 0 1-1.968467 3.834676c6.391126-5.470804 14.46951-6.774594 19.339548-7.554312 2.134636-0.345121 5.368546-0.856411 6.237739-1.41883l22.011039-16.859791-15.760517-8.423504h-0.703024l-7.337013 1.367701c-7.912214 2.939918-11.670197 7.068586-16.987614 18.342532-3.86024 8.308464-4.691087 10.276931-4.831691 10.660399z m0.089476-0.242863l-0.076694 0.217298z m-24.810353-10.034068z m53.685461-46.821392zM520.238251 100.979796zM259.352475 296.944511A24.733659 24.733659 0 0 1 234.951155 268.427305v-0.306774l-3.770765-26.357005a24.541925 24.541925 0 0 1 4.576047-18.074105l18.930516-25.807368a24.759223 24.759223 0 0 1 2.454192-2.850442l19.684669-19.684669L306.838543 138.048329a24.554707 24.554707 0 0 1 7.400925-6.186611l46.565746-25.411118a24.669748 24.669748 0 0 1 36.493331 21.653136V143.16123a24.810352 24.810352 0 0 1-9.714512 19.620757c-17.652291 13.44693-27.021682 21.026806-31.239825 24.644183 0 4.780562 0 13.830397 0.178951 28.325472a24.784788 24.784788 0 0 1-9.573907 19.876403l-72.526501 56.114089a24.605836 24.605836 0 0 1-15.070276 5.202377z m-1.41883-58.082556l3.681289 25.807368a24.68253 24.68253 0 0 1 0.242862 2.876007l67.822633-52.407236c-0.472943-32.748131 0-34.665469 0.51129-36.685065 1.278225-5.112901 1.725604-6.889634 40.276878-36.288815v-10.379189l-42.986716 23.455433-29.820995 37.068533a24.861481 24.861481 0 0 1-1.776733 1.968467l-19.646322 19.646322z m69.816664-83.966617zM246.378488 851.055163a13.383019 13.383019 0 0 1-7.541529-2.313588l-53.353122-36.237686a13.421365 13.421365 0 0 1-4.563264-5.304635l-29.322488-61.175861a19.684669 19.684669 0 0 1 17.754549-28.184867h24.452449a30.268374 30.268374 0 0 1 28.82398 21.486967l3.553466 11.887495a7.183626 7.183626 0 0 0 5.636974 5.04899c11.504027 2.057943 14.699591 2.454193 15.440961 2.55645 4.93395 0.076694 8.730279 1.802298 29.616479 17.895154a30.677406 30.677406 0 0 1 4.333184 44.367199l-2.083507 2.403063c-0.370685 0.421814-0.754153 0.830846-1.150403 1.278225l-22.113297 22.35616a13.408583 13.408583 0 0 1-9.484432 3.936934z m-42.820546-58.734451l41.133289 27.929222 14.264994-14.418381 2.070725-2.377499a3.834676 3.834676 0 0 0-0.549637-5.509151c-10.519794-8.129513-15.249227-11.376205-17.204912-12.628865-2.556451-0.332339-7.26032-1.060927-16.182332-2.658709a33.898534 33.898534 0 0 1-26.638214-23.787772l-3.553467-11.887495a3.259474 3.259474 0 0 0-3.106087-2.313588h-13.063462z m43.319054-6.710682z m0-26.842731z" fill="#203529"></path><path d="M789.637008 839.793999a13.421365 13.421365 0 0 1-11.759672-6.953546L764.379277 808.324093a58.938967 58.938967 0 0 1-7.273102-28.31269v-14.520639a39.38212 39.38212 0 0 1 5.432457-19.953096l26.369788-44.840143A41.9897 41.9897 0 0 1 824.979937 680.015841a15.134187 15.134187 0 0 1 15.070275 16.616928l-5.867054 64.57594a13.421365 13.421365 0 0 1-1.278225 4.486571l-31.175914 66.467714a13.421365 13.421365 0 0 1-11.721326 7.669351z m21.729829-124.332972l-25.679545 43.676957a12.526608 12.526608 0 0 0-1.725604 6.391127v14.520639a32.032325 32.032325 0 0 0 3.949716 15.338703l0.779717 1.406048 18.968863-40.430265zM185.854522 374.711736a25.807368 25.807368 0 0 1-24.554707-17.895154l-0.651895-2.019595-10.545358-31.405995a13.421365 13.421365 0 0 1 2.55645-13.037898l14.060478-16.335719a13.421365 13.421365 0 0 1 10.161891-4.65274h7.043021a13.421365 13.421365 0 0 1 9.791206 4.243708l15.09584 16.105638a13.421365 13.421365 0 0 1 3.46399 7.068586l3.195564 20.068137a33.553413 33.553413 0 0 1-18.483138 35.304582 25.794586 25.794586 0 0 1-11.133342 2.55645zM177.980655 322.112767l8.142295 24.28628v0.153387l0.281209 0.856411a6.557296 6.557296 0 0 0 2.556451-6.263304l-2.556451-16.003381-5.752014-6.135481z" fill="#203529"></path><path d="M511.993698 1023.999041A511.584097 511.584097 0 0 1 0.000569 511.99313a13.421365 13.421365 0 0 1 26.84273 0C26.843299 779.512895 244.486715 997.143529 511.993698 997.143529s485.163181-217.630633 485.163182-485.150399S779.513464 26.842731 511.993698 26.842731a13.421365 13.421365 0 0 1 0-26.842731 512.133734 512.133734 0 0 1 199.300884 983.76051 508.797566 508.797566 0 0 1-199.300884 40.238531z" fill="#203529"></path></g></svg>`
let logoSvg=`<svg width="128px" height="20px" viewBox="0 0 208 40" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M198.976 27.5223L195.587 23.115C195.643 23.0461 195.7 22.9772 195.753 22.9071C197.213 21.0294 197.956 18.696 197.956 15.9759C197.956 14.5014 197.708 13.0806 197.216 11.7497C196.69 10.3289 195.899 9.06117 194.862 7.97687C193.795 6.85868 192.469 5.98469 190.923 5.37594C189.464 4.80341 187.816 4.51364 186.023 4.51364H177.481C176.285 4.51364 175.188 4.93661 174.33 5.64001C173.292 5.17264 172.217 4.79173 171.115 4.51364C169.582 4.12455 168.069 3.92709 166.616 3.92709C164.91 3.92709 163.307 4.2005 161.852 4.73915C160.511 5.23573 159.328 5.9438 158.305 6.82363C158.037 6.59578 157.743 6.39014 157.421 6.21838C156.027 5.47292 154.549 4.89922 153.026 4.51364C151.491 4.12455 149.977 3.92709 148.526 3.92709C146.82 3.92709 145.217 4.2005 143.762 4.73915C142.772 5.10487 141.872 5.59327 141.05 6.17164C140.142 5.15628 138.825 4.51364 137.353 4.51364L126.854 4.51598C125.37 4.51598 124.039 5.16562 123.131 6.19618C122.221 5.16562 120.89 4.51598 119.405 4.51598H115.456C113.971 4.51598 112.641 5.16562 111.73 6.19618C110.822 5.16562 109.49 4.51598 108.007 4.51598H102.518C100.609 4.51598 98.9562 5.5921 98.1261 7.16831C97.5852 6.74067 97.0173 6.35158 96.4155 6.00689C94.0012 4.62698 91.2216 3.92709 88.1528 3.92709C85.8416 3.92709 83.6767 4.31384 81.7226 5.07916C79.7146 5.86435 77.9571 6.99305 76.4994 8.43489C76.1376 8.79126 75.7969 9.16749 75.4761 9.56009C72.823 3.92242 67.0999 0 60.4624 0C55.1643 0 50.4505 2.50278 47.411 6.37845C46.5012 5.24975 45.1243 4.51364 43.5601 4.51364H31.5472C29.3987 4.51364 27.5745 5.87953 26.8849 7.78641C26.1379 7.10639 25.33 6.50932 24.4531 6.00689C22.0376 4.62698 19.258 3.92709 16.1893 3.92709C13.878 3.92709 11.7143 4.31384 9.76016 5.07916C7.75099 5.86435 5.99355 6.99305 4.53585 8.43489C3.06059 9.89192 1.9155 11.6527 1.13221 13.6695C0.380524 15.6044 0 17.7251 0 19.972C0 22.2481 0.389891 24.3875 1.15796 26.3305C1.94477 28.3204 3.07464 30.066 4.51594 31.5184C5.96311 32.9766 7.70298 34.1181 9.68639 34.9092C11.6206 35.6803 13.7527 36.0729 16.0218 36.0729C17.6552 36.0729 19.2475 35.8626 20.7556 35.4478C22.2999 35.0225 23.7494 34.3892 25.0607 33.5666C25.7059 33.1623 26.3112 32.7043 26.8814 32.2042C27.5687 34.1158 29.3952 35.4852 31.5472 35.4852H43.5601C46.301 35.4852 48.5221 33.2687 48.5221 30.5357V28.4921C50.4435 31.3863 53.1469 34.7502 56.9545 38.55C57.9228 39.5174 59.1932 40 60.4624 40C61.7327 40 63.0019 39.5174 63.9702 38.55C68.485 34.0457 71.4472 30.1548 73.3932 26.9323C74.1613 28.6686 75.1869 30.2167 76.4795 31.5184C77.9267 32.9766 79.6666 34.1181 81.6488 34.9092C83.583 35.6803 85.7163 36.0729 87.9854 36.0729C89.6187 36.0729 91.2111 35.8626 92.7191 35.4478C94.2635 35.0225 95.7118 34.3892 97.0243 33.5666C98.2198 32.8165 99.2829 31.8888 100.21 30.8208C100.538 31.2625 100.892 31.6796 101.278 32.0652C103.748 34.5306 107.265 35.7796 111.73 35.7796C115.567 35.7796 118.697 34.8542 121.063 33.0338C121.923 34.499 123.515 35.4852 125.34 35.4852H137.353C138.498 35.4852 139.547 35.0961 140.387 34.4465C142.708 35.5191 145.179 36.0729 147.771 36.0729C149.594 36.0729 151.293 35.8112 152.822 35.2936C154.187 34.8309 155.403 34.1765 156.462 33.3622C159.35 35.1545 162.505 36.0729 165.861 36.0729C167.685 36.0729 169.385 35.8112 170.912 35.2936C171.976 34.9325 172.945 34.45 173.827 33.8751C174.733 34.8624 176.033 35.4852 177.481 35.4852H182.969C183.93 35.4852 184.828 35.2129 185.588 34.7409C186.363 35.22 187.267 35.4852 188.206 35.4852H195.04C196.928 35.4852 198.654 34.4149 199.488 32.7254C200.323 31.0346 200.125 29.0179 198.976 27.5223Z" fill="#CC302E"/><path fill-rule="evenodd" clip-rule="evenodd" d="M60.4627 4.9502C66.9012 4.9502 72.0985 10.159 72.0985 16.5842C72.0985 16.5842 72.4873 23.0503 60.4627 35.0489C48.4393 23.0503 48.8292 16.5842 48.8292 16.5842C48.8292 10.159 54.0266 4.9502 60.4627 4.9502ZM57.4115 13.5346C57.4115 15.216 58.7778 16.5819 60.4639 16.5819C62.1499 16.5819 63.5174 15.216 63.5186 13.5346C63.5186 11.8439 62.151 10.4827 60.4639 10.4827C58.7778 10.4827 57.4115 11.8428 57.4115 13.5346Z" fill="white"/><path d="M150.766 17.6802C150.318 17.5318 149.865 17.3916 149.408 17.2607C148.95 17.131 148.541 16.9768 148.176 16.8004C147.812 16.6228 147.518 16.4136 147.294 16.1706C147.071 15.9287 146.958 15.6214 146.958 15.2487C146.958 14.7089 147.182 14.2719 147.631 13.9354C148.078 13.6 148.656 13.4329 149.367 13.4329C149.926 13.4329 150.504 13.5486 151.102 13.7823C151.701 14.0148 152.298 14.3735 152.895 14.8573L155.08 10.582C154.033 10.0235 152.941 9.59933 151.803 9.31073C150.663 9.02213 149.571 8.87724 148.527 8.87724C147.406 8.87724 146.393 9.0455 145.488 9.38083C144.583 9.71617 143.816 10.187 143.191 10.7911C142.566 11.3975 142.081 12.1243 141.736 12.9714C141.39 13.8197 141.218 14.765 141.218 15.8084C141.218 16.8518 141.381 17.7129 141.709 18.3929C142.034 19.073 142.464 19.6361 142.995 20.0836C143.528 20.53 144.135 20.8899 144.816 21.1598C145.498 21.4297 146.193 21.6762 146.903 21.9006C147.5 22.105 148.009 22.2908 148.428 22.4591C148.848 22.6261 149.189 22.8084 149.45 23.0035C149.713 23.1998 149.899 23.4137 150.01 23.6462C150.122 23.8799 150.179 24.1545 150.179 24.4711C150.179 24.9922 149.96 25.4584 149.521 25.8685C149.081 26.2787 148.414 26.4831 147.518 26.4831C146.735 26.4831 145.941 26.3055 145.138 25.9527C144.335 25.5986 143.522 25.0576 142.702 24.3309L140.351 28.7464C142.627 30.3308 145.101 31.1218 147.77 31.1218C149.058 31.1218 150.21 30.9489 151.229 30.6053C152.246 30.2607 153.105 29.7769 153.806 29.1518C154.505 28.5279 155.036 27.7778 155.401 26.9026C155.766 26.0274 155.947 25.0483 155.947 23.9675C155.947 22.3656 155.531 21.0663 154.7 20.0696C153.869 19.073 152.559 18.2761 150.766 17.6802Z" fill="white"/><path d="M16.1895 22.9901H20.6984C20.6048 23.6047 20.4268 24.127 20.1657 24.5546C19.9046 24.9834 19.5733 25.3328 19.1717 25.6027C18.7701 25.8726 18.3181 26.0689 17.8135 26.1893C17.31 26.3108 16.7867 26.3715 16.2457 26.3715C15.3313 26.3715 14.5281 26.2173 13.8373 25.91C13.1465 25.6027 12.5669 25.1692 12.1009 24.6107C11.6338 24.0522 11.2849 23.3909 11.0507 22.6267C10.8177 21.8626 10.7018 21.0341 10.7018 20.1403C10.7018 19.1518 10.8364 18.258 11.1069 17.4564C11.3774 16.656 11.7509 15.9713 12.2274 15.4023C12.7028 14.8356 13.2776 14.3975 13.9485 14.089C14.6218 13.7817 15.3676 13.6286 16.1895 13.6286C17.1789 13.6286 18.0605 13.8799 18.8356 14.3823C19.6096 14.8859 20.2395 15.7143 20.7265 16.8699L25.9345 14.7176C24.9638 12.7254 23.6478 11.2532 21.9864 10.3033C20.3249 9.35336 18.3919 8.87781 16.1895 8.87781C14.4906 8.87781 12.9498 9.14772 11.5694 9.68753C10.1878 10.2285 9.0064 10.9833 8.0264 11.9519C7.0464 12.9206 6.29004 14.089 5.75848 15.4584C5.22574 16.8278 4.95996 18.3327 4.95996 19.972C4.95996 21.63 5.23042 23.1432 5.77253 24.5137C6.31346 25.882 7.06982 27.0562 8.04045 28.0342C9.01108 29.0122 10.1737 29.7717 11.5272 30.3115C12.8807 30.8525 14.3782 31.1224 16.0209 31.1224C17.2152 31.1224 18.3556 30.9728 19.4374 30.6749C20.5205 30.3769 21.5145 29.9434 22.4208 29.3756C23.3258 28.8077 24.115 28.0996 24.7859 27.2514C25.4591 26.4042 25.9907 25.4309 26.3829 24.3315C26.6627 23.5486 26.8489 22.7015 26.9426 21.789C27.0362 20.8752 27.0831 19.8599 27.0831 18.7429H16.1895V22.9901Z" fill="white"/><path d="M31.5471 30.5352H43.5599V25.8965H37.0348V22.2627H43.1958V17.624H37.0348V14.1035H43.5599V9.46488H31.5471V30.5352Z" fill="white"/><path d="M92.6607 22.9901H88.153V18.7429H99.0465C99.0465 19.8599 98.9985 20.8752 98.906 21.789C98.8123 22.7015 98.6262 23.5486 98.3463 24.3315C97.9541 25.4309 97.4225 26.4042 96.7493 27.2514C96.0773 28.0996 95.2881 28.8077 94.383 29.3756C93.478 29.9434 92.4839 30.3769 91.4009 30.6749C90.3179 30.9728 89.1786 31.1224 87.9844 31.1224C86.3417 31.1224 84.843 30.8525 83.4907 30.3115C82.136 29.7717 80.9745 29.0122 80.0039 28.0342C79.0321 27.0562 78.2769 25.882 77.736 24.5137C77.1939 23.1432 76.9234 21.63 76.9234 19.972C76.9234 18.3327 77.1892 16.8278 77.7219 15.4584C78.2535 14.089 79.0099 12.9206 79.9899 11.9519C80.9699 10.9833 82.1512 10.2285 83.5317 9.68753C84.9133 9.14772 86.4541 8.87781 88.153 8.87781C90.3553 8.87781 92.2872 9.35336 93.9498 10.3033C95.6113 11.2532 96.9273 12.7254 97.8979 14.7176L92.69 16.8699C92.2029 15.7143 91.573 14.8859 90.7991 14.3823C90.024 13.8799 89.1423 13.6286 88.153 13.6286C87.331 13.6286 86.5852 13.7817 85.912 14.089C85.2399 14.3975 84.6662 14.8356 84.1908 15.4023C83.7143 15.9713 83.3408 16.656 83.0703 17.4564C82.7999 18.258 82.6641 19.1518 82.6641 20.1403C82.6641 21.0341 82.7812 21.8626 83.0142 22.6267C83.2471 23.3909 83.5972 24.0522 84.0644 24.6107C84.5304 25.1692 85.11 25.6027 85.8008 25.91C86.4915 26.2173 87.2936 26.3715 88.2092 26.3715C88.7501 26.3715 89.2735 26.3108 89.7769 26.1893C90.2804 26.0689 90.7335 25.8726 91.1351 25.6027C91.5367 25.3328 91.8669 24.9834 92.1292 24.5546C92.3903 24.127 92.5682 23.6047 92.6607 22.9901Z" fill="white"/><path d="M115.456 20.6287C115.456 21.2433 115.431 21.8719 115.385 22.5145C115.339 23.1583 115.193 23.7402 114.951 24.2613C114.708 24.7836 114.34 25.2066 113.846 25.5326C113.351 25.8597 112.646 26.0221 111.73 26.0221C110.816 26.0221 110.107 25.8597 109.603 25.5326C109.098 25.2066 108.73 24.7836 108.497 24.2613C108.262 23.7402 108.123 23.1583 108.076 22.5145C108.029 21.8719 108.007 21.2433 108.007 20.6287V9.17106H102.518V21.3835C102.518 24.6621 103.274 27.055 104.787 28.5646C106.299 30.0731 108.613 30.8279 111.73 30.8279C114.848 30.8279 117.159 30.0731 118.662 28.5646C120.164 27.055 120.915 24.6621 120.915 21.3835V9.17106H115.456V20.6287Z" fill="white"/><path d="M137.353 30.5352H125.34V9.46488H137.353V14.1035H130.828V17.624H136.989V22.2627H130.828V25.8965H137.353V30.5352Z" fill="white"/><path d="M167.498 17.2607C167.954 17.3916 168.409 17.5318 168.857 17.6802C170.649 18.2761 171.96 19.073 172.79 20.0696C173.621 21.0663 174.037 22.3656 174.037 23.9675C174.037 25.0483 173.855 26.0274 173.491 26.9026C173.126 27.7778 172.594 28.5279 171.895 29.1518C171.194 29.7769 170.336 30.2607 169.318 30.6053C168.301 30.9489 167.149 31.1218 165.86 31.1218C163.19 31.1218 160.717 30.3308 158.44 28.7464L160.791 24.3309C161.613 25.0576 162.426 25.5986 163.228 25.9527C164.03 26.3055 164.825 26.4831 165.609 26.4831C166.504 26.4831 167.172 26.2787 167.611 25.8685C168.049 25.4584 168.268 24.9922 168.268 24.4711C168.268 24.1545 168.212 23.8799 168.101 23.6462C167.988 23.4137 167.802 23.1998 167.54 23.0035C167.279 22.8084 166.938 22.6261 166.518 22.4591C166.099 22.2908 165.589 22.105 164.992 21.9006C164.283 21.6762 163.587 21.4297 162.906 21.1598C162.224 20.8899 161.617 20.53 161.085 20.0836C160.554 19.6361 160.124 19.073 159.798 18.3929C159.47 17.7129 159.308 16.8518 159.308 15.8084C159.308 14.765 159.48 13.8197 159.825 12.9714C160.171 12.1243 160.655 11.3975 161.282 10.7911C161.906 10.187 162.673 9.71617 163.578 9.38083C164.484 9.0455 165.497 8.87724 166.616 8.87724C167.662 8.87724 168.754 9.02213 169.892 9.31073C171.03 9.59933 172.124 10.0235 173.169 10.582L170.985 14.8573C170.387 14.3735 169.79 14.0148 169.192 13.7823C168.595 13.5486 168.016 13.4329 167.457 13.4329C166.746 13.4329 166.168 13.6 165.719 13.9354C165.271 14.2719 165.048 14.7089 165.048 15.2487C165.048 15.6214 165.161 15.9287 165.383 16.1706C165.609 16.4136 165.903 16.6228 166.266 16.8004C166.631 16.9768 167.04 17.131 167.498 17.2607Z" fill="white"/><path fill-rule="evenodd" clip-rule="evenodd" d="M188.403 21.9C189.915 21.546 191.058 20.8707 191.833 19.874C192.608 18.8773 192.995 17.578 192.995 15.9749C192.995 15.0811 192.849 14.2433 192.561 13.4605C192.271 12.6776 191.841 11.9894 191.272 11.3924C190.703 10.7965 189.98 10.3268 189.103 9.98206C188.226 9.63738 187.198 9.46445 186.022 9.46445H177.481V30.5347H182.969V22.4305L188.206 30.5347H195.04L188.403 21.9ZM186.498 18.2113C185.919 18.6588 185.089 18.882 184.006 18.882H182.969V13.6836H184.006C185.089 13.6836 185.919 13.908 186.498 14.3543C187.076 14.8018 187.366 15.4445 187.366 16.2834C187.366 17.1212 187.076 17.7638 186.498 18.2113Z" fill="white"/><path d="M207.546 3.766C207.546 1.68 205.852 0 203.766 0C201.68 0 200 1.68 200 3.766C200 5.852 201.68 7.518 203.766 7.518C205.852 7.518 207.546 5.852 207.546 3.766ZM206.972 3.766C206.972 5.53 205.53 6.944 203.766 6.944C202.002 6.944 200.588 5.53 200.588 3.766C200.588 2.002 202.002 0.559999 203.766 0.559999C205.53 0.559999 206.972 2.002 206.972 3.766ZM205.53 5.908C205.53 5.866 205.516 5.81 205.502 5.782L204.424 4.032C205.012 3.864 205.362 3.486 205.362 2.772V2.716C205.362 1.652 204.69 1.302 203.528 1.302C203.22 1.302 202.674 1.316 202.464 1.344C202.296 1.358 202.212 1.47 202.212 1.652V5.88C202.212 5.978 202.282 6.09 202.394 6.09H202.744C202.856 6.09 202.94 5.978 202.94 5.88V4.144H203.5L203.668 4.186L204.802 5.978C204.83 6.034 204.9 6.09 204.97 6.09H205.362C205.488 6.09 205.53 6.006 205.53 5.908ZM204.662 2.772C204.662 3.332 204.354 3.542 203.57 3.542C203.458 3.542 203.08 3.528 202.926 3.528V1.96C202.968 1.96 203.038 1.96 203.122 1.96C203.276 1.96 203.458 1.96 203.57 1.96C204.34 1.96 204.662 2.156 204.662 2.716V2.772Z" fill="white"/></svg>`
let leaveSvg=`<svg width="28px" height="28px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <title>Session-Leave</title> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Session-Leave"> <rect id="Rectangle" fill-rule="nonzero" x="0" y="0" width="24" height="24"> </rect> <line x1="9" y1="12" x2="19" y2="12" id="Path" stroke="#ffffff" stroke-width="2" stroke-linecap="round"> </line> <path d="M16,8 L18.5858,10.5858 C19.3668,11.3668 19.3668,12.6332 18.5858,13.4142 L16,16" id="Path" stroke="#ffffff" stroke-width="2" stroke-linecap="round"> </path> <path d="M16,4 L6,4 C4.89543,4 4,4.89543 4,6 L4,18 C4,19.1046 4.89543,20 6,20 L16,20" id="Path" stroke="#ffffff" stroke-width="2" stroke-linecap="round"> </path> </g> </g> </g></svg>`
let filterSvg=`<svg fill="#666666" height="40px" width="40px" version="1.1" id="Filled_Icons" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g id="Filter-Filled"> <path d="M23,2v0.5l-8,10v8l-5,2v-10l-8-10V2H23z"></path> </g> </g></svg>`
const pinUrl = svgToUrl(pinSvg)
const earthUrl=svgToUrl(earthSvg)
const logoUrl=svgToUrl(logoSvg)
const leaveUrl=svgToUrl(leaveSvg)
const filterUrl=svgToUrl(filterSvg)
const stopUrl="url('https://www.svgrepo.com/show/463232/stop.svg')"
const playUrl="url('https://www.svgrepo.com/show/522228/play.svg')";
const fastUrl="url('https://www.svgrepo.com/show/501562/fast-forward.svg')";
const monthNameList = [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
];
var u = `https://www.geoguessr.com/api/v4/feed/${IS_FRIENDS_ACTIVITIES_INCLUDED =='YES' ? 'friends' : 'private'}?count=26`;
var map,heatmapLayer
let myNick=JSON.parse(localStorage.getItem('myNick'));
let activities={'duels':{},'games':{}};
let friendsData=JSON.parse(localStorage.getItem('friendsData'));
if (!friendsData){
friendsData={}
getFriends()
}
function svgToUrl(svgText) {
const svgBlob = new Blob([svgText], {type: 'image/svg+xml'});
const svgUrl = URL.createObjectURL(svgBlob);
return svgUrl;
}
async function processFriendsData() {
try {
const rankDataArray = await Promise.all(
Object.keys(friendsData).map(id => getRank(id).catch(error => null))
);
rankDataArray.forEach((rankData, index) => {
if (rankData) {
const id = Object.keys(friendsData)[index];
friendsData[id].rate = rankData.rate;
friendsData[id].division = rankData.division;
}
});
localStorage.setItem('friendsData', JSON.stringify(friendsData));
} catch (error) {
console.error("Error processing friends data:", error);
}
}
function getMyProfile() {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: "https://geoguessr.com/api/v3/profiles",
onload: function(response) {
if (response.status === 200) {
const data = JSON.parse(response.responseText);
const myId=data.user.id
friendsData[myId]={nick:data.user.nick,
flag:data.user.countryCode,
rate:data.user.competitive.rating,
division:null,
avatar:data.user.pin.url,
tierId:data.user.progress.title.tierId,
fullBody:data.user.avatar.fullBodyPath,
xp:(data.user.progress.xp-data.user.progress.levelXp),
nextLevelXp:data.user.progress.nextLevelXp,
level:data.user.progress.level,
levelXp:data.user.progress.levelXp}
localStorage.setItem('friendsData',JSON.stringify(friendsData))
localStorage.setItem('myNick',JSON.stringify(data.user.nick))
processFriendsData()
} else {
console.error("Error fetching user data: " + response.statusText);
reject(null);
}
},
onerror: function(error) {
console.error("Error fetching user data:", error);
reject(null);
}
});
});
}
function matchPlayerNick(gameData) {
gameData.forEach(game => {
const playerId = game.playerId;
if (friendsData[playerId]){game.playerNick = friendsData[playerId].nick}
});
return gameData;
}
function getFriends() {
let page = 0;
function fetchPageData() {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: `https://www.geoguessr.com/api/v3/social/friends/summary?page=${page}&fast=true`,
onload: function(response) {
if (response.status === 200) {
try {
const data = JSON.parse(response.responseText);
if (data.friends.length === 0) {
console.log("No more friends data available.");
resolve();
return;
}
data.friends.forEach(friend => {
friendsData[friend.userId] = {
nick: friend.nick,
flag: friend.countryCode,
rate: null,
division: null,
avatar: friend.pin.url,
tierId: friend.progress.title.tierId,
fullBody: friend.avatar.fullBodyPath,
xp: (friend.progress.xp - friend.progress.levelXp),
nextLevelXp: friend.progress.nextLevelXp,
level: friend.progress.level,
levelXp: friend.progress.levelXp
};
});
console.log(`Page ${page} data fetched. Total friends: ${Object.keys(friendsData).length}`);
page++;
resolve(fetchPageData());
} catch (error) {
console.error("Error parsing JSON: ", error);
reject(error);
}
} else {
console.error("Error fetching user data: " + response.statusText);
reject(new Error(`Request failed with status: ${response.statusText}`));
}
},
onerror: function(error) {
console.error("Error fetching user data:", error);
reject(error);
}
});
});
}
return fetchPageData()
.then(() => {
getMyProfile()
localStorage.setItem('friendsData', JSON.stringify(friendsData));
console.log("All friends data fetched and saved.");
})
.catch(error => {
console.error("Error during the fetch process: ", error);
return null;
});
}
function getUserPage(id) {
return new Promise(function(resolve, reject) {
GM_xmlhttpRequest({
method: "GET",
url: `https://www.geoguessr.com/user/${id}`,
onload: function(response) {
if (response.status == 200) {
var htmlContent = response.responseText;
var parser = new DOMParser();
var doc = parser.parseFromString(htmlContent, 'text/html');
var scriptTag = doc.getElementById('__NEXT_DATA__');
if (scriptTag) {
var jsonContent = scriptTag.textContent;
try {
var jsonData = JSON.parse(jsonContent);
resolve(jsonData);
} catch (error) {
console.error("Error parsing JSON:", error);
reject(error);
}
} else {
console.error("dara not found");
reject(new Error("Script tag with id '__NEXT_DATA__' not found"));
}
} else {
console.error("Request failed with status:", response.status);
reject(new Error("Request failed with status:" + response.status));
}
}
});
});
}
function getRank(id) {
return new Promise(function(resolve, reject) {
GM_xmlhttpRequest({
method: "GET",
url: `https://www.geoguessr.com/api/v4/ranked-system/progress/${id}`,
onload: function(response) {
if (response.status == 200) {
try {
const data = JSON.parse(response.responseText);
const division = data.divisionName;
const rate = data.rating;
resolve({ rate, division });
} catch (error) {
console.error("Error parsing JSON:", error);
reject(error);
}
} else {
console.error("Request failed with status:", response.status);
resolve({ rate: 'unknown', division: "unknown" });
}
},
onerror: function(error) {
console.error("Request failed:", error);
resolve({ rate: 'unknown', division: "unknown" });
}
});
});
}
function getDivisionImg(division) {
const baseUrl = "https://www.geoguessr.com/_next/image?url=%2F_next%2Fstatic%2Fmedia%2F";
const imagePaths = {
"Champion": "1.591857a5.webp",
"Gold I": "4.9f6be174.webp",
"Gold II": "5.2587b5e2.webp",
"Gold III":"6.783bcca3.webp",
"Master I": "2.8e03312b.webp",
"Master II": "3.413a29f9.webp",
"Silver I":"7.5fef2ee5.webp"
};
if (division in imagePaths) {
return `${baseUrl}${imagePaths[division]}&w=1920&q=75`;
} else {
return null;
}
}
function getPlayerKey(players,playerNick) {
return Object.keys(players).find(key => players[key].nick === playerNick) || null;
}
function updateFlag(countryCode) {
return countryCode === "tw" || countryCode === "mo" || countryCode === "hk" ? "cn" : countryCode;
}
function getWeight(country){
const distrbution={'al': 0.37, 'as': 0.05, 'ad': 0.12, 'aq': 0.004, 'ar': 2.76, 'au': 2.93, 'at': 0.85, 'bd': 0.83, 'by': 0.01,
'be': 0.6, 'bm': 0.05, 'bt': 0.37, 'bo': 1.01, 'bw': 0.52, 'br': 3.42, 'bg': 0.83, 'kh': 1.11, 'ca': 3.22,
'cl': 1.71, 'cn': 0.004, 'cx': 0.02, 'cc': 0.02, 'co': 1.75, 'cr': 0.01, 'hr': 0.69, 'cw': 0.12,
'cz': 0.83, 'dk': 0.83, 'do': 0.18, 'ec': 1.11, 'eg': 0.005, 'ee': 0.55, 'sz': 0.32, 'fo': 0.16,
'fi': 1.11, 'fr': 2.03, 'de': 1.62, 'gh': 1.12, 'gi': 0.03, 'sy': 0.01, 'gr': 1.19, 'gl': 0.14,
'gu': 0.05, 'gt': 0.83, 'gy': 0.001, 'hk': 0.21, 'hu': 0.83, 'is': 0.55, 'in': 1.65, 'id': 2.79, 'ie': 0.83,
'im': 0.09, 'il': 0.51, 'it': 1.66, 'jp': 2.42, 'je': 0.05, 'jo': 0.56, 'kz': 0.69, 'ke': 1.52, 'kg': 0.55,
'la': 0.14, 'lv': 0.55, 'lb': 0.01, 'ls': 0.23, 'li': 0.001, 'lt': 0.55, 'lu': 0.21, 'mo': 0.06, 'mg': 0.01,
'my': 1.75, 'ml': 0.003, 'mt': 0.21, 'mq': 0.002, 'mx': 2.67, 'mc': 0.04, 'mn': 0.23, 'me': 0.3, 'np': 0.01,
'nl': 0.74, 'nz': 1.2, 'ng': 0.87, 'mk': 0.23, 'mp': 0.05, 'no': 1.47, 'pk': 0.01, 'pa': 0.51, 'py': 0.002,
'pe': 1.57, 'ph': 1.91, 'pn': 0.01, 'pl': 1.38, 'pt': 0.74, 'pr': 0.14, 'qa': 0.32, 're': 0.12, 'ro': 1.3,
'ru': 3.97, 'rw': 0.2, 'sm': 0.12, 'st': 0.01, 'sn': 0.89, 'rs': 0.55, 'sg': 0.16, 'sk': 0.55, 'si': 0.41, 'za': 2.52,
'gs': 0.003, 'kr': 0.97, 'es': 2.03, 'lk': 0.83, 'se': 1.66, 'ch': 0.64, 'tw': 0.83, 'tz': 0.002, 'th': 2.12,
'gm': 0.001, 'tn': 0.46, 'tr': 1.81, 'ug': 0.18, 'ua': 1.2, 'ae': 0.55, 'gb': 1.57, 'um': 0.01, 'us': 4.64,
'vi': 0.14, 'uy': 0.83, 'vu': 0.001, 'ps': 0.22}
if(country){
const weight=distrbution[country]
if (weight){
return weight }
else{
return 0.002}
}
else{
return 0.002}
}
function generateHTML(label, stats) {
let innerHTML
innerHTML = label ? `<h1 style="text-align:center;font-size:20px;font-weight:bold;margin-left:75px;margin-top:5px;margin-bottom:5px">${label}</h1>` : '';
for (var key in stats) {
if (stats.hasOwnProperty(key)) {
var flag = '';
const shortenKey=key.replace(' country','')
if (key.includes('country')) {
stats[key] = stats[key] ? stats[key] : 'NaN';
flag = `https://flagicons.lipis.dev/flags/4x3/${stats[key]}.svg`;
}
innerHTML += `
<div class="stat-panel">
<div class="statistics">
<div class="stat-value">${stats[key]}${key.includes('country') ? `<img src="${flag}" style="position:relative;bottom:2px;left:6px;width:20px;height:15px;">` : ''}</div>
<div class="stat-label">${shortenKey.toUpperCase()}</div>
</div>
</div>`;
}
}
return innerHTML;
}
function markOptions(k,f){
const uniqueUsingMaps = new Set();
f.forEach(item => {
if (item.hasOwnProperty(`${k}`)) {
uniqueUsingMaps.add(item[k]);
}
});
const select = document.querySelector(`select[name="${k}"]`);
select.querySelectorAll('option').forEach(option => {
if (uniqueUsingMaps.has(option.textContent)) {
option.style.color = 'red';
}
else{
option.style.color = '#000000';
}
});
}
function downloadJSON(coords) {
var originalJson = JSON.stringify(coords, null, 2);
var originalBlob = new Blob([originalJson], { type: 'application/json' });
var originalUrl = URL.createObjectURL(originalBlob);
var originalLink = document.createElement('a');
originalLink.href = originalUrl;
originalLink.download = 'original_data.json';
document.body.appendChild(originalLink);
originalLink.click();
document.body.removeChild(originalLink);
}
function clearLocalStorage() {
localStorage.removeItem('friendsData');
localStorage.removeItem('friendsData');
Swal.fire('Success', 'Activity data has been cleared, please refresh the page and retrieve data again!', 'success');
}
function loadGoogleMapsAPI() {
const newScript = document.createElement('script');
newScript.src = "https://maps.googleapis.com/maps/api/js?libraries=visualization&key=AIzaSyAiRLvmrxcqZRhsiPMzK5Ps2b5Ov6XhJrY";
document.head.appendChild(newScript);
}
function createHeatmap(coordinates) {
let heatmapData=[]
let filteredData
function createMap() {
var css = `
.control-panel {
position:absolute;
margin-top:160px;
margin-left:8px;
height: 30px;
cursor: pointer;
text-align: center;
line-height: 30px;
}
.control-panel .select-container {
display: none;
}
.control-panel:hover .select-container {
width:125px;
display: block;
}
.control-panel select {
position:atuo;
top:40px;
width: 100%;
padding: 5px;
border: 1px solid #ccc;
background-color: #fff;
cursor: pointer;
outline: none;
}
#player-panel {
position:absolute;
margin-top:125px;
width:108px;
height:108px;
background-color:none;
border:none;
border-radius:50%;
background-size: 135px,96px;
background-position: center, center;
opacity:1;
z-index:999;
}
#player-panel:hover {
cursor: pointer;
}
#player-panel::after {
position: absolute;
bottom:100%;
transform: translateX(-50%);
background-color: rgba(0, 0, 0, 0.8);
color: #fff;
padding: 5px;
border-radius: 5px;
font-size: 11px;
line-height: 1;
height: auto;
white-space: nowrap;
opacity: 0;
transition: opacity 0.3s ease;
}
#player-panel:hover::after {
content: attr(data-content);
opacity: 1;
}
#stats-panel {
position: absolute;
left:460px;
margin-top:60px;
width:555px;
height:640px;
transform: translateX(-50%);
background-color: rgba(0, 0, 0, 0.8);
padding:5px;
border-radius: 5px;
font-size: 11px;
line-height: auto;
white-space: nowrap;
opacity: 0.9;
transition: opacity 0.3s ease;
}
.stat-panel {
display:inline-block;
text-align: center;
width: 150px;
height:50px;
margin-top: 1px;
margin-left: 15px;
margin-right: 15px;
margin-bottom:10px;
}
.statistics {
display: flex;
height:100%;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #484747;
padding: 0px;
border-radius: 10px;
}
.stat-value {
color:white;
left:auto;
height:auto;
text-align:center;
font-size: 18px;
font-weight: bold;
margin-bottom:0px;
margin-top:0px
}
.stat-label {
text-align:center;
font-size: 10.5px;
font-weight: bold;
color:#A19BD9;
margin-top:0px;
}
.custom-button {
position:absolute;
background: none;
border: 0px;
text-transform: none;
cursor: pointer;
user-select: none;
border-radius: 2px;
height: 40px;
width: 40px;
box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 4px -1px;
overflow: hidden;
color: #d3cfcf;
font-size: 30px;
line-height: 40px;
text-align: center;
background-color: rgb(34, 34, 34);
}
.progress-bar {
margin-left:10px;
display: flex;
align-items: center;
width: 160px;
height: 20px;
position: absolute;
left:60px;
top:5px
}
.progress-bar .background {
flex: 1;
height: 100%;
background-color: #888;
border-radius: 5px;
}
.progress-bar .experience {
position:absolute;
height: 100%;
background-color: #FFD700;
color: white;
text-align: center;
line-height: 20px;
border-radius: 5px;
}
.progress-bar span {
font-size:14px;
font-weight:bold;
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
color: white;
line-height: 20px;
}
`;
var style = document.createElement('style');
style.textContent = css;
document.head.appendChild(style);
let previousListener,previousLeaveListener,previousBarListener,previousPlayListener
const playerDiv=document.createElement('div')
playerDiv.id='player-panel'
previousListener=function(){window.open("https://www.geoguessr.com", "_blank")}
playerDiv.style.backgroundImage = ` url(${logoUrl}),url(${earthUrl})`;
playerDiv.style.display='block'
playerDiv.setAttribute('data-content', "https://www.geoguessr.com")
playerDiv.addEventListener('click',previousListener)
const statsDiv=document.createElement('div')
statsDiv.id='stats-panel'
statsDiv.style.display='none'
const statsCloseButton=document.createElement('button')
statsCloseButton.id='stats-close-button'
statsCloseButton.className = 'custom-button'
statsCloseButton.textContent='×'
statsCloseButton.style.fontSize='42px'
statsCloseButton.style.color='white';
statsCloseButton.style.backgroundColor='transparent';
statsCloseButton.style.boxShadow='none'
statsCloseButton.style.top = '1px';
statsCloseButton.style.right = '1px';
statsCloseButton.style.opacity='0.9'
statsDiv.appendChild(statsCloseButton)
const leaveButton=document.createElement('button')
leaveButton.id='stats-leave-button'
leaveButton.className = 'custom-button'
leaveButton.style.backgroundColor='transparent';
leaveButton.style.boxShadow='none'
leaveButton.style.top = '1px';
leaveButton.style.right = '40px';
leaveButton.style.opacity='0.9';
leaveButton.style.backgroundImage=`url(${leaveUrl})`
leaveButton.style.backgroundRepeat = 'no-repeat';
leaveButton.style.backgroundPosition='center'
statsDiv.appendChild(leaveButton)
const profileContainer=document.createElement('div')
profileContainer.style.position = "absolute";
profileContainer.style.top = "5px";
profileContainer.style.left = "center";
profileContainer.style.fontSize="20px"
statsDiv.appendChild(profileContainer)
const panelContainer = document.createElement('div');
panelContainer.style.position = "relative";
panelContainer.style.top = "130px";
statsDiv.appendChild(panelContainer)
const fullBodyImg = document.createElement('img');
fullBodyImg.style.position = 'fixed';
fullBodyImg.style.top = '5px';
fullBodyImg.style.left = '20px';
statsDiv.appendChild(fullBodyImg);
const barContainer = document.createElement('div');
barContainer.style.position='absolute'
barContainer.style.display='flex'
barContainer.style.marginBottom='20px'
barContainer.style.width='250px'
barContainer.style.height='30px'
barContainer.style.borderRadius='2px'
barContainer.style.backgroundColor='#FFFFFF'
const timeRangeLabel = document.createElement('label');
timeRangeLabel.id='time-range-label'
timeRangeLabel.style.display = 'flex';
timeRangeLabel.style.fontSize = '12px';
timeRangeLabel.style.color = '#000';
timeRangeLabel.style.position = 'absolute';
timeRangeLabel.style.left = '5px';
timeRangeLabel.style.top = '2px';
timeRangeLabel.style.fontWeight='bold'
timeRangeLabel.style.width='70px'
timeRangeLabel.style.whiteSpace = 'pre-wrap'
timeRangeLabel.style.lineHeight = '1.2';
const timeRangeInput = document.createElement('input');
timeRangeInput.setAttribute('type', 'range');
timeRangeInput.setAttribute('id', 'timeRange');
timeRangeInput.setAttribute('min', '0');
timeRangeInput.setAttribute('max', '100');
timeRangeInput.setAttribute('value', '0');
timeRangeInput.style.position = 'absolute';
timeRangeInput.style.left = '30%';
timeRangeInput.style.top = '28%';
timeRangeInput.style.width='120px'
const minTimestamp = coordinates.reduce((min, item) => {
const targetTimestamp = item.gameDate;
return targetTimestamp < min ? targetTimestamp : min;
}, Infinity);
const maxTimestamp = coordinates.reduce((max, item) => {
const targetTimestamp = item.gameDate;
return targetTimestamp > max ? targetTimestamp : max;
}, 0);
timeRangeInput.setAttribute('min', minTimestamp);
timeRangeInput.setAttribute('max', maxTimestamp);
timeRangeInput.setAttribute('value', maxTimestamp)
timeRangeLabel.textContent = new Date(maxTimestamp).toISOString().slice(0, 19).replace('T', ' ');
const playButton = document.createElement('button');
playButton.id='play-button'
playButton.style.position = 'absolute';
playButton.style.right = '12%';
playButton.style.top = '20%';
playButton.style.backgroundImage = playUrl
playButton.style.backgroundSize='cover'
playButton.style.width='18px'
playButton.style.height='18px'
playButton.style.backgroundColor='transparent'
playButton.style.border='none'
playButton.style.cursor = 'pointer';
const fastButton = document.createElement('button');
fastButton.id='fast-button'
fastButton.style.position = 'absolute';
fastButton.style.right = '2%';
fastButton.style.top = '20%';
fastButton.style.backgroundImage = fastUrl
fastButton.style.backgroundSize='cover'
fastButton.style.width='18px'
fastButton.style.height='18px'
fastButton.style.backgroundColor='transparent'
fastButton.style.border='none'
fastButton.style.cursor = 'pointer';
barContainer.appendChild(timeRangeLabel);
barContainer.appendChild(timeRangeInput);
barContainer.appendChild(playButton);
barContainer.appendChild(fastButton);
let interval,isPlaying = false
let playStep=60000
previousPlayListener=function() {
isPlaying = !isPlaying;
if (isPlaying) {
playButton.style.backgroundImage = stopUrl
interval = setInterval(function() {
if (parseInt(timeRangeInput.value) < parseInt(timeRangeInput.max)) {
timeRangeInput.value = parseInt(timeRangeInput.value) + playStep;
barListener(timeRangeInput.value, coordinates);
timeRangeLabel.textContent = new Date(parseInt(timeRangeInput.value)).toISOString().slice(0, 19).replace('T', ' ');
} else {
clearInterval(interval);
playButton.style.backgroundImage =playUrl
isPlaying = false;
}
}, 500);
} else {
playButton.style.backgroundImage = playUrl
clearInterval(interval);
}
}
previousBarListener=function(){
barListener(timeRangeInput.value,coordinates);
timeRangeLabel.textContent = new Date(parseInt(timeRangeInput.value)).toISOString().slice(0, 19).replace('T', ' ');}
timeRangeInput.addEventListener('input',previousBarListener)
playButton.addEventListener('click', previousPlayListener);
fastButton.addEventListener('click',function(){
playStep=playStep*6
if (playStep>=86400000){
playStep=60000
}
})
map=unsafeWindow.map
function getMap(){
let element = document.getElementsByClassName("map-embed")[0]
try{
const keys = Object.keys(element)
const key = keys.find(key => key.startsWith("__reactFiber$"))
const props = element[key]
map=props.pendingProps.children[1].props.children[1].props.map
}
catch(error){
console.error('Failed to get map')
}
}
if(!map) getMap()
let google= unsafeWindow.google
const controlDiv = document.createElement('div');
controlDiv.className = 'control-panel';
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(playerDiv)
map.controls[google.maps.ControlPosition.TOP_LEFT].push(controlDiv)
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(statsDiv)
map.controls[google.maps.ControlPosition.BOTTOM_CENTER].push(barContainer)
const filterIcon = document.createElement('div');
filterIcon.style.display='block'
filterIcon.style.width='40px'
filterIcon.style.height='40px'
filterIcon.style.boxShadow='rgba(0, 0, 0, 0.3) 0px 1px 4px -1px'
filterIcon.style.borderRadius='2px'
filterIcon.style.backgroundColor='#fff'
filterIcon.style.backgroundImage = `url(${filterUrl})`
filterIcon.style.backgroundSize = '20px'
filterIcon.style.backgroundPosition='center'
controlDiv.classList.add('hoverable')
controlDiv.addEventListener('mouseenter', () => {
selectContainer.style.display = 'block';
controlDiv.style.height = '380px';
filterIcon.style.backgroundColor='#ebebeb'
});
controlDiv.addEventListener('mouseleave', () => {
selectContainer.style.display = 'none';
controlDiv.style.height = '30px';
filterIcon.style.backgroundColor='#fff'
});
filterIcon.onclick =async () =>{
var mmd
if(heatmapData.length>0)mmd=await processMapMakingData(heatmapData)
else{
for (const coord of coordinates) {
heatmapData.push({
location: new google.maps.LatLng(coord.latLng.lat, coord.latLng.lng),
weight: coord.score,
player:coord.playerNick,
forbidOptions:coord.forbidOptions,
heading:coord.heading,
pitch:coord.pitch,
zoom:coord.zoom,
usingMap:coord.usingMap,
gameMode:coord.gameMode
});
}
mmd=await processMapMakingData(heatmapData)}
const editor=unsafeWindow.editor
editor.importFromString(JSON.stringify(mmd))
GM_setClipboard(JSON.stringify(mmd))
}
controlDiv.appendChild(filterIcon)
const keysToFilter = ['playerNick', 'gameMode', 'forbidOptions', 'usingMap', 'country', 'score', 'distance', 'guessSeconds'];
const optionValues = {};
let filters = [];
let players=[];
const selectContainer = document.createElement('div');
selectContainer.className = 'select-container';
controlDiv.appendChild(selectContainer);
selectContainer.style.backgroundColor= '#fff';
keysToFilter.forEach(key => {
const select = document.createElement('select');
select.setAttribute('name', key);
select.style.marginBottom = '15px';
const defaultOption = document.createElement('option');
defaultOption.setAttribute('value', 'default');
defaultOption.textContent = `${key}`;
select.appendChild(defaultOption);
if (key === 'score' || key === 'distance' || key === 'guessSeconds') {
const ranges = key === 'score' ? [
{ min: 0, max: 1499 },
{ min: 1500, max: 2999 },
{ min: 3000, max: 3999 },
{ min: 4000, max: 4499 },
{ min: 4500, max: 4999 },
{ min: 5000 }
] : key === 'distance' ? [
{ max: 0.5 },
{ min: 0.5, max: 5 },
{ min: 5, max: 100 },
{ min: 100, max: 1000 },
{ min: 1000, max: 5000 },
{ min: 5000 }
] : [
{ max: 5 },
{ min: 5, max: 15 },
{ min: 15, max: 30 },
{ min: 30, max: 60 },
{ min: 60, max: 300 },
{ min: 300 }
];
for (let range of ranges) {
const option = document.createElement('option');
let label = range.max === undefined ? (key === 'score' ? '5000' : key === 'distance' ? '>5000km' : '>300s') : (key === 'score' ? `${range.min}-${range.max}` : key === 'distance' ? `${range.min}-${range.max}km` : `${range.min}-${range.max}s`);
if (range.min==undefined&&key==='distance'){
label='<0.5km';
}
if (range.min==undefined&&key==='guessSeconds'){
label='<5s';
}
option.setAttribute('value', label);
option.textContent = label;
select.appendChild(option);
}
}
else {
const optionCounts = {};
coordinates.forEach(item => {
const value = item[key];
optionCounts[value] = (optionCounts[value] || 0) + 1;
});
const sortedOptions = Object.keys(optionCounts).sort((a, b) => optionCounts[b] - optionCounts[a]);
sortedOptions.forEach(value => {
if (!optionValues[value]) {
optionValues[value] = true;
const option = document.createElement('option');
option.setAttribute('value', value);
if (key === 'playerNick') {
option.textContent = value;
if (value == myNick) {
option.textContent = `${value}(me)`;
option.style.color = 'red';
}
} else {
option.textContent = value;
}
select.appendChild(option);
}
});
}
selectContainer.appendChild(select);
select.addEventListener('change', () => {
const selectedValue = select.value;
filters[key] = selectedValue;
let filteredData = coordinates
Object.keys(filters).forEach(filterKey => {
const filterValue = filters[filterKey];
if (filterValue) {
if (filterValue.includes('-')&&filterKey!='playerNick') {
filteredData = filteredData.filter(item => {
const [minValue, maxValue] = filterValue.split('-').map(val => parseFloat(val));
const itemValue = parseFloat(item[filterKey]);
return itemValue >= minValue && itemValue <= maxValue;
});
}
else if (filterValue.includes('>') || filterValue.includes('<')) {
const operator = filterValue.includes('>') ? '>' : '<';
const value = parseFloat(filterValue.substring(1));
filteredData = filteredData.filter(item => {
const itemValue = parseFloat(item[filterKey]);
return operator === '>' ? itemValue > value : itemValue < value;
});
}
else if (filterValue.includes('5000')) {
filteredData = filteredData.filter(item => {
const itemValue = parseFloat(item[filterKey]);
return itemValue === 5000;
});}
else if (filterValue==='default'){
}
else {
filteredData = filteredData.filter(item => item[filterKey] === filterValue);
}
if (filterKey=='playerNick'){
if (previousListener) {
playerDiv.removeEventListener('click', previousListener);
}
if(previousLeaveListener){
leaveButton.removeEventListener('click', previousLeaveListener)
}
if (filterValue!='default'){
const pId=getPlayerKey(friendsData,filterValue)
if(pId){
const flag=updateFlag(friendsData[pId].flag)
const flagUrl=`https://flagicons.lipis.dev/flags/4x3/${flag}.svg`
const pinUrl=`https://www.geoguessr.com/images/resize:auto:96:96/gravity:ce/plain/${friendsData[pId].avatar}`
const divisionUrl=getDivisionImg(friendsData[pId].division)
const tierUrl=`https://www.geoguessr.com/static/avatars/tiers/high-quality-no-bling/tier-${friendsData[pId].tierId}.webp`
const fullBodyUrl=`https://www.geoguessr.com/images/resize:auto:135:135/gravity:ce/plain/${friendsData[pId].fullBody}`
playerDiv.style.backgroundImage=`url(${tierUrl}),url(${pinUrl})`;
playerDiv.style.backgroundSize= "135px,60px"
playerDiv.style.backgroundPosition= "50%,48%"
playerDiv.setAttribute('data-content',"View player's stats")
fullBodyImg.src = fullBodyUrl;
previousLeaveListener=function(){window.open(`https://www.geoguessr.com/user/${pId}`, "_blank")}
statsCloseButton.addEventListener('click', function() {
statsDiv.style.display = 'none';
});
leaveButton.addEventListener('click',previousLeaveListener)
const playerLine = `<div style="position:fixed;left:calc(50% - ${filterValue.length * 6}px);font-size:22px;font-weight:bold;text-align:center;">${filterValue} <img src="${flagUrl}" style="width:20px;height:15px;"></div>`;
const levelProgress=(friendsData[pId].xp / (friendsData[pId].nextLevelXp- friendsData[pId].levelXp) ) * 100
const progressBar = `<div class="progress-bar">
<div class="background"></div>
<div class="experience" style="width:${levelProgress}%;"></div>
<span>${friendsData[pId].xp } / ${(friendsData[pId].nextLevelXp- friendsData[pId].levelXp)}</span>
</div>`;
const levelLine = `<div style="position:fixed; top:45px; left:165px; display:flex; margin-top:5px; color:#FFD700;font-szie:18px;font-weight:bold">LV ${friendsData[pId].level}${progressBar} </div>`;
const divisionLine = `<div style="position:fixed;top:90px;left:210px;white-space:pre">${friendsData[pId].division} ${friendsData[pId].rate}</div>`;
const divisionImg=`<div style="position:fixed;top:50px;right:50px"><img src="${divisionUrl}" style="width:64px;height:72px;"></div>`
profileContainer.innerHTML = playerLine + levelLine + divisionLine+divisionImg;
previousListener=function() {
statsDiv.style.display='block'
}
playerDiv.addEventListener('click', previousListener)}
}
else{
statsDiv.style.display='none'
previousListener=function() {
window.open(`https://www.geoguessr.com`, "_blank");
}
playerDiv.style.backgroundImage = ` url(${logoUrl}),url(${earthUrl})`;
playerDiv.style.backgroundSize= "135px,96px"
playerDiv.style.backgroundPosition="center, center";
playerDiv.style.display='block'
playerDiv.setAttribute('data-content', "https://www.geoguessr.com")
playerDiv.addEventListener('click', previousListener);
}
markOptions('usingMap',filteredData)
markOptions('country',filteredData)
}
if (filterValue!='default'){displayStats(filteredData,panelContainer)}
}
});
refreshHeatmap(filteredData);
if (previousBarListener){
timeRangeInput.removeEventListener('input',previousBarListener)
previousBarListener=function(){
barListener(timeRangeInput.value,filteredData)
timeRangeLabel.textContent = new Date(parseInt(timeRangeInput.value)).toISOString().slice(0, 19).replace('T', ' ')
}
timeRangeInput.addEventListener('input',previousBarListener)
}
if (previousPlayListener){
if(isPlaying){
playButton.click()}
playButton.removeEventListener('click',previousPlayListener)
barListener(timeRangeInput.value, filteredData);
isPlaying = false;
previousPlayListener=function() {
isPlaying = !isPlaying;
if (isPlaying) {
playButton.style.backgroundImage = stopUrl
interval = setInterval(function() {
if (parseInt(timeRangeInput.value) < parseInt(timeRangeInput.max)) {
timeRangeInput.value = parseInt(timeRangeInput.value) + playStep;
barListener(timeRangeInput.value, filteredData);
timeRangeLabel.textContent = new Date(parseInt(timeRangeInput.value)).toISOString().slice(0, 19).replace('T', ' ');
} else {
clearInterval(interval);
playButton.style.backgroundImage =playUrl
isPlaying = false;
}
}, 500);
} else {
playButton.style.backgroundImage = playUrl
clearInterval(interval);
}
}
playButton.addEventListener('click',previousPlayListener)
}
});
});
}
function refreshHeatmap(fd) {
if (fd.length === 0) {
console.error('No valid coordinates data found');
}
heatmapData=[]
for (const coord of fd) {
heatmapData.push({
location: new google.maps.LatLng(coord.latLng.lat, coord.latLng.lng),
weight: coord.score,
player:coord.playerNick,
forbidOptions:coord.forbidOptions,
heading:coord.heading,
pitch:coord.pitch,
zoom:coord.zoom,
usingMap:coord.usingMap,
gameMode:coord.gameMode
});
}
heatmapLayer.setData(heatmapData);
}
function barListener(selectedTimestamp, data) {
const timeFilteredData = data.filter(item => {
return item.gameDate <= selectedTimestamp;
})
refreshHeatmap(timeFilteredData);
}
if(!map){
createMap();
getDefault(coordinates)
}
}
async function getDefault(coordinates){
var h=[];
if (heatmapLayer) {
heatmapLayer.setMap(null);
}
for (const coord of coordinates) {
h.push({
location: new google.maps.LatLng(coord.latLng.lat, coord.latLng.lng),
weight: coord.score,
heading:coord.heading,
pitch:coord.pitch,
zoom:coord.zoom
});
}
heatmapLayer = new google.maps.visualization.HeatmapLayer({
data: h,
dissipating: true,
map: map,
});}
function displayStats(data,container){
function createOrGetElementById(id, parent) {
let element = document.getElementById(id);
if (!element) {
element = document.createElement('div');
element.id = id;
element.classList.add('stat-item');
parent.appendChild(element);
}
return element;
}
const playerStats=getPlayerStats(data)
let totalPanelDiv = createOrGetElementById('total-panel', container);
let subTotalPanel = createOrGetElementById('sub-total-panel', container);
let avgPanelDiv = createOrGetElementById('avg-panel', container);
let subAvgPanelI= createOrGetElementById('sub-avg-panel-i', container);
let subAvgPanelII=createOrGetElementById('sub-avg-panel-ii', container);
let subAvgPanelIII=createOrGetElementById('sub-avg-panel-iii', container);
let subAvgPanelIV=createOrGetElementById('sub-avg-panel-iv', container);
totalPanelDiv.innerHTML = generateHTML('Total', {'rounds played': playerStats.totalRounds, 'games played': playerStats.totalGames, 'days played': playerStats.totalDays});
subTotalPanel.innerHTML=generateHTML(null,{'duels played':playerStats.totalDuels,'win ratio': `${playerStats.winRate}%`,'5k streak': playerStats.get5k, })
avgPanelDiv.innerHTML = generateHTML('Average', {'avg. round score': playerStats.avgScore, 'avg. round distance': `${playerStats.avgDistance}km`, 'avg. round timespent': `${playerStats.avgGuessSeconds}s`});
subAvgPanelI.innerHTML = generateHTML(null, {'rounds per game':playerStats.roundsPerGame, 'rounds per day': playerStats.roundsPerDay,'games per day': playerStats.gamesPerDay});
subAvgPanelII.innerHTML =generateHTML(null,{ 'rounds per 5k': playerStats.rounsPer5k,'timespent per 5k': playerStats.timeSpent5k === 'NaN' ? 'NaN' : `${playerStats.timeSpent5k}s`,'score std':playerStats.std})
subAvgPanelIII.innerHTML =generateHTML(null,{ 'min avg. distance country': updateFlag(playerStats.minAvgDistanceCountry),'min std country':updateFlag(playerStats.minStdCountry),'min avg. timespent country':playerStats.minTimeSpentCountry})
subAvgPanelIV.innerHTML =generateHTML(null,{'max avg. distance country': updateFlag(playerStats.maxAvgDistanceCountry),'max std country':updateFlag(playerStats.maxStdCountry),'max avg. timespent country':playerStats.maxTimeSpentCountry})
}
function getActivities(url, result, maxPages,currentPage = 1, pageToken = null) {
if (currentPage==1){
const swal = Swal.fire({
title: 'Fetching Activities',
text: 'Please wait...',
allowOutsideClick: false,
allowEscapeKey: false,
showConfirmButton: false,
didOpen: () => {
Swal.showLoading();
}
});
}
if (currentPage > maxPages) {
console.log(`Reached maximum number of pages (${maxPages}). Stopping requests.`);
swal.close()
Swal.fire('Success', 'All activities retrieved successfully!', 'success');
getCoords(result);
return;
}
let nextPageUrl = url;
if (pageToken) {
nextPageUrl += `&paginationToken=${encodeURIComponent(pageToken)}`;
}
GM_xmlhttpRequest({
method: "GET",
url: nextPageUrl,
onload: function(response) {
if (response.status === 200) {
const data = JSON.parse(response.responseText);
processActivities(data, result);
const nextPageToken = data.paginationToken;
if (nextPageToken) {
getActivities(url, result, maxPages, currentPage + 1, nextPageToken);
} else {
Swal.fire('Success', 'All activities retrieved successfully!', 'success');
getCoords(result);
}
} else {
console.error('Request failed: ' + response.statusText);
Swal.fire('Error', 'Failed to fetch activities. Please try again later.', 'error');
}
},
onerror: function(response) {
console.error('Request failed: ' + response.statusText);
Swal.fire('Error', 'Failed to fetch activities. Please try again later.', 'error');
}
});
}
function processActivities(data, result) {
const entries = data.entries;
if (entries && entries.length > 0) {
entries.forEach(entry => {
if (entry.payload) {
const payloadList = JSON.parse(entry.payload);
const userId = entry.user.id;
if (!Array.isArray(payloadList)) {
processPayload(payloadList, userId, result);
} else {
payloadList.forEach(payload => {
processPayload(payload, userId, result);
});
}
}
});
} else {
console.error('Data not found!');
}
}
function getPlayerStats(data) {
let playerStats = initStats();
let stats={}
for (const game of data) {
updateStats(playerStats, game);
}
playerStats = calculateStats(playerStats)
return playerStats;
}
function initStats() {
return {
totalGames: 0,
totalRounds: 0,
totalDays: 0,
playedGames:[],
dates:[],
scores: [],
distances: [],
guessSeconds: [],
wins: 0,
duels: 0,
get5k: 0,
totalTimeSpent5k: 0,
countryStats: {}
};
}
function updateStats(stats, game) {
stats.totalRounds++
if (!stats.playedGames.includes(game.gId)){
stats.playedGames.push(game.gId)
stats.totalGames++;
if (game.gameMode === 'duels') {
stats.duels++;
if (game.isWin === 'win') {
stats.wins++;
}
}
}
stats.scores.push(game.score);
stats.distances.push(parseFloat(game.distance));
stats.guessSeconds.push(parseFloat(game.guessSeconds));
const date=new Date(game.gameDate).toISOString().slice(0,10)
if ( !stats.dates.includes(date) ){
stats.totalDays++;
stats.dates.push(date);
}
if (game.score === 5000) {
stats.get5k++;
stats.totalTimeSpent5k += parseFloat(game.guessSeconds);
}
if (game.country) {
if (!stats.countryStats[game.country]) {
stats.countryStats[game.country] = { distances: [],timeSpent:[]};
}
stats.countryStats[game.country].distances.push(parseFloat(game.distance));
stats.countryStats[game.country].timeSpent.push(parseFloat(game.guessSeconds));
}
}
function calculateStats(stats) {
const avgScore = _.round(_.mean(stats.scores));
const avgDistance = _.round(_.mean(stats.distances), 2);
const avgGuessSeconds = _.round(_.mean(stats.guessSeconds), 2);
const winRate = stats.duels === 0 ? null : _.round(stats.wins * 100 / stats.duels, 2);
const timeSpent5k = stats.get5k === 0 ? null : _.round(stats.totalTimeSpent5k / stats.get5k, 2);
const rounsPer5k = stats.get5k === 0 ? null : _.round(stats.totalRounds / stats.get5k, 2);
const std = _.round(Math.sqrt(_.sum(stats.scores.map(score => Math.pow(score - _.mean(stats.scores), 2))) / stats.totalGames));
const countryStats = calculateCountryStats(stats.countryStats,stats.totalRounds);
const maxStdCountry = _.maxBy(Object.keys(countryStats), country => countryStats[country].stdDev/(getWeight(country)));
const minStdCountry = _.minBy(Object.keys(countryStats), country => countryStats[country].stdDev/(getWeight(country)));
const maxAvgDistanceCountry = _.maxBy(Object.keys(countryStats), country => countryStats[country].avgDistance);
const minAvgDistanceCountry = _.minBy(Object.keys(countryStats), country => countryStats[country].avgDistance);
const maxTimeSpentCountry = _.maxBy(Object.keys(countryStats), country => countryStats[country].timeSpentMean);
const minTimeSpentCountry = _.minBy(Object.keys(countryStats), country => countryStats[country].timeSpentMean);
const countries = _.map(countryStats, country => country.avgDistance);
const countriesAvg = _.mean(countries);
const sD = _.map(countries, avgDistance => Math.pow(avgDistance - countriesAvg, 2));
const meanSd = _.mean(sD);
const countryStd = _.round(Math.sqrt(meanSd));
return {
totalGames: stats.totalGames,
totalRounds: stats.totalRounds,
totalDuels:stats.duels,
totalDays: stats.totalDays,
roundsPerGame: stats.totalGames==0?'NaN':_.round(stats.totalRounds / stats.totalGames, 2),
roundsPerDay: stats.totalDays==0?'NaN':_.round(stats.totalRounds / stats.totalDays, 2),
gamesPerDay:stats.totalDays==0?'NaN': _.round(stats.totalGames / stats.totalDays, 2),
avgScore,
avgDistance,
avgGuessSeconds,
winRate: winRate !== null ? winRate : 'NaN',
get5k: stats.get5k,
timeSpent5k: timeSpent5k !== null ? timeSpent5k : 'NaN',
rounsPer5k: rounsPer5k !== null ? rounsPer5k : 'NaN',
std,
countryStd,
maxStdCountry,
minStdCountry,
maxAvgDistanceCountry,
minAvgDistanceCountry,
maxTimeSpentCountry,
minTimeSpentCountry
};
}
function calculateCountryStats(countryStats,totalRounds) {
const result = {};
for (const country in countryStats) {
const weight=getWeight(country)
const distances = countryStats[country].distances;
if (weight <0.5 ||distances.length<totalRounds*0.02) continue;
const mean = _.mean(distances);
const stdDev = _.round(Math.sqrt(_.mean(distances.map(distance => Math.pow(distance - mean, 2)))), 2);
const timeSpent=countryStats[country].timeSpent
const timeSpentMean=_.mean(timeSpent)
result[country] = { avgDistance: _.round(mean, 2), stdDev,timeSpentMean};
}
return result;
}
function processPayload(payload, userId, result) {
if (payload.gameToken) {
result.games[userId] = result.games[userId] || [];
if (!result.games[userId].includes(payload.gameToken)) {
result.games[userId].push(payload.gameToken);
}
} else if (payload.gameId) {
result.duels[userId] = result.duels[userId] || [];
if (!result.duels[userId].includes(payload.gameId)) {
result.duels[userId].push(payload.gameId);
}
}
}
async function getCoords(data) {
try {
var coordinates = [];
const duelsPromises = [];
const gamesPromises = [];
const chunkSize = 20;
const swal = Swal.fire({
title: 'Fetching Coordinates',
text: 'Please wait...',
allowOutsideClick: false,
allowEscapeKey: false,
showConfirmButton: false,
didOpen: () => {
Swal.showLoading();
}
});
for (const gameIds of Object.values(data.duels)) {
for (let i = 0; i < gameIds.length; i += chunkSize) {
const chunk = gameIds.slice(i, i + chunkSize);
const chunkPromises = chunk.map(gameId => {
const requestUrl = `https://game-server.geoguessr.com/api/duels/${gameId}`;
return getGameSummary(requestUrl, 'duels', coordinates);
});
duelsPromises.push(Promise.allSettled(chunkPromises));
}
}
await Promise.allSettled(duelsPromises);
for (const gameIds of Object.values(data.games)) {
for (let i = 0; i < gameIds.length; i += chunkSize) {
const chunk = gameIds.slice(i, i + chunkSize);
const chunkPromises = chunk.map(gameId => {
const requestUrl = `https://www.geoguessr.com/api/v3/games/${gameId}?client=web`;
return getGameSummary(requestUrl, 'games', coordinates);
});
gamesPromises.push(Promise.allSettled(chunkPromises));
}
}
await Promise.allSettled(gamesPromises);
swal.close();
try {
var matchedData = matchPlayerNick(coordinates);
await downloadJSON(matchedData);
createHeatmap(matchedData);
Swal.fire('Success', 'Heatmap is prepared!', 'success');
} catch (error) {
console.error("Error:", error);
Swal.fire('Error', 'Failed to prepare heatmap', 'error');
}
} catch (error) {
Swal.fire('Error', 'Error parsing JSON from localStorage', 'error');
console.error('Error parsing JSON from localStorage:', error);
}
}
async function getGameSummary(url, mode, coordinates) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: url,
onload: function(response) {
try {let forbidOptions
const data = JSON.parse(response.responseText);
if(data.teams||data.player){
if (mode === 'duels') {
const movementOptions=data.movementOptions
if(movementOptions.forbidMoving&&movementOptions.forbidZooming&&movementOptions.forbidRotating){forbidOptions='NMPZ'}
else if (!movementOptions.forbidMoving&&!movementOptions.forbidZooming&&!movementOptions.forbidRotating){forbidOptions='Moving'}
else if(movementOptions.forbidMoving&&!movementOptions.forbidZooming&&!movementOptions.forbidRotating){forbidOptions='NM'}
else{forbidOptions='Entertainment'}
const usingMap=data.options.map.name
const gId=data.gameId
var isWin
if(data.result.winnerStyle==='Victory'){isWin='win'}
else{isWin='Lose'}
data.teams.forEach(team => {
team.players.forEach(player => {
const playerId = player.playerId;
if (friendsData[playerId]){
player.guesses.forEach(guess => {
const roundNumber = guess.roundNumber;
const roundData = data.rounds.find(round => round.roundNumber === roundNumber);
if (roundData) {
const gameDate = new Date(guess.created).getTime()
const gameMode = 'duels';
const latLng = { 'lat': roundData.panorama.lat, 'lng': roundData.panorama.lng };
const country =roundData.panorama.countryCode
const heading=roundData.panorama.heading
const pitch=roundData.panorama.pitch
const zoom=roundData.panorama.zoom
const score = team.roundResults.find(result => result.roundNumber === roundNumber).score;
const distance = (guess.distance / 1000).toFixed(2);
const guessSeconds = (Math.abs(new Date(guess.created) - new Date(roundData.startTime)) / 1000).toFixed(2);
coordinates.push({gId,gameMode, playerId,isWin, latLng, country, score, distance, guessSeconds, forbidOptions, usingMap,gameDate,heading,pitch,zoom});
}
});}
});
});
}
else {
if(data.forbidMoving&&data.forbidZooming&&data.forbidRotating){forbidOptions='NMPZ'}
else if (!data.forbidMoving&&!data.forbidZooming&&!data.forbidRotating){forbidOptions='Moving'}
else if(data.forbidMoving&&!data.forbidZooming&&!data.forbidRotating){forbidOptions='NM'}
else{forbidOptions='Entertainment'}
const gId=data.token
const gameMode = 'classic';
const player = data.player;
const playerId=player.id
const usingMap=data.mapName
player.guesses.forEach((guess, index) => {
const roundData = data.rounds[index];
const gameDate = new Date(roundData.startTime).getTime()
const heading=roundData.heading
const pitch=roundData.pitch
const zoom=roundData.zoom
const latLng = { 'lat': roundData.lat, 'lng': roundData.lng };
const country = roundData.streakLocationCode
const score = guess.roundScoreInPoints;
const distance = parseFloat(guess.distance.meters.amount);
const guessSeconds = guess.time;
coordinates.push({ gId,gameMode,playerId,latLng, country, score, distance, guessSeconds, forbidOptions,usingMap, gameDate,heading,pitch,zoom});
});
}}
resolve();
}catch (error) {
console.error(`Error parsing JSON from URL: ${url}`, error);
}
},
onerror: function(error) {
reject(error);
}
});
});
}
async function getPlayerName(id) {
return new Promise((resolve, reject) => {
const url = `https://www.geoguessr.com/user/${id}`;
GM_xmlhttpRequest({
method: 'GET',
url: url,
onload: function(response) {
if (response.status === 200) {
const playerName = extractPlayerName(response.responseText);
resolve(playerName);
} else {
reject('Error:', response.status);
}
},
onerror: function(error) {
reject('Error:', error);
}
});
});
}
function extractPlayerName(responseText) {
const regex = /"user"\s*:\s*{\s*"nick"\s*:\s*"(.+?)"/;
const match = responseText.match(regex);
if (match && match.length > 1) {
return match[1];
}
return null;
}
async function swalOption(){
const { value: inputOption,dismiss: inputDismiss } =await Swal.fire({
title: 'Get Activities',
text: 'Do you want to fetch activities from your Geoguessr account? If you click "Cancel", you will need to upload a JSON file',
icon: 'question',
showCancelButton: true,
showCloseButton:true,
allowOutsideClick: false,
input: 'number',
inputLabel: 'Set A Limit Of Activities Pages',
inputPlaceholder: '10',
inputAttributes: {
min:1,
max:80,
step:10,
},
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes',
cancelButtonText: 'Cancel',
inputValidator: (value) => {
if (!value||parseInt(value)<1) {
return 'Please set a valid limit number';
}
if (parseInt(value) > 100) {
return 'It is recommended that the maximum number of pages should not exceed 100!';
}
}
});
if (inputOption) {
const pageValue=parseInt(inputOption)
getActivities(u,activities,pageValue)
}
else if(inputDismiss==='cancel'){
const input = document.createElement('input');
input.type = 'file';
input.multiple = true;
input.style.display = 'none';
document.body.appendChild(input);
const coordsPromise = new Promise((resolve, reject) => {
input.addEventListener('change', async () => {
const files = Array.from(input.files);
try {
let combinedData = [];
let filesProcessed = 0;
for (const file of files) {
const reader = new FileReader();
reader.onload = (event) => {
try {
const result = JSON.parse(event.target.result);
combinedData = combinedData.concat(result);
filesProcessed++;
if (filesProcessed === files.length) {
const uniqueData = Array.from(new Set(combinedData));
resolve(uniqueData);
document.body.removeChild(input);
}
} catch (error) {
reject(new Error('Error parsing JSON data.'));
}
};
reader.readAsText(file);
}
} catch (error) {
reject(error);
}
});
input.click();
});
coordsPromise.then(async (data) => {
try {
var matchedData = matchPlayerNick(data);
createHeatmap(matchedData);
Swal.fire('Success', 'Heatmap is prepared!', 'success');
} catch (error) {
console.error("Error:", error);
Swal.fire('Error', 'Failed to prepare heatmap', 'error');
}
}).catch(error => {
console.error("Error:", error);
Swal.fire('Error', 'Failed to process uploaded files', 'error');
});
}
}
function createButton() {
var mapButton = document.createElement('button');
mapButton.textContent = 'Create Heatmap';
mapButton.addEventListener('click',swalOption);
mapButton.style.position = 'fixed';
mapButton.style.top = '8px';
mapButton.style.right = '58%';
mapButton.style.zIndex = '9999';
mapButton.style.borderRadius = "18px";
mapButton.style.padding = "5px 10px";
mapButton.style.border = "none";
mapButton.style.backgroundColor = "#4CAF50";
mapButton.style.color = "white";
mapButton.style.cursor = "pointer";
document.body.appendChild(mapButton);
var clearButton = document.createElement('button');
clearButton.textContent = 'Clear Activities';
clearButton.addEventListener('click', clearLocalStorage);
clearButton.style.position = 'fixed';
clearButton.style.top = '8px';
clearButton.style.right = '50%'
clearButton.style.zIndex = '9999';
clearButton.style.borderRadius = "18px";
clearButton.style.padding = "5px 10px";
clearButton.style.border = "none";
clearButton.style.backgroundColor = "#4CAF50";
clearButton.style.color = "white";
clearButton.style.cursor = "pointer";
document.body.appendChild(clearButton);
}
function processMapMakingData(coords) {
return new Promise((resolve, reject) => {
var convertedData = coords.map(function(item) {
var scoreCategory;
if (item.weight >= 0 && item.weight <= 1499) {
scoreCategory = "0-1499";
} else if (item.weight >= 1500 && item.weight <= 2999) {
scoreCategory = "1500-2999";
} else if (item.weight >= 3000 && item.weight <= 4499) {
scoreCategory = "3000-4499";
} else if (item.weight >= 4500 && item.weight <= 4999) {
scoreCategory = "4500-4999";
} else {
scoreCategory = "5000";
}
var tags = [];
if (item.gameMode) {
tags.push(item.gameMode);
}
if (item.playerNick) {
tags.push(item.player);
}
if (item.forbidOptions) {
tags.push(item.forbidOptions);
}
if (item.usingMap) {
tags.push(item.usingMap);
}
tags.push(scoreCategory);
return {
"lat": item.location.lat(),
"lng": item.location.lng(),
"heading": item.heading,
"pitch": item.pitch,
"zoom": item.zoom,
"panoId": null,
"countryCode": null,
"stateCode": null,
"extra": {
"tags": tags
}
};
})
resolve(convertedData);
});
}
async function createPanoSelector(panoId,selector,lat,lng) {
selector.innerHTML = ''
var result = await UE(panoId,lat,lng);
var panoYear,panoMonth,panos
if (result.length===3){
panoYear=result[1][6][7][0]
panoMonth=result[1][6][7][1]
}
else{
panoYear=result[1][0][6][7][0]
panoMonth=result[1][0][6][7][1]
}
const defaultPano = document.createElement('option');
defaultPano.value=panoId
defaultPano.textContent = ` ${monthNameList[panoMonth-1]} ${panoYear} (Default)`;
selector.appendChild(defaultPano);
try {
try{
panos = result[1][0][5][0][8];}
catch (error){
return
}
if (panos){
if (panos.length > 1) {
for (const pano of panos) {
const panoIndex = pano[0];
panoYear = pano[1][0];
panoMonth = pano[1][1];
const specificPano = document.createElement("option");
specificPano.value = result[1][0][5][0][3][0][panoIndex][0][1];
specificPano.textContent = `${monthNameList[panoMonth-1]} ${panoYear}`;
selector.appendChild(specificPano);
}
}
}
}
catch (error) {
console.log('Faile to load pano selector'+error)
}
}
async function UE(id,lat,lng) {
var url = `https://maps.googleapis.com/$rpc/google.internal.maps.mapsjs.v1.MapsJsInternalService/GetMetadata`;
var payload = JSON.stringify([["apiv3",null,null,null,"US",null,null,null,null,null,[[0]]],["en","US"],[[[2,id]]],[[1,2,3,4,8,6]]]);
if (id.length>22){url = `https://maps.googleapis.com/$rpc/google.internal.maps.mapsjs.v1.MapsJsInternalService/SingleImageSearch`;
payload=JSON.stringify(
[["apiv3",null,null,null,"US",null,null,null,null,null,[[0]]],[[null,null,lat,lng],30],[null,["en","US"],null,null,null,null,null,null,[2],null,[[[2,1,2],[3,1,2],[10,1,2]]]],[[1,2,3,4,8,6]]]
)
}
try {
const response = await new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "POST",
url: url,
headers: {
"Content-Type": "application/json+protobuf",
"x-user-agent": "grpc-web-javascript/0.1",
},
data: payload,
responseType: "json",
onload: resolve,
onerror: reject
});
});
if (response.status >= 200 && response.status < 300) {
return response.response;
} else {
throw new Error(`HTTP error! status: ${response.status}`);
}
} catch (error) {
console.error(`There was a problem with the UE function: ${error.message}`);
throw error;
}
}
loadGoogleMapsAPI()
createButton()
})()