florr.io | Playtime counter

Shows how no life you are

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         florr.io | Playtime counter
// @namespace    Furaken
// @version      2.0.5
// @description  Shows how no life you are
// @author       Furaken / sk
// @match        https://florr.io/*
// @grant        unsafeWindow
// @grant        GM_addStyle
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]
// ==/UserScript==

var getTodayDateLocalString = new Date().toString().substring(0,15),
    allAvailableServersNumber = 7,
    icons = {
        hamburger: "data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyBmaWxsPSIjZmZmZmZmIiB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAzMiAzMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBzdHJva2U9IiNmZmZmZmYiPgoNPGcgaWQ9IlNWR1JlcG9fYmdDYXJyaWVyIiBzdHJva2Utd2lkdGg9IjAiLz4KDTxnIGlkPSJTVkdSZXBvX3RyYWNlckNhcnJpZXIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgoNPGcgaWQ9IlNWR1JlcG9faWNvbkNhcnJpZXIiPgoNPHBhdGggZD0iTTYuMDAxIDcuMTI4TDYgMTAuNDM4bDE5Ljk5OC0uMDA1TDI2IDcuMTI0ek02LjAwMSAyMS41NjZMNiAyNC44NzZsMTkuOTk4LS4wMDYuMDAyLTMuMzA4ek02LjAwMSAxNC4zNDFMNiAxNy42NWwxOS45OTgtLjAwNC4wMDItMy4zMDl6Ii8+Cg08L2c+Cg08L3N2Zz4=",
        brackets: "data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBzdHJva2U9IiNmZmZmZmYiPgoNPGcgaWQ9IlNWR1JlcG9fYmdDYXJyaWVyIiBzdHJva2Utd2lkdGg9IjAiLz4KDTxnIGlkPSJTVkdSZXBvX3RyYWNlckNhcnJpZXIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgoNPGcgaWQ9IlNWR1JlcG9faWNvbkNhcnJpZXIiPiA8cGF0aCBkPSJNOSAyMUM3Ljg5NTQzIDIxIDcgMjAuMTA0NiA3IDE5VjE1LjMyNTVDNyAxNC44MzYzIDcgMTQuNTkxNyA2Ljk0NDc0IDE0LjM2MTVDNi44OTU3NSAxNC4xNTc1IDYuODE0OTQgMTMuOTYyNCA2LjcwNTI4IDEzLjc4MzRDNi41ODE2IDEzLjU4MTYgNi40MDg2MyAxMy40MDg2IDYuMDYyNzQgMTMuMDYyN0w1IDEyTDYuMDYyNzQgMTAuOTM3M0M2LjQwODY0IDEwLjU5MTQgNi41ODE2IDEwLjQxODQgNi43MDUyOCAxMC4yMTY2QzYuODE0OTQgMTAuMDM3NiA2Ljg5NTc1IDkuODQyNTQgNi45NDQ3NCA5LjYzODQ2QzcgOS40MDgyOSA3IDkuMTYzNyA3IDguNjc0NTJWNUM3IDMuODk1NDMgNy44OTU0MyAzIDkgM00xNSAyMUMxNi4xMDQ2IDIxIDE3IDIwLjEwNDYgMTcgMTlWMTUuMzI1NUMxNyAxNC44MzYzIDE3IDE0LjU5MTcgMTcuMDU1MyAxNC4zNjE1QzE3LjEwNDMgMTQuMTU3NSAxNy4xODUxIDEzLjk2MjQgMTcuMjk0NyAxMy43ODM0QzE3LjQxODQgMTMuNTgxNiAxNy41OTE0IDEzLjQwODYgMTcuOTM3MyAxMy4wNjI3TDE5IDEyTDE3LjkzNzMgMTAuOTM3M0MxNy41OTE0IDEwLjU5MTQgMTcuNDE4NCAxMC40MTg0IDE3LjI5NDcgMTAuMjE2NkMxNy4xODUxIDEwLjAzNzYgMTcuMTA0MyA5Ljg0MjU0IDE3LjA1NTMgOS42Mzg0NkMxNyA5LjQwODI5IDE3IDkuMTYzNyAxNyA4LjY3NDUyVjVDMTcgMy44OTU0MyAxNi4xMDQ2IDMgMTUgMyIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjIuNCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+IDwvZz4KDTwvc3ZnPg==",
        palette: "data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBzdHJva2U9IiNmZmZmZmYiPgoNPGcgaWQ9IlNWR1JlcG9fYmdDYXJyaWVyIiBzdHJva2Utd2lkdGg9IjAiLz4KDTxnIGlkPSJTVkdSZXBvX3RyYWNlckNhcnJpZXIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgoNPGcgaWQ9IlNWR1JlcG9faWNvbkNhcnJpZXIiPiA8cGF0aCBkPSJNMTUuNSA4LjVIMTUuNTFNMTAuNSA3LjVIMTAuNTFNNy41IDExLjVINy41MU0xMiAyMUM3LjAyOTQ0IDIxIDMgMTYuOTcwNiAzIDEyQzMgNy4wMjk0NCA3LjAyOTQ0IDMgMTIgM0MxNi45NzA2IDMgMjEgNy4wMjk0NCAyMSAxMkMyMSAxMy42NTY5IDE5LjY1NjkgMTUgMTggMTVIMTcuNEMxNy4wMjg0IDE1IDE2Ljg0MjYgMTUgMTYuNjg3MSAxNS4wMjQ2QzE1LjgzMTMgMTUuMTYwMiAxNS4xNjAyIDE1LjgzMTMgMTUuMDI0NiAxNi42ODcxQzE1IDE2Ljg0MjYgMTUgMTcuMDI4NCAxNSAxNy40VjE4QzE1IDE5LjY1NjkgMTMuNjU2OSAyMSAxMiAyMVpNMTYgOC41QzE2IDguNzc2MTQgMTUuNzc2MSA5IDE1LjUgOUMxNS4yMjM5IDkgMTUgOC43NzYxNCAxNSA4LjVDMTUgOC4yMjM4NiAxNS4yMjM5IDggMTUuNSA4QzE1Ljc3NjEgOCAxNiA4LjIyMzg2IDE2IDguNVpNMTEgNy41QzExIDcuNzc2MTQgMTAuNzc2MSA4IDEwLjUgOEMxMC4yMjM5IDggMTAgNy43NzYxNCAxMCA3LjVDMTAgNy4yMjM4NiAxMC4yMjM5IDcgMTAuNSA3QzEwLjc3NjEgNyAxMSA3LjIyMzg2IDExIDcuNVpNOCAxMS41QzggMTEuNzc2MSA3Ljc3NjE0IDEyIDcuNSAxMkM3LjIyMzg2IDEyIDcgMTEuNzc2MSA3IDExLjVDNyAxMS4yMjM5IDcuMjIzODYgMTEgNy41IDExQzcuNzc2MTQgMTEgOCAxMS4yMjM5IDggMTEuNVoiIHN0cm9rZT0iI2ZmZmZmZiIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4gPC9nPgoNPC9zdmc+",
        reset: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4MDBweCIgaGVpZ2h0PSI4MDBweCIgdmlld0JveD0iMCAwIDI0LjAwIDI0LjAwIiBmaWxsPSJub25lIiB0cmFuc2Zvcm09InJvdGF0ZSgwKSIgc3Ryb2tlPSIjMDAwMDAwIj4KCjxnIGlkPSJTVkdSZXBvX2JnQ2FycmllciIgc3Ryb2tlLXdpZHRoPSIwIi8+Cgo8ZyBpZD0iU1ZHUmVwb190cmFjZXJDYXJyaWVyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KCjxnIGlkPSJTVkdSZXBvX2ljb25DYXJyaWVyIj4gPHBhdGggZD0iTTIxIDNWOE0yMSA4SDE2TTIxIDhMMTggNS4yOTE2OEMxNi40MDc3IDMuODY2NTYgMTQuMzA1MSAzIDEyIDNDNy4wMjk0NCAzIDMgNy4wMjk0NCAzIDEyQzMgMTYuOTcwNiA3LjAyOTQ0IDIxIDEyIDIxQzE2LjI4MzIgMjEgMTkuODY3NSAxOC4wMDggMjAuNzc3IDE0IiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+IDwvZz4KCjwvc3ZnPg==",
        cross: "data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyBmaWxsPSIjZmZmZmZmIiB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAxNiAxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMC4wMDAxNiI+Cg08ZyBpZD0iU1ZHUmVwb19iZ0NhcnJpZXIiIHN0cm9rZS13aWR0aD0iMCIvPgoNPGcgaWQ9IlNWR1JlcG9fdHJhY2VyQ2FycmllciIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+Cg08ZyBpZD0iU1ZHUmVwb19pY29uQ2FycmllciI+IDxwYXRoIGQ9Ik0wIDE0LjU0NUwxLjQ1NSAxNiA4IDkuNDU1IDE0LjU0NSAxNiAxNiAxNC41NDUgOS40NTUgOCAxNiAxLjQ1NSAxNC41NDUgMCA4IDYuNTQ1IDEuNDU1IDAgMCAxLjQ1NSA2LjU0NSA4eiIgZmlsbC1ydWxlPSJldmVub2RkIi8+IDwvZz4KDTwvc3ZnPg==",
        eyeOpen: "data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KDTxnIGlkPSJTVkdSZXBvX2JnQ2FycmllciIgc3Ryb2tlLXdpZHRoPSIwIi8+Cg08ZyBpZD0iU1ZHUmVwb190cmFjZXJDYXJyaWVyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KDTxnIGlkPSJTVkdSZXBvX2ljb25DYXJyaWVyIj4gPHBhdGggZD0iTTE1LjAwMDcgMTJDMTUuMDAwNyAxMy42NTY5IDEzLjY1NzYgMTUgMTIuMDAwNyAxNUMxMC4zNDM5IDE1IDkuMDAwNzMgMTMuNjU2OSA5LjAwMDczIDEyQzkuMDAwNzMgMTAuMzQzMSAxMC4zNDM5IDkgMTIuMDAwNyA5QzEzLjY1NzYgOSAxNS4wMDA3IDEwLjM0MzEgMTUuMDAwNyAxMloiIHN0cm9rZT0iI2ZmZmZmZiIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4gPHBhdGggZD0iTTEyLjAwMTIgNUM3LjUyMzU0IDUgMy43MzMyNiA3Ljk0Mjg4IDIuNDU4OTggMTJDMy43MzMyNCAxNi4wNTcxIDcuNTIzNTQgMTkgMTIuMDAxMiAxOUMxNi40Nzg4IDE5IDIwLjI2OTEgMTYuMDU3MSAyMS41NDM0IDEyQzIwLjI2OTEgNy45NDI5MSAxNi40Nzg4IDUgMTIuMDAxMiA1WiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPiA8L2c+Cg08L3N2Zz4=",
        eyeClose: "data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KDTxnIGlkPSJTVkdSZXBvX2JnQ2FycmllciIgc3Ryb2tlLXdpZHRoPSIwIi8+Cg08ZyBpZD0iU1ZHUmVwb190cmFjZXJDYXJyaWVyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KDTxnIGlkPSJTVkdSZXBvX2ljb25DYXJyaWVyIj4gPHBhdGggZD0iTTIuOTk5MDIgM0wyMC45OTkgMjFNOS44NDMzIDkuOTEzNjRDOS4zMjA2NiAxMC40NTM2IDguOTk5MDIgMTEuMTg5MiA4Ljk5OTAyIDEyQzguOTk5MDIgMTMuNjU2OSAxMC4zNDIyIDE1IDExLjk5OSAxNUMxMi44MjE1IDE1IDEzLjU2NjcgMTQuNjY5IDE0LjEwODYgMTQuMTMzTTYuNDk5MDIgNi42NDcxNUM0LjU5OTcyIDcuOTAwMzQgMy4xNTMwNSA5Ljc4Mzk0IDIuNDU3MDMgMTJDMy43MzEyOCAxNi4wNTcxIDcuNTIxNTkgMTkgMTEuOTk5MiAxOUMxMy45ODgxIDE5IDE1Ljg0MTQgMTguNDE5NCAxNy4zOTg4IDE3LjQxODRNMTAuOTk5IDUuMDQ5MzlDMTEuMzI4IDUuMDE2NzMgMTEuNjYxNyA1IDExLjk5OTIgNUMxNi40NzY5IDUgMjAuMjY3MiA3Ljk0MjkxIDIxLjU0MTQgMTJDMjEuMjYwNyAxMi44OTQgMjAuODU3NyAxMy43MzM4IDIwLjM1MjIgMTQuNSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPiA8L2c+Cg08L3N2Zz4=",
        capture: "data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBzdHJva2U9IiNmZmZmZmYiPgoNPGcgaWQ9IlNWR1JlcG9fYmdDYXJyaWVyIiBzdHJva2Utd2lkdGg9IjAiLz4KDTxnIGlkPSJTVkdSZXBvX3RyYWNlckNhcnJpZXIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgoNPGcgaWQ9IlNWR1JlcG9faWNvbkNhcnJpZXIiPiA8cGF0aCBkPSJNMTIgMTZDMTMuNjU2OSAxNiAxNSAxNC42NTY5IDE1IDEzQzE1IDExLjM0MzEgMTMuNjU2OSAxMCAxMiAxMEMxMC4zNDMxIDEwIDkgMTEuMzQzMSA5IDEzQzkgMTQuNjU2OSAxMC4zNDMxIDE2IDEyIDE2WiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjIuNCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+IDxwYXRoIGQ9Ik0zIDE2LjhWOS4yQzMgOC4wNzk5IDMgNy41MTk4NCAzLjIxNzk5IDcuMDkyMDJDMy40MDk3MyA2LjcxNTY5IDMuNzE1NjkgNi40MDk3MyA0LjA5MjAyIDYuMjE3OTlDNC41MTk4NCA2IDUuMDc5OSA2IDYuMiA2SDcuMjU0NjRDNy4zNzc1OCA2IDcuNDM5MDUgNiA3LjQ5NTc2IDUuOTkzNUM3Ljc5MTY2IDUuOTU5NjEgOC4wNTcwNSA1Ljc5NTU5IDguMjE5NjkgNS41NDYwOUM4LjI1MDg2IDUuNDk4MjcgOC4yNzgzNiA1LjQ0MzI4IDguMzMzMzMgNS4zMzMzM0M4LjQ0MzI5IDUuMTEzNDIgOC40OTgyNyA1LjAwMzQ2IDguNTYwNjIgNC45MDc4MkM4Ljg4NTkgNC40MDg4MiA5LjQxNjY4IDQuMDgwNzggMTAuMDA4NSA0LjAxMjk5QzEwLjEyMTkgNCAxMC4yNDQ4IDQgMTAuNDkwNyA0SDEzLjUwOTNDMTMuNzU1MiA0IDEzLjg3ODEgNCAxMy45OTE1IDQuMDEyOTlDMTQuNTgzMyA0LjA4MDc4IDE1LjExNDEgNC40MDg4MiAxNS40Mzk0IDQuOTA3ODJDMTUuNTAxNyA1LjAwMzQ1IDE1LjU1NjcgNS4xMTM0NSAxNS42NjY3IDUuMzMzMzNDMTUuNzIxNiA1LjQ0MzI5IDE1Ljc0OTEgNS40OTgyNyAxNS43ODAzIDUuNTQ2MDlDMTUuOTQzIDUuNzk1NTkgMTYuMjA4MyA1Ljk1OTYxIDE2LjUwNDIgNS45OTM1QzE2LjU2MSA2IDE2LjYyMjQgNiAxNi43NDU0IDZIMTcuOEMxOC45MjAxIDYgMTkuNDgwMiA2IDE5LjkwOCA2LjIxNzk5QzIwLjI4NDMgNi40MDk3MyAyMC41OTAzIDYuNzE1NjkgMjAuNzgyIDcuMDkyMDJDMjEgNy41MTk4NCAyMSA4LjA3OTkgMjEgOS4yVjE2LjhDMjEgMTcuOTIwMSAyMSAxOC40ODAyIDIwLjc4MiAxOC45MDhDMjAuNTkwMyAxOS4yODQzIDIwLjI4NDMgMTkuNTkwMyAxOS45MDggMTkuNzgyQzE5LjQ4MDIgMjAgMTguOTIwMSAyMCAxNy44IDIwSDYuMkM1LjA3OTkgMjAgNC41MTk4NCAyMCA0LjA5MjAyIDE5Ljc4MkMzLjcxNTY5IDE5LjU5MDMgMy40MDk3MyAxOS4yODQzIDMuMjE3OTkgMTguOTA4QzMgMTguNDgwMiAzIDE3LjkyMDEgMyAxNi44WiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjIuNCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+IDwvZz4KDTwvc3ZnPg==",
        chart: "data:image/svg+xml;base64,PCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KDTwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIFRyYW5zZm9ybWVkIGJ5OiBTVkcgUmVwbyBNaXhlciBUb29scyAtLT4KPHN2ZyB3aWR0aD0iODAwcHgiIGhlaWdodD0iODAwcHgiIHZpZXdCb3g9IjAgMCA1MC44IDUwLjgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIj4KDTxnIGlkPSJTVkdSZXBvX2JnQ2FycmllciIgc3Ryb2tlLXdpZHRoPSIwIi8+Cg08ZyBpZD0iU1ZHUmVwb190cmFjZXJDYXJyaWVyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz4KDTxnIGlkPSJTVkdSZXBvX2ljb25DYXJyaWVyIj4gPGcgc3R5bGU9ImRpc3BsYXk6aW5saW5lIj4gPHBhdGggZD0iTTcuODU0IDMzLjU0NiAxNiAyMi44OTNsNy41MiAxNi4yOTMgNi4yNjctMjcuNTcyIDMuNzYgOC43NzMgNS42NC02Ljg5MyAzLjc2IDguMTQ2IiBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDo1LjA4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZCIvPiA8L2c+IDwvZz4KDTwvc3ZnPg=="
    },
    availableRegions = ["NA", "EU", "AS"],
    defaultColors = {
        "Garden": "#1EA761",
        "Desert": "#E0D1AF",
        "Ocean": "#66869E",
        "Jungle": "#3AA049",
        "Ant Hell": "#8E603F",
        "Sewers": "#752F08",
        "Hel / PvP": "#8F3838"
    },
    allAvailableMaps = Object.keys(defaultColors),
    defaultBarColors = {
        NA: "#EF476F",
        EU: "#FFD166",
        AS: "#06D6A0"
    },
    timeObject = JSON.stringify([
        {
            date: getTodayDateLocalString,
            region: {
                NA: 0,
                EU: 0,
                AS: 0
            },
            map: {
                Garden: 0
            }
        }
    ]),
    previewIndex = 0

function sumValuesInObject(obj) {
    var sum = 0
    for (var el in obj) {
        if(obj.hasOwnProperty(el)) {
            sum += Number(obj[el])
        }
    }
    return sum
}
function timeFormatting(input) {
    input = Number(input)
    var days = Math.floor(input / (24 * 60 * 60))
    var hours = Math.floor((input - days * (24 * 60 * 60)) / (60 * 60))
    var mins = Math.floor((input - days * (24 * 60 * 60) - hours * (60 * 60)) / 60)
    var seconds = input - days * (24 * 60 * 60) - hours * (60 * 60) - mins * 60
    seconds = Math.round(seconds * 100) / 100
    var output = `${days}d ${hours < 10 ? "0" + hours : hours}:${mins < 10 ? "0" + mins : mins}:${seconds < 10 ? "0" + seconds : seconds}`
    return output
}

Date.prototype.addDays = function(days) {
    var date = new Date(this.valueOf())
    date.setDate(date.getDate() + days)
    return date;
}

function getDates(startDate, stopDate) {
    var dateArray = new Array()
    var dateArrayTemporary = new Array()
    var currentDate = startDate
    while (currentDate <= stopDate) {
        dateArray.push(new Date(currentDate).toString().slice(8, 10))
        dateArrayTemporary.push(new Date(currentDate).toString().slice(0, 15))
        currentDate = currentDate.addDays(1)
    }
    return {dateArray, dateArrayTemporary}
}

function calcColor(min, max, val) {
    var minHue = 240, maxHue = 0
    var curPercent = (val - min) / (max - min)
    var colString = "hsl(" + ((curPercent * (maxHue - minHue)) + minHue) + ",100%,50%)"
    return colString
}

let cp6 = unsafeWindow.cp6
let url = "";
const nativeWebsocketFinder = unsafeWindow.WebSocket;
unsafeWindow.WebSocket = function (...args) {
    const wss = new nativeWebsocketFinder(...args);
    url = wss.url
    return wss;
};

var currentServers = [],
    currentCodes = [],
    currentServerName = ""

function getCp6Codes() {
    for (let i = 0; i <= allAvailableServersNumber; i++) {
        fetch(`https://api.n.m28.io/endpoint/florrio-map-${i}-green/findEach/`).then((response) => response.json()).then((data) => {
            currentServers[i] = `${data.servers["vultr-miami"].id} ${data.servers["vultr-frankfurt"].id} ${data.servers["vultr-tokyo"].id}`
        });
    }
}
getCp6Codes()

function findCurrentServer() {
    var AlternativeWSS = url.slice(6, url.indexOf("."))
    if (!currentServers.join(" ").includes(AlternativeWSS)) getCp6Codes()
    currentServers.forEach((item, index) => {
        if (item.includes(AlternativeWSS)) {
            currentCodes = item.split(" ")
            if (AlternativeWSS == currentCodes[0]) currentServerName = "NA"
            else if (AlternativeWSS == currentCodes[1]) currentServerName = "EU"
            else if (AlternativeWSS == currentCodes[2]) currentServerName = "AS"
        }
    })
}

if (!localStorage.getItem("playtimeCounter2")) localStorage.setItem("playtimeCounter2", timeObject)
var thisTimeObject = JSON.parse(localStorage.getItem("playtimeCounter2"))

var FurakenContainer = document.createElement('div')
FurakenContainer.style = `
    position: absolute;
    bottom: 10px;
    right: 10px;
    width: 100%;
`
document.querySelector('body').appendChild(FurakenContainer)

var playtimeCounterContainer = document.createElement('div')
playtimeCounterContainer.className = "options-button"
playtimeCounterContainer.style = `
    background-color: #BB5555;
    width: fit-content;
    height: auto;
    border-radius: 5px;
    border: 6px solid rgba(0, 0, 0, 0.3);
    padding: 5px;
    position: absolute;
    bottom: 0;
    right: 0;
    color: white;
    text-shadow: rgb(0 0 0) 2px 0px 0px, rgb(0 0 0) 1.75517px 0.958851px 0px, rgb(0 0 0) 1.0806px 1.68294px 0px, rgb(0 0 0) 0.141474px 1.99499px 0px, rgb(0 0 0) -0.832294px 1.81859px 0px, rgb(0 0 0) -1.60229px 1.19694px 0px, rgb(0 0 0) -1.97998px 0.28224px 0px, rgb(0 0 0) -1.87291px -0.701566px 0px, rgb(0 0 0) -1.30729px -1.5136px 0px, rgb(0 0 0) -0.421592px -1.95506px 0px, rgb(0 0 0) 0.567324px -1.91785px 0px, rgb(0 0 0) 1.41734px -1.41108px 0px, rgb(0 0 0) 1.92034px -0.558831px 0px;
    font-family: 'Ubuntu';
    cursor: pointer;
    transition: all 0.2s ease-in-out;
    text-align: center;
    box-shadow: 5px 5px rgba(0, 0, 0, 0.3);
    opacity: 0;
`
playtimeCounterContainer.innerHTML = `
    <div style="background-image: url(${icons.hamburger}); background-repeat: no-repeat; background-position: center; background-size: 35px; height: 30px; width: 30px;"></div>
`
playtimeCounterContainer.onclick = function() {
    playtimeCounterOptions.style.display = playtimeCounterOptions.style.display == "block" ? "none" : "block"
}
playtimeCounterContainer.onmouseover = function() {
    playtimeDataPreview.style.opacity = 1
    playtimeCounterContainer.style.opacity = 1
}
playtimeCounterContainer.onmouseout = function() {
    playtimeDataPreview.style.opacity = 0
    playtimeCounterContainer.style.opacity = 0
}
FurakenContainer.appendChild(playtimeCounterContainer)

var playtimeDataPreview = document.createElement('div')
playtimeDataPreview.className = "options-button"
playtimeDataPreview.style = `
    background-color: #BB5555;
    width: auto;
    height: 20px;
    line-height: 18px;
    border-radius: 5px;
    border: 6px solid rgba(0, 0, 0, 0.3);
    padding: 5px 20px;
    position: absolute;
    bottom: 0;
    right: 0;
    margin-right: 60px;
    color: white;
    text-shadow: rgb(0 0 0) 2px 0px 0px, rgb(0 0 0) 1.75517px 0.958851px 0px, rgb(0 0 0) 1.0806px 1.68294px 0px, rgb(0 0 0) 0.141474px 1.99499px 0px, rgb(0 0 0) -0.832294px 1.81859px 0px, rgb(0 0 0) -1.60229px 1.19694px 0px, rgb(0 0 0) -1.97998px 0.28224px 0px, rgb(0 0 0) -1.87291px -0.701566px 0px, rgb(0 0 0) -1.30729px -1.5136px 0px, rgb(0 0 0) -0.421592px -1.95506px 0px, rgb(0 0 0) 0.567324px -1.91785px 0px, rgb(0 0 0) 1.41734px -1.41108px 0px, rgb(0 0 0) 1.92034px -0.558831px 0px;
    font-family: 'Ubuntu';
    cursor: pointer;
    transition: all 0.2s ease-in-out;
    text-align: center;
    box-shadow: 5px 5px rgba(0, 0, 0, 0.3);
    opacity: 0;
    pointer-events: all;
`
playtimeDataPreview.innerHTML = "Fetching datas..."
playtimeDataPreview.onclick = function() {
    previewIndex = (previewIndex + 1) % 3
}
FurakenContainer.appendChild(playtimeDataPreview)

var playtimeCounterOptions = document.createElement('div')
playtimeCounterOptions.style = `
    height: auto;
    width: 30px;
    right: 0px;
    bottom: 60px;
    position: absolute;
    display: none;
`
FurakenContainer.appendChild(playtimeCounterOptions)

/*
var playtimeCounterOptions_EditableBox = document.createElement('div')
playtimeCounterOptions_EditableBox.contentEditable = "true"
playtimeCounterOptions_EditableBox.style = `
    overflow-y: auto;
    width: 300px;
    height: 83%;
    border-radius: 5px;
    background-color: #C52A61;
    border: 6px solid rgba(0, 0, 0, 0.3);
    position: absolute;
    margin-inline: -340px;
    box-shadow: 5px 5px rgba(0, 0, 0, 0.3);
    color: white;
    text-shadow: rgb(0 0 0) 2px 0px 0px, rgb(0 0 0) 1.75517px 0.958851px 0px, rgb(0 0 0) 1.0806px 1.68294px 0px, rgb(0 0 0) 0.141474px 1.99499px 0px, rgb(0 0 0) -0.832294px 1.81859px 0px, rgb(0 0 0) -1.60229px 1.19694px 0px, rgb(0 0 0) -1.97998px 0.28224px 0px, rgb(0 0 0) -1.87291px -0.701566px 0px, rgb(0 0 0) -1.30729px -1.5136px 0px, rgb(0 0 0) -0.421592px -1.95506px 0px, rgb(0 0 0) 0.567324px -1.91785px 0px, rgb(0 0 0) 1.41734px -1.41108px 0px, rgb(0 0 0) 1.92034px -0.558831px 0px;
    font-family: 'Ubuntu';
    font-size: 12px;
    padding: 10px;
`
playtimeCounterOptions.appendChild(playtimeCounterOptions_EditableBox)

var playtimeCounterOptions_Customize = document.createElement('div')
playtimeCounterOptions_Customize.innerHTML = `
    <div class="label">
        Customize
    </div>
`
playtimeCounterOptions.appendChild(playtimeCounterOptions_Customize)

var playtimeCounterOptions_Brackets = document.createElement('div')
playtimeCounterOptions_Brackets.innerHTML = `
    <div class="label">
        Datas
    </div>
`
playtimeCounterOptions.appendChild(playtimeCounterOptions_Brackets)
*/
var playtimeCounterOptions_Reset_Confirm = document.createElement('div')
playtimeCounterOptions_Reset_Confirm.innerHTML = `Clear all datas?`
playtimeCounterOptions_Reset_Confirm.className = "options-button"
playtimeCounterOptions_Reset_Confirm.style = `
    background-color: rgb(187, 85, 85);
    width: 100px;
    height: 20px;
    border-radius: 5px;
    border: 3px solid rgba(0, 0, 0, 0.3);
    background-size: 20px;
    background-repeat: no-repeat;
    background-position: center center;
    cursor: pointer;
    box-shadow: rgba(0, 0, 0, 0.3) 5px 5px;
    transition: all 0.2s ease-in-out 0s;
    position: absolute;
    right: 34px;
    color: white;
    text-shadow: rgb(0 0 0) 2px 0px 0px, rgb(0 0 0) 1.75517px 0.958851px 0px, rgb(0 0 0) 1.0806px 1.68294px 0px, rgb(0 0 0) 0.141474px 1.99499px 0px, rgb(0 0 0) -0.832294px 1.81859px 0px, rgb(0 0 0) -1.60229px 1.19694px 0px, rgb(0 0 0) -1.97998px 0.28224px 0px, rgb(0 0 0) -1.87291px -0.701566px 0px, rgb(0 0 0) -1.30729px -1.5136px 0px, rgb(0 0 0) -0.421592px -1.95506px 0px, rgb(0 0 0) 0.567324px -1.91785px 0px, rgb(0 0 0) 1.41734px -1.41108px 0px, rgb(0 0 0) 1.92034px -0.558831px 0px;
    font-family: 'Ubuntu';
    font-size: 12px;
    text-align: center;
    line-height: 20px;
    padding: 2px 5px;
    display: none;
    z-index: 1;
`
playtimeCounterOptions_Reset_Confirm.onclick = function() {
    localStorage.setItem("playtimeCounter2", JSON.stringify([{
        date: getTodayDateLocalString,
        region: {
            NA: 0,
            EU: 0,
            AS: 0
        },
        map: {
            Garden: 0
        }
    }]))
}
playtimeCounterOptions.appendChild(playtimeCounterOptions_Reset_Confirm)

var playtimeCounterOptions_Reset = document.createElement('div')
playtimeCounterOptions_Reset.innerHTML = `
    <div class="label">
        Reset
    </div>
`
playtimeCounterOptions_Reset.onclick = function() {
    playtimeCounterOptions_Reset_Confirm.style.display = playtimeCounterOptions_Reset_Confirm.style.display == "block" ? "none" : "block"
    playtimeCounterOptions_Reset.style.backgroundImage = playtimeCounterOptions_Reset_Confirm.style.display == "block" ? `url(${icons.cross})` : `url(${icons.reset})`
}
playtimeCounterOptions.appendChild(playtimeCounterOptions_Reset)

var ifEyeClose = false
var playtimeCounterOptions_Eye = document.createElement('div')
playtimeCounterOptions_Eye.innerHTML = `
    <div class="label">
        Toggle
    </div>
`
playtimeCounterOptions_Eye.onclick = function() {
    if (ifEyeClose) {
        ifEyeClose = false
        playtimeCounterOptions_Eye.style.backgroundImage = `url(${icons.eyeOpen})`
        playtimeDataPreview.style.pointerEvents = "all"
        playtimeDataPreview.classList.add("alwaysShow")
        playtimeCounterContainer.classList.add("alwaysShow")
    } else {
        ifEyeClose = true
        playtimeCounterOptions_Eye.style.backgroundImage = `url(${icons.eyeClose})`
        playtimeDataPreview.style.pointerEvents = "none"
        playtimeDataPreview.classList.remove("alwaysShow")
        playtimeCounterContainer.classList.remove("alwaysShow")
    }
}
playtimeCounterOptions.appendChild(playtimeCounterOptions_Eye)

var playtimeCounterOptions_Capture = document.createElement('div')
playtimeCounterOptions_Capture.innerHTML = `
    <div class="label">
        Capture
    </div>
`
playtimeCounterOptions_Capture.onclick = function() {
    var graph = document.getElementById("lineGraph")
    var image = new Image()
    image.src = graph.toDataURL()
    var blank_ = window.open("")
    blank_.document.body.appendChild(image)
    blank_.document.body.style.margin = 0
}
playtimeCounterOptions.appendChild(playtimeCounterOptions_Capture)

var playtimeCounterOptions_Chart = document.createElement('div')
playtimeCounterOptions_Chart.innerHTML = `
    <div class="label">
        Chart
    </div>
`
playtimeCounterOptions_Chart.onclick = function() {
    playtimeChart.style.opacity == 1 ? 0 : updateChartData()
    playtimeChart.style.opacity = playtimeChart.style.opacity == 1 ? 0 : 1
    playtimeChart.style.pointerEvents = playtimeChart.style.pointerEvents == "all" ? "none" : "all"
}
playtimeCounterOptions.appendChild(playtimeCounterOptions_Chart);

[/*playtimeCounterOptions_Brackets, playtimeCounterOptions_Customize, */playtimeCounterOptions_Reset, playtimeCounterOptions_Eye, playtimeCounterOptions_Capture, playtimeCounterOptions_Chart].forEach(item => {
    item.className = "options-button label-con"
    item.style = `
        width: 20px;
        height: 20px;
        border-radius: 5px;
        border: 3px solid rgba(0, 0, 0, 0.3);
        margin-bottom: 2px;
        background-size: 20px;
        background-repeat: no-repeat;
        background-position: center;
        padding: 2px;
        cursor: pointer;
        box-shadow: 5px 5px rgba(0, 0, 0, 0.3);
        transition: all 0.2s ease-in-out;
    `
})

playtimeDataPreview.classList.add("alwaysShow")
playtimeCounterContainer.classList.add("alwaysShow")
/*
playtimeCounterOptions_Customize.style.backgroundImage = `url(${icons.palette})`
playtimeCounterOptions_Customize.style.backgroundColor = `#C52A61`
playtimeCounterOptions_Brackets.style.backgroundImage = `url(${icons.brackets})`
playtimeCounterOptions_Brackets.style.backgroundColor = `#FFD166`
*/
playtimeCounterOptions_Reset.style.backgroundImage = `url(${icons.reset})`
playtimeCounterOptions_Reset.style.backgroundColor = `#BB5555`
playtimeCounterOptions_Eye.style.backgroundImage = `url(${icons.eyeOpen})`
playtimeCounterOptions_Eye.style.backgroundColor = `#2ACACC`
playtimeCounterOptions_Capture.style.backgroundImage = `url(${icons.capture})`
playtimeCounterOptions_Capture.style.backgroundColor = `#E83473`
playtimeCounterOptions_Chart.style.backgroundImage = `url(${icons.chart})`
playtimeCounterOptions_Chart.style.backgroundColor = `#2BFFA3`

var playtimeChart = document.createElement('div')
playtimeChart.style = `
    width: 100%;
    height: 100%;
    position: absolute;
    z-index: 100;
    top: 0;
    margin: 0;
    opacity: 0;
    transform: scale(0.9);
    transition: 0.4s ease-in-out;
    pointer-events: none;
`
playtimeChart.innerHTML = `
    <canvas id="lineGraph" style="border-radius: 15px;transition: 0.4s ease-in-out;position: absolute;z-index: 1;"></canvas>
`
document.querySelector('body').appendChild(playtimeChart)

Chart.defaults.font.family = 'Ubuntu';
Chart.defaults.font.size = 15;
Chart.defaults.font.weight = 600;
Chart.defaults.color = '#E7E7E7';
var lineGraph = new Chart(document.getElementById('lineGraph'), {
    data: {
        labels: [""],
        datasets: [{
            type: "line",
            data: [],
            label: ""
        }]
    },
    options: {
        // animation: false,
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
            customCanvasBackgroundColor: {
                color: "#2A2A2A",
            },
            legend: {
                labels: {
                    boxWidth: 15,
                    boxHeight: 15
                },
                position: "top"
            },
            datalabels: {
                formatter: (value, context) => {
                    if (context.dataset.label == "Total" && value != 0) return value.toFixed(2)
                    else if (context.dataset.label == "Average" && context.dataIndex == 0) return value.toFixed(2)
                    else return ""
                },
                color: "#E7E7E7",
                font: {
                    size: 12,
                    weight: 600
                },
                align: 'end'
            }
        },
        layout: {
            padding: 50
        },
        scales: {
            x: {
                title: {
                    display: true,
                    text: ["Date", `Last 30 days - ${new Date().toString().slice(4, 7)}`]
                },
                grid: {
                    color: "#E7E7E71A"
                }
            },
            y: {
                title: {
                    display: true,
                    text: "Hours"
                },
                grid: {
                    color: "#E7E7E71A"
                },
                min: 0,
                ticks: {
                    stepSize: 1
                }
            }
        },
    },
    plugins: [{
        id: 'customCanvasBackgroundColor',
        beforeDraw: (chart, args, options) => {
            const { ctx } = chart;
            ctx.save();
            ctx.globalCompositeOperation = 'destination-over';
            ctx.fillStyle = options.color || '#000000';
            ctx.fillRect(0, 0, chart.width, chart.height);
            ctx.restore();
        }
    }, ChartDataLabels]
});

function updateChartData() {
    var priorDate = new Date()
    priorDate.setDate(priorDate.getDate() - 29)
    priorDate = new Date(priorDate.toString().slice(0, 15))

    var today = new Date(new Date().toString().slice(0, 15))
    var temporaryTimeObjForChart = JSON.parse(localStorage.getItem("playtimeCounter2")),
        chartLabels = getDates(priorDate, today).dateArray,
        matchingDateArray = getDates(priorDate, today).dateArrayTemporary,
        chartDataSets = [],
        chartRegionDataSets = [],
        dataOfDataSets = [],
        totalPlaytimeData = [],
        averagePlaytimeData = []

    for (let index = 0; index < allAvailableMaps.length; index++) {
        chartDataSets[index] = {
            type: "line",
            label: allAvailableMaps[index] + "​",
            data: [],
            borderColor: defaultColors[allAvailableMaps[index]],
            borderWidth: 2.5,
            tension: 0.3
        }
        for (let i = 0; i < chartLabels.length; i++) {
            chartDataSets[index].data.push(0)
        }
    }

    for (let index = 0; index < availableRegions.length; index++) {
        chartRegionDataSets[index] = {
            type: "bar",
            label: availableRegions[index] + "​",
            data: [],
            fill: true,
            backgroundColor: defaultBarColors[availableRegions[index]],
        }
        for (let i = 0; i < chartLabels.length; i++) {
            chartRegionDataSets[index].data.push(0)
        }
    }

    temporaryTimeObjForChart.forEach((item, index) => {
        if (matchingDateArray.includes(item.date)) {
            for (const property in temporaryTimeObjForChart[index].map) {
                chartDataSets[allAvailableMaps.indexOf(property)].data[matchingDateArray.indexOf(item.date)] = temporaryTimeObjForChart[index].map[property] / 3600
                if (!totalPlaytimeData[matchingDateArray.indexOf(item.date)]) totalPlaytimeData[matchingDateArray.indexOf(item.date)] = 0
                totalPlaytimeData[matchingDateArray.indexOf(item.date)] += temporaryTimeObjForChart[index].map[property] / 3600
            }
            for (const property in temporaryTimeObjForChart[index].region) chartRegionDataSets[availableRegions.indexOf(property)].data[matchingDateArray.indexOf(item.date)] = temporaryTimeObjForChart[index].region[property] / 3600
        }
    })

    var thisIndex = 0,
        thisChartDataSetsLength = chartDataSets.length
    for (let i = 0; i < thisChartDataSetsLength; i++) {
        var isAllZero = chartDataSets[thisIndex].data.every(item => item == 0)
        if (isAllZero) {
            chartDataSets.splice(chartDataSets.indexOf(chartDataSets[thisIndex]), 1)
            thisIndex--
        }
        thisIndex++
    }

    totalPlaytimeData = Array.from(totalPlaytimeData, item => item || 0)
    var sumOfTotalPlaytimeData = totalPlaytimeData.reduce((accumulator, currentValue) => {
        return accumulator + currentValue
    }, 0)
    sumOfTotalPlaytimeData = sumOfTotalPlaytimeData / 30
    for (let i = 0; i < matchingDateArray.length; i++) averagePlaytimeData.push(sumOfTotalPlaytimeData)

    chartDataSets.unshift({
        type: "line",
        label: "Average",
        data: averagePlaytimeData,
        borderColor: "#2BFFA399",
        borderWidth: 3,
        pointRadius: 0
    })
    chartDataSets.unshift({
        type: "line",
        label: "Total",
        data: totalPlaytimeData,
        borderColor: "#E7E7E7",
        borderWidth: 3,
        tension: 0.3
    })
    chartDataSets = chartDataSets.concat(chartRegionDataSets)

    lineGraph.data.labels = chartLabels
    lineGraph.data.datasets = chartDataSets
    lineGraph.update()
}

// Credit to: Florr.io 汉化
function getFlorrioCanvas() {
    if (typeof (OffscreenCanvasRenderingContext2D) == 'undefined') {
        return [CanvasRenderingContext2D]
    }
    return [OffscreenCanvasRenderingContext2D, CanvasRenderingContext2D];
}

for (const { prototype } of getFlorrioCanvas()) {
    if (prototype.getArcPrototype == undefined) {
        prototype.getFillTextPrototype = prototype.fillText;
    } else { break }
}

var lastMapName,
    thisStartTime = 0,
    lastRegion,
    thisStartTimeOfRegions = 0,
    lastOnScreenTime = Date.now(),
    og_text

for (const { prototype } of getFlorrioCanvas()) {
    prototype.fillText = function(text, x, y) {
        if (allAvailableMaps.includes(text) || /\b([0-9]|[1-9][0-9])\b Flowers?/.test(text)) {
            if (/\b([0-9]|[1-9][0-9])\b Flowers?/.test(text)) {
                og_text = text
                text = "Hel / PvP"
            } else og_text = text
            lastOnScreenTime = Date.now()
            thisTimeObject = JSON.parse(localStorage.getItem("playtimeCounter2"))
            if (!thisTimeObject[0].map[text]) thisTimeObject[0].map[text] = 0
            if (lastMapName != text) thisStartTime = Date.now() - thisTimeObject[0].map[text] * 1000
            if (lastRegion != currentServerName) thisStartTimeOfRegions = Date.now() - thisTimeObject[0].region[currentServerName] * 1000
            var thisDelta = Date.now() - thisStartTime
            var thisDeltaOfRegions = Date.now() - thisStartTimeOfRegions
            thisTimeObject[0].map[text] = Math.floor(thisDelta / 1000)
            thisTimeObject[0].region[currentServerName] = Math.floor(thisDeltaOfRegions / 1000)
            lastMapName = text
            lastRegion = currentServerName
            localStorage.setItem("playtimeCounter2", JSON.stringify(thisTimeObject))
            var totalPlaytime = 0,
                thisMapPlaytime = 0
            thisTimeObject.forEach(item => {
                totalPlaytime += sumValuesInObject(item.map)
                thisMapPlaytime += item.map[text] == null ? 0 : item.map[text]
            })
            var playtimeDatasArray = [
                `<td>Since ${thisTimeObject[thisTimeObject.length - 1].date}:</td><td>${timeFormatting(totalPlaytime)}</td>`,
                `<td>${text}:</td><td>${timeFormatting(thisMapPlaytime)}</td>`,
                `<td>Today:</td><td>${timeFormatting(sumValuesInObject(thisTimeObject[0].map)).slice(3)}</td>`
            ]
            playtimeDataPreview.innerHTML = `
                <table style="border-spacing: 15px 0; pointer-events: none;">
                    <tr>
                        ${playtimeDatasArray[previewIndex]}
                    </tr>
                </table>
            `
            text = og_text
        }
        return this.getFillTextPrototype(text, x, y);
    }
}

document.querySelector('canvas').onclick = function() {
    playtimeChart.style.display = "none"
}

var WSSArray = []
setInterval(() => {
    WSSArray.unshift(url)
    if (WSSArray.length > 2) WSSArray.splice(2)
    if (WSSArray[WSSArray.length - 1] != WSSArray[0]) findCurrentServer()

    getTodayDateLocalString = new Date().toString().substring(0,15)
    var temporaryTimeObj = JSON.parse(localStorage.getItem("playtimeCounter2"))
    temporaryTimeObj = temporaryTimeObj.filter((value, index, self) => index === self.findIndex((t) => (
        t.date == value.date
    )))
    localStorage.setItem("playtimeCounter2", JSON.stringify(temporaryTimeObj))

    if (Date.now() - lastOnScreenTime > 1000 && lastMapName != "Hel / PvP") {
        thisStartTime = Date.now() - thisTimeObject[0].map[lastMapName] * 1000
        thisStartTimeOfRegions = Date.now() - thisTimeObject[0].region[currentServerName] * 1000
    }

    if (temporaryTimeObj[0].date != getTodayDateLocalString) {
        thisStartTime = Date.now()
        thisStartTimeOfRegions = Date.now()
        temporaryTimeObj.unshift({
            date: getTodayDateLocalString,
            region: {
                NA: 0,
                EU: 0,
                AS: 0
            },
            map: {
                Garden: 0
            }
        })
        localStorage.setItem("playtimeCounter2", JSON.stringify(temporaryTimeObj))
    }
}, 1000)

GM_addStyle(`
    .alwaysShow {
        opacity: 1!important
    }
    .options-button:hover {
        filter: brightness(1.1)
    }
    .label {
        pointer-events: none;
        z-index: 1;
        width: fit-content;
        height: auto;
        line-height: 14px;
        padding: 5px 15px;
        background: rgba(0, 0, 0, 0.5);
        text-shadow: rgb(0 0 0) 2px 0px 0px, rgb(0 0 0) 1.75517px 0.958851px 0px, rgb(0 0 0) 1.0806px 1.68294px 0px, rgb(0 0 0) 0.141474px 1.99499px 0px, rgb(0 0 0) -0.832294px 1.81859px 0px, rgb(0 0 0) -1.60229px 1.19694px 0px, rgb(0 0 0) -1.97998px 0.28224px 0px, rgb(0 0 0) -1.87291px -0.701566px 0px, rgb(0 0 0) -1.30729px -1.5136px 0px, rgb(0 0 0) -0.421592px -1.95506px 0px, rgb(0 0 0) 0.567324px -1.91785px 0px, rgb(0 0 0) 1.41734px -1.41108px 0px, rgb(0 0 0) 1.92034px -0.558831px 0px;
        font-family: 'Ubuntu';
        color: white;
        position: absolute;
        right: 130%;
        margin-block: -1px;
        border-radius: 5px;
        font-size: 12px;
        transition: all 0.3s ease-in-out;
        opacity: 0;
    }
    .label-con:hover .label {
        opacity: 1;
    }
`)