Greasy Fork is available in English.

Skribbl Essentials 2.5

Provides a list of potential words for skribbl.io

// ==UserScript==
// @name         Skribbl Essentials 2.5
// @match        *://skribbl.io/*
// @author       Databones
// @description  Provides a list of potential words for skribbl.io
// @namespace    https://discord.gg/jepPDJS7ra
// @version      2.5
// @license      MIT
// @icon         https://raw.githubusercontent.com/Databones/SkribblEssentials/main/logoGIF.gif
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// ==/UserScript==

// ──  FEATURES  ──
// 📄 Suggestions tab: Generate a smart list of potential guesses.
// 🖼️ Themes: Customize the background to your liking.
// 📦 Compact chat: Have the chat more instant and compact.
// 💾 Saveable private room settings: Save and load the settings you use for private rooms.
// 🎩 Hats: Allows you to wear hats seen by other players using only ASCII characters
// #️⃣ Special character usernames: Allows you to use all special characters by spoofing with lookalikes.
// 🔤 Fixed character limit: Enjoy an extended 14-character username.

// ──  2.5 CHANGES  ──
// Suggestions tab guessing improved: Now accounts for the hint's capitalization.
// Skribbl Essentials is made more compatible with older browsers.

"use strict";

function _typeof(obj) {
   "@babel/helpers - typeof";
   return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
      return typeof obj;
   } : function (obj) {
      return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
   }, _typeof(obj);
}

function _regeneratorRuntime() {
   "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
   _regeneratorRuntime = function _regeneratorRuntime() {
      return exports;
   };
   var exports = {},
      Op = Object.prototype,
      hasOwn = Op.hasOwnProperty,
      defineProperty = Object.defineProperty || function (obj, key, desc) {
         obj[key] = desc.value;
      },
      $Symbol = "function" == typeof Symbol ? Symbol : {},
      iteratorSymbol = $Symbol.iterator || "@@iterator",
      asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator",
      toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";

   function define(obj, key, value) {
      return Object.defineProperty(obj, key, {
         value: value,
         enumerable: !0,
         configurable: !0,
         writable: !0
      }), obj[key];
   }
   try {
      define({}, "");
   } catch (err) {
      define = function define(obj, key, value) {
         return obj[key] = value;
      };
   }

   function wrap(innerFn, outerFn, self, tryLocsList) {
      var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator,
         generator = Object.create(protoGenerator.prototype),
         context = new Context(tryLocsList || []);
      return defineProperty(generator, "_invoke", {
         value: makeInvokeMethod(innerFn, self, context)
      }), generator;
   }

   function tryCatch(fn, obj, arg) {
      try {
         return {
            type: "normal",
            arg: fn.call(obj, arg)
         };
      } catch (err) {
         return {
            type: "throw",
            arg: err
         };
      }
   }
   exports.wrap = wrap;
   var ContinueSentinel = {};

   function Generator() {}

   function GeneratorFunction() {}

   function GeneratorFunctionPrototype() {}
   var IteratorPrototype = {};
   define(IteratorPrototype, iteratorSymbol, function () {
      return this;
   });
   var getProto = Object.getPrototypeOf,
      NativeIteratorPrototype = getProto && getProto(getProto(values([])));
   NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype);
   var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);

   function defineIteratorMethods(prototype) {
      ["next", "throw", "return"].forEach(function (method) {
         define(prototype, method, function (arg) {
            return this._invoke(method, arg);
         });
      });
   }

   function AsyncIterator(generator, PromiseImpl) {
      function invoke(method, arg, resolve, reject) {
         var record = tryCatch(generator[method], generator, arg);
         if ("throw" !== record.type) {
            var result = record.arg,
               value = result.value;
            return value && "object" == _typeof(value) && hasOwn.call(value, "__await") ? PromiseImpl.resolve(value.__await).then(function (value) {
               invoke("next", value, resolve, reject);
            }, function (err) {
               invoke("throw", err, resolve, reject);
            }) : PromiseImpl.resolve(value).then(function (unwrapped) {
               result.value = unwrapped, resolve(result);
            }, function (error) {
               return invoke("throw", error, resolve, reject);
            });
         }
         reject(record.arg);
      }
      var previousPromise;
      defineProperty(this, "_invoke", {
         value: function value(method, arg) {
            function callInvokeWithMethodAndArg() {
               return new PromiseImpl(function (resolve, reject) {
                  invoke(method, arg, resolve, reject);
               });
            }
            return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
         }
      });
   }

   function makeInvokeMethod(innerFn, self, context) {
      var state = "suspendedStart";
      return function (method, arg) {
         if ("executing" === state) throw new Error("Generator is already running");
         if ("completed" === state) {
            if ("throw" === method) throw arg;
            return doneResult();
         }
         for (context.method = method, context.arg = arg;;) {
            var delegate = context.delegate;
            if (delegate) {
               var delegateResult = maybeInvokeDelegate(delegate, context);
               if (delegateResult) {
                  if (delegateResult === ContinueSentinel) continue;
                  return delegateResult;
               }
            }
            if ("next" === context.method) context.sent = context._sent = context.arg;
            else if ("throw" === context.method) {
               if ("suspendedStart" === state) throw state = "completed", context.arg;
               context.dispatchException(context.arg);
            } else "return" === context.method && context.abrupt("return", context.arg);
            state = "executing";
            var record = tryCatch(innerFn, self, context);
            if ("normal" === record.type) {
               if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue;
               return {
                  value: record.arg,
                  done: context.done
               };
            }
            "throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg);
         }
      };
   }

   function maybeInvokeDelegate(delegate, context) {
      var methodName = context.method,
         method = delegate.iterator[methodName];
      if (undefined === method) return context.delegate = null, "throw" === methodName && delegate.iterator["return"] && (context.method = "return", context.arg = undefined, maybeInvokeDelegate(delegate, context), "throw" === context.method) || "return" !== methodName && (context.method = "throw", context.arg = new TypeError("The iterator does not provide a '" + methodName + "' method")), ContinueSentinel;
      var record = tryCatch(method, delegate.iterator, context.arg);
      if ("throw" === record.type) return context.method = "throw", context.arg = record.arg, context.delegate = null, ContinueSentinel;
      var info = record.arg;
      return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, "return" !== context.method && (context.method = "next", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = "throw", context.arg = new TypeError("iterator result is not an object"), context.delegate = null, ContinueSentinel);
   }

   function pushTryEntry(locs) {
      var entry = {
         tryLoc: locs[0]
      };
      1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry);
   }

   function resetTryEntry(entry) {
      var record = entry.completion || {};
      record.type = "normal", delete record.arg, entry.completion = record;
   }

   function Context(tryLocsList) {
      this.tryEntries = [{
         tryLoc: "root"
      }], tryLocsList.forEach(pushTryEntry, this), this.reset(!0);
   }

   function values(iterable) {
      if (iterable) {
         var iteratorMethod = iterable[iteratorSymbol];
         if (iteratorMethod) return iteratorMethod.call(iterable);
         if ("function" == typeof iterable.next) return iterable;
         if (!isNaN(iterable.length)) {
            var i = -1,
               next = function next() {
                  for (; ++i < iterable.length;)
                     if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next;
                  return next.value = undefined, next.done = !0, next;
               };
            return next.next = next;
         }
      }
      return {
         next: doneResult
      };
   }

   function doneResult() {
      return {
         value: undefined,
         done: !0
      };
   }
   return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, "constructor", {
      value: GeneratorFunctionPrototype,
      configurable: !0
   }), defineProperty(GeneratorFunctionPrototype, "constructor", {
      value: GeneratorFunction,
      configurable: !0
   }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) {
      var ctor = "function" == typeof genFun && genFun.constructor;
      return !!ctor && (ctor === GeneratorFunction || "GeneratorFunction" === (ctor.displayName || ctor.name));
   }, exports.mark = function (genFun) {
      return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, "GeneratorFunction")), genFun.prototype = Object.create(Gp), genFun;
   }, exports.awrap = function (arg) {
      return {
         __await: arg
      };
   }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () {
      return this;
   }), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {
      void 0 === PromiseImpl && (PromiseImpl = Promise);
      var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);
      return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) {
         return result.done ? result.value : iter.next();
      });
   }, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, "Generator"), define(Gp, iteratorSymbol, function () {
      return this;
   }), define(Gp, "toString", function () {
      return "[object Generator]";
   }), exports.keys = function (val) {
      var object = Object(val),
         keys = [];
      for (var key in object) keys.push(key);
      return keys.reverse(),
         function next() {
            for (; keys.length;) {
               var key = keys.pop();
               if (key in object) return next.value = key, next.done = !1, next;
            }
            return next.done = !0, next;
         };
   }, exports.values = values, Context.prototype = {
      constructor: Context,
      reset: function reset(skipTempReset) {
         if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = "next", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset)
            for (var name in this) "t" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined);
      },
      stop: function stop() {
         this.done = !0;
         var rootRecord = this.tryEntries[0].completion;
         if ("throw" === rootRecord.type) throw rootRecord.arg;
         return this.rval;
      },
      dispatchException: function dispatchException(exception) {
         if (this.done) throw exception;
         var context = this;

         function handle(loc, caught) {
            return record.type = "throw", record.arg = exception, context.next = loc, caught && (context.method = "next", context.arg = undefined), !!caught;
         }
         for (var i = this.tryEntries.length - 1; i >= 0; --i) {
            var entry = this.tryEntries[i],
               record = entry.completion;
            if ("root" === entry.tryLoc) return handle("end");
            if (entry.tryLoc <= this.prev) {
               var hasCatch = hasOwn.call(entry, "catchLoc"),
                  hasFinally = hasOwn.call(entry, "finallyLoc");
               if (hasCatch && hasFinally) {
                  if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);
                  if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);
               } else if (hasCatch) {
                  if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);
               } else {
                  if (!hasFinally) throw new Error("try statement without catch or finally");
                  if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);
               }
            }
         }
      },
      abrupt: function abrupt(type, arg) {
         for (var i = this.tryEntries.length - 1; i >= 0; --i) {
            var entry = this.tryEntries[i];
            if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
               var finallyEntry = entry;
               break;
            }
         }
         finallyEntry && ("break" === type || "continue" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null);
         var record = finallyEntry ? finallyEntry.completion : {};
         return record.type = type, record.arg = arg, finallyEntry ? (this.method = "next", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record);
      },
      complete: function complete(record, afterLoc) {
         if ("throw" === record.type) throw record.arg;
         return "break" === record.type || "continue" === record.type ? this.next = record.arg : "return" === record.type ? (this.rval = this.arg = record.arg, this.method = "return", this.next = "end") : "normal" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel;
      },
      finish: function finish(finallyLoc) {
         for (var i = this.tryEntries.length - 1; i >= 0; --i) {
            var entry = this.tryEntries[i];
            if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel;
         }
      },
      "catch": function _catch(tryLoc) {
         for (var i = this.tryEntries.length - 1; i >= 0; --i) {
            var entry = this.tryEntries[i];
            if (entry.tryLoc === tryLoc) {
               var record = entry.completion;
               if ("throw" === record.type) {
                  var thrown = record.arg;
                  resetTryEntry(entry);
               }
               return thrown;
            }
         }
         throw new Error("illegal catch attempt");
      },
      delegateYield: function delegateYield(iterable, resultName, nextLoc) {
         return this.delegate = {
            iterator: values(iterable),
            resultName: resultName,
            nextLoc: nextLoc
         }, "next" === this.method && (this.arg = undefined), ContinueSentinel;
      }
   }, exports;
}

function _createForOfIteratorHelper(o, allowArrayLike) {
   var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
   if (!it) {
      if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
         if (it) o = it;
         var i = 0;
         var F = function F() {};
         return {
            s: F,
            n: function n() {
               if (i >= o.length) return {
                  done: true
               };
               return {
                  done: false,
                  value: o[i++]
               };
            },
            e: function e(_e) {
               throw _e;
            },
            f: F
         };
      }
      throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
   }
   var normalCompletion = true,
      didErr = false,
      err;
   return {
      s: function s() {
         it = it.call(o);
      },
      n: function n() {
         var step = it.next();
         normalCompletion = step.done;
         return step;
      },
      e: function e(_e2) {
         didErr = true;
         err = _e2;
      },
      f: function f() {
         try {
            if (!normalCompletion && it["return"] != null) it["return"]();
         } finally {
            if (didErr) throw err;
         }
      }
   };
}

function _unsupportedIterableToArray(o, minLen) {
   if (!o) return;
   if (typeof o === "string") return _arrayLikeToArray(o, minLen);
   var n = Object.prototype.toString.call(o).slice(8, -1);
   if (n === "Object" && o.constructor) n = o.constructor.name;
   if (n === "Map" || n === "Set") return Array.from(o);
   if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}

function _arrayLikeToArray(arr, len) {
   if (len == null || len > arr.length) len = arr.length;
   for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
   return arr2;
}

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
   try {
      var info = gen[key](arg);
      var value = info.value;
   } catch (error) {
      reject(error);
      return;
   }
   if (info.done) {
      resolve(value);
   } else {
      Promise.resolve(value).then(_next, _throw);
   }
}

function _asyncToGenerator(fn) {
   return function () {
      var self = this,
         args = arguments;
      return new Promise(function (resolve, reject) {
         var gen = fn.apply(self, args);

         function _next(value) {
            asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
         }

         function _throw(err) {
            asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
         }
         _next(undefined);
      });
   };
}
(function () {
   'use strict';

   var versionFileURL = 'https://raw.githubusercontent.com/Databones/SkribblEssentials/main/version';
   var redirectURL = 'https://github.com/Databones/SkribblEssentials/raw/main/Skribbl%20Essentials.user.js';

   function fetchRemoteVersion() {
      return _fetchRemoteVersion.apply(this, arguments);
   }

   function _fetchRemoteVersion() {
      _fetchRemoteVersion = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime().mark(function _callee() {
         var response, remoteVersion, currentVersion;
         return _regeneratorRuntime().wrap(function _callee$(_context) {
            while (1) switch (_context.prev = _context.next) {
               case 0:
                  _context.next = 2;
                  return fetch(versionFileURL);
               case 2:
                  response = _context.sent;
                  _context.next = 5;
                  return response.text();
               case 5:
                  remoteVersion = _context.sent;
                  currentVersion = GM_info.script.version;
                  if (remoteVersion.trim() !== currentVersion.trim()) {
                     window.location.href = redirectURL;
                  }
               case 8:
               case "end":
                  return _context.stop();
            }
         }, _callee);
      }));
      return _fetchRemoteVersion.apply(this, arguments);
   }
   if (typeof GM_info !== 'undefined' && GM_info.script) {
      fetchRemoteVersion();
   }

   function addStyles(styles) {
      var style = document.createElement('style');
      style.textContent = styles;
      document.head.appendChild(style);
   }
   addStyles("\n  .powered-by-skribbl-essentials {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    color: white;\n    font: inherit;\n    margin-top: 10px;\n  }\n");
   var logoLink = document.createElement('a');
   logoLink.href = 'https://github.com/Databones/SkribblEssentials';
   logoLink.target = '_blank';
   logoLink.style.textDecoration = 'none';
   var customLogoDiv = document.createElement('div');
   customLogoDiv.className = 'powered-by-skribbl-essentials';
   customLogoDiv.style.userSelect = 'none';
   customLogoDiv.style.pointerEvents = 'none';
   customLogoDiv.innerHTML = "\n  Powered by Skribbl Essentials 2.5\n  <img src=\"https://raw.githubusercontent.com/Databones/SkribblEssentials/main/logoGIF.gif\" alt=\"Skribbl Essentials Icon\" style=\"width: 25px; margin-left: 5px;\">\n";
   logoLink.appendChild(customLogoDiv);
   var logoBigDiv = document.querySelector('div.logo-big');
   if (logoBigDiv) {
      logoBigDiv.appendChild(logoLink);
   }

   function changeBackground(imageURL, repeat) {
      var img = new Image();
      img.src = imageURL;
      img.onload = function () {
         var isSquare = img.width === img.height;
         document.body.style.backgroundImage = "url(".concat(imageURL, ")");
         document.body.style.backgroundRepeat = isSquare ? 'repeat' : 'no-repeat';
         document.body.style.backgroundSize = isSquare ? 'auto' : 'cover';
         var svgElements = document.querySelectorAll('svg[viewBox="0 0 1 1"][preserveAspectRatio="none"]');
         svgElements.forEach(function (element) {
            element.remove();
            var styleElement = document.createElement('style');
            styleElement.innerHTML = ':root { --COLOR_PANEL_BG: rgba(12, 44, 150, 0.0) !important; }';
            document.head.appendChild(styleElement);
         });
      };
   }

   function handleThemingButtonClick() {
      var imageURL = prompt("Enter the image URL:");
      if (imageURL) {
         GM_setValue('backgroundImageURL', imageURL);
         GM_setValue('backgroundRepeat', false);
         changeBackground(imageURL, false);
      }
   }

   function handleResetButtonClick() {
      var defaultBackgroundImageURL = '/img/background.png';
      var defaultBackgroundRepeat = true;
      changeBackground(defaultBackgroundImageURL, defaultBackgroundRepeat);
      GM_setValue('backgroundImageURL', defaultBackgroundImageURL);
      GM_setValue('backgroundRepeat', defaultBackgroundRepeat);
   }

   function toggleSuggestions() {
      var currentSetting = GM_getValue('suggestions', true);
      var newSetting = !currentSetting;
      GM_setValue('suggestions', newSetting);
      updateToggleButton(newSetting);
      window.location.reload();
   }

   function toggleCompactChat() {
      var currentSetting = GM_getValue('compactChat', false);
      var newSetting = !currentSetting;
      GM_setValue('compactChat', newSetting);
      updateCompactChatButton(newSetting);
      window.location.reload();
   }

   function updateToggleButton(enabled) {
      var toggleButton = document.getElementById('suggestionsToggleButton');
      if (enabled) {
         toggleButton.style.backgroundColor = 'green';
      } else {
         toggleButton.style.backgroundColor = 'red';
      }
   }

   function updateCompactChatButton(enabled) {
      var compactChatButton = document.getElementById('compactChatToggleButton');
      if (enabled) {
         compactChatButton.style.backgroundColor = 'green';
      } else {
         compactChatButton.style.backgroundColor = 'red';
      }
   }
   var sectionContainers = document.querySelectorAll('.section-container');
   sectionContainers.forEach(function (container) {
      while (container.firstChild) {
         container.removeChild(container.firstChild);
      }
      var buttons = [createButton('Add custom background', handleThemingButtonClick), createButton('Reset', handleResetButtonClick)];
      var suggestionsToggleButton = createButton('Suggestions Tab', toggleSuggestions);
      suggestionsToggleButton.id = 'suggestionsToggleButton';
      buttons.push(suggestionsToggleButton);
      var compactChatToggleButton = createButton('Compact Chat', toggleCompactChat);
      compactChatToggleButton.id = 'compactChatToggleButton';
      buttons.push(compactChatToggleButton);
      buttons.forEach(function (button) {
         return container.appendChild(button);
      });
   });
   var savedImageURL = GM_getValue('backgroundImageURL');
   var backgroundRepeat = GM_getValue('backgroundRepeat');
   if (savedImageURL) {
      changeBackground(savedImageURL, backgroundRepeat);
   }
   var suggestionsEnabled = GM_getValue('suggestions', true);
   updateToggleButton(suggestionsEnabled);
   var compactChatEnabled = GM_getValue('compactChat', false);
   updateCompactChatButton(compactChatEnabled);

   function createButton(text, clickHandler) {
      var button = document.createElement('button');
      button.textContent = text;
      Object.assign(button.style, {
         borderRadius: '5px',
         padding: '5 5px',
         margin: '10 5px',
         color: 'black'
      });
      button.addEventListener('click', clickHandler);
      return button;
   }

   function changeMaxLength() {
      var inputElements = document.querySelectorAll('input.input-name[data-translate="placeholder"]');
      inputElements.forEach(function (element) {
         return element.setAttribute('maxlength', '14');
      });
   }

   function loadSettings() {
      var settingIds = ["item-settings-rounds", "item-settings-slots", "item-settings-language", "item-settings-drawtime", "item-settings-wordcount", "item-settings-hints"];
      for (var _i = 0, _settingIds = settingIds; _i < _settingIds.length; _i++) {
         var settingId = _settingIds[_i];
         var value = GM_getValue(settingId);
         if (value !== undefined) {
            var element = document.getElementById(settingId);
            if (element && element.tagName === "SELECT") {
               element.value = value;
               var event = new Event("change", {
                  bubbles: true
               });
               element.dispatchEvent(event);
            }
         }
      }
      var customWordsOnlyCheckbox = document.getElementById("item-settings-customwordsonly");
      if (customWordsOnlyCheckbox) {
         var checkboxValue = GM_getValue("item-settings-customwordsonly");
         if (checkboxValue !== undefined) {
            customWordsOnlyCheckbox.checked = checkboxValue === "on";
            customWordsOnlyCheckbox.dispatchEvent(new Event("change", {
               bubbles: true
            }));
         }
      }
      var customWordsTextarea = document.getElementById("item-settings-customwords");
      if (customWordsTextarea && customWordsTextarea.dataset.loaded !== "true") {
         var textareaValue = GM_getValue("item-settings-customwords");
         if (textareaValue !== undefined) {
            customWordsTextarea.value = textareaValue;
            customWordsTextarea.dispatchEvent(new Event("input", {
               bubbles: true
            }));
            customWordsTextarea.dataset.loaded = "true";
         }
      }
   }

   function storeSetting(settingId, value) {
      GM_setValue(settingId, value);
   }
   document.addEventListener("change", function (event) {
      if (event.target.matches("select, input[type='checkbox'], textarea")) {
         var settingId = event.target.id;
         var value = event.target.type === "checkbox" ? event.target.checked ? "on" : "off" : event.target.value;
         storeSetting(settingId, value);
      }
   });

   function checkForRoomShow() {
      var roomShowDiv = document.querySelector("div.room.show");
      if (roomShowDiv) {
         loadSettings();
      }
   }
   var observer = new MutationObserver(checkForRoomShow);
   var observerConfig = {
      childList: true,
      subtree: true
   };
   observer.observe(document, observerConfig);
   var compactChat = GM_getValue('compactChat', false);
   if (compactChat) {
      GM_addStyle("\n            #game-chat .chat-container .chat-content p {\n                padding: 0 !important;\n                animation: none !important;\n                transition: none !important;\n            }\n        ");
   }
   var replacements = {
      'dz': 'dz',
      '\\.': '․',
      'Dz': 'Dz',
      'DZ': 'DZ',
      'LJ': 'LJ',
      'Lj': 'Lj',
      'lj': 'lj',
      'NJ': 'NJ',
      'Nj': 'Nj',
      'nj': 'nj',
      '\\$': '$',
      '#': 'ⵌ',
      '%': '%',
      '&': '&',
      '\\(': '(',
      '\\)': ')',
      '\\+': '+',
      ',': ',',
      '\\/': '/',
      '\\\\': '\',
      ':': '׃',
      '\\?': '?',
      '\\{': '{',
      '}': '}',
      '<': 'ᐸ',
      '>': 'ᐳ',
      "'": '՚',
      '"': '‟'
   };

   function replaceCharacterCombinations(e) {
      var inputElement = e.target;
      var newValue = inputElement.value;
      for (var pattern in replacements) {
         if (replacements.hasOwnProperty(pattern)) {
            var regex = new RegExp(pattern, 'g');
            newValue = newValue.replace(regex, replacements[pattern]);
         }
      }
      inputElement.value = newValue;
   }
   var inputField = document.querySelector('input.input-name[type="text"][placeholder="Enter your name"]');
   if (inputField) {
      inputField.addEventListener('input', replaceCharacterCombinations);
   }

   function modifyPlayerName() {
      var targetDiv = document.querySelector('div.player-name.me');
      if (targetDiv) {
         targetDiv.classList.remove('me');
         targetDiv.classList.add('player-name');
         targetDiv.textContent = targetDiv.textContent.replace(' (You)', '');
      }
   }
   var observer2 = new MutationObserver(function (mutationsList) {
      var _iterator = _createForOfIteratorHelper(mutationsList),
         _step;
      try {
         for (_iterator.s(); !(_step = _iterator.n()).done;) {
            var mutation = _step.value;
            if (mutation.type === 'childList') {
               modifyPlayerName();
            }
         }
      } catch (err) {
         _iterator.e(err);
      } finally {
         _iterator.f();
      }
   });
   var targetNode = document.body;
   var config = {
      childList: true,
      subtree: true
   };
   observer2.observe(targetNode, config);
   var avatars = [{
      imageUrl: 'https://raw.githubusercontent.com/Databones/SkribblEssentials/main/avatars/Eyeball.png',
      avatarData: [0, 3, 0],
      name: 'DZDZDZ       👁👁',
      partsToChange: [1]
   }, {
      imageUrl: 'https://raw.githubusercontent.com/Databones/SkribblEssentials/main/avatars/Dark.png',
      avatarData: [0, 26, 0],
      name: 'ᅠᅠ          ⬤⬤',
      partsToChange: [1]
   }, {
      imageUrl: 'https://raw.githubusercontent.com/Databones/SkribblEssentials/main/avatars/Creepy.png',
      avatarData: [0, 42, 0],
      name: 'ᅠᅠ          ◉◉',
      partsToChange: [1]
   }, {
      imageUrl: 'https://raw.githubusercontent.com/Databones/SkribblEssentials/main/avatars/Pupils.png',
      avatarData: [0, 35, 0],
      name: 'ᅠᅠ          ⬤⬤',
      partsToChange: [1]
   }, {
      imageUrl: 'https://raw.githubusercontent.com/Databones/SkribblEssentials/main/avatars/Nose.png',
      avatarData: [0, 0, 0],
      name: 'ᅠᅠ          👃',
      partsToChange: [-1]
   }, {
      imageUrl: 'https://raw.githubusercontent.com/Databones/SkribblEssentials/main/avatars/PigSnout.png',
      avatarData: [0, 0, 0],
      name: 'ᅠᅠ          🐽',
      partsToChange: [-1]
   }, {
      imageUrl: 'https://raw.githubusercontent.com/Databones/SkribblEssentials/main/avatars/Sweat.png',
      avatarData: [0, 0, 0],
      name: 'ㅤ       ㅤ💧',
      partsToChange: [-1]
   }, {
      imageUrl: 'https://raw.githubusercontent.com/Databones/SkribblEssentials/main/avatars/Lips.png',
      avatarData: [0, 0, 6],
      name: 'ᅠᅠ          👄',
      partsToChange: [2]
   }, {
      imageUrl: 'https://raw.githubusercontent.com/Databones/SkribblEssentials/main/avatars/Stars.png',
      avatarData: [0, 0, 0],
      name: 'ㅤ       ✨',
      partsToChange: [-1]
   }];
   var panelRightElements = document.querySelectorAll('.panel-right .ad-side');
   var _iterator2 = _createForOfIteratorHelper(panelRightElements),
      _step2;
   try {
      for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
         var panelRightElement = _step2.value;
         panelRightElement.parentElement.removeChild(panelRightElement);
      }
   } catch (err) {
      _iterator2.e(err);
   } finally {
      _iterator2.f();
   }

   function applyAvatar(avatar) {
      var currentAvatarData = JSON.parse(localStorage.getItem('ava'));
      avatar.partsToChange.forEach(function (index) {
         currentAvatarData[index] = avatar.avatarData[index];
      });
      localStorage.setItem('ava', JSON.stringify(currentAvatarData));
      if (avatar.name) {
         localStorage.setItem('name', avatar.name);
      }
      window.location.reload();
   }
   var numRows = 3;
   var numCols = 5;
   var panelRight = document.querySelector('.panel-right');
   for (var i = 0; i < numRows; i++) {
      var row = document.createElement('div');
      row.className = 'avatar-row';
      var _loop = function _loop() {
         var index = i * numCols + j;
         if (index < avatars.length) {
            var avatar = avatars[index];
            var button = document.createElement('button');
            button.style.cursor = 'pointer';
            var image = document.createElement('img');
            image.src = avatar.imageUrl;
            image.draggable = false;
            image.style.userSelect = 'none';
            button.style = "\n                width: 92px;\n                height: 111px;\n                padding: 10px;\n                background-color: transparent;\n                border: none;\n                margin: 5px;\n            ";
            button.appendChild(image);
            button.addEventListener('click', function () {
               applyAvatar(avatar);
            });
            row.appendChild(button);
         }
      };
      for (var j = 0; j < numCols; j++) {
         _loop();
      }
      panelRight.appendChild(row);
   }
   var isSuggestionsEnabled = GM_getValue('suggestions', true);
   if (!isSuggestionsEnabled) {
      return;
   }
   var form = document.querySelector('form');
   var chatInput = document.querySelector('form input[placeholder="Type your guess here..."]');
   var chatContent = document.querySelector('.chat-content');
   var hintsContainer = document.querySelector('.hints .container');
   var suggestionsDiv = document.createElement('div');
   suggestionsDiv.className = 'suggestions';
   suggestionsDiv.style.maxHeight = '150px';
   suggestionsDiv.style.overflowY = 'auto';
   form.appendChild(suggestionsDiv);
   var clickedButtons = new Set();
   var wordList = [];

   function isWordListValid() {
      var storedData = localStorage.getItem("wordListData");
      if (storedData) {
         var _JSON$parse = JSON.parse(storedData),
            timestamp = _JSON$parse.timestamp,
            data = _JSON$parse.data;
         var now = new Date().getTime();
         if (now - timestamp <= 24 * 60 * 60 * 1000) {
            wordList = data.split('\n');
            return true;
         }
      }
      return false;
   }

   function fetchWordList() {
      if (!isWordListValid()) {
         fetch("https://raw.githubusercontent.com/Databones/SkribblEssentials/main/wordList").then(function (response) {
            return response.text();
         }).then(function (data) {
            var timestamp = new Date().getTime();
            localStorage.setItem("wordListData", JSON.stringify({
               timestamp: timestamp,
               data: data
            }));
            wordList = data.split('\n');
            updateSuggestions();
         })["catch"](function (error) {
            console.error("Error fetching data:", error);
         });
      }
   }

   function updateSuggestions() {
      var inputText = chatInput.value.trim().toLowerCase();
      var hintElements = hintsContainer.querySelectorAll('.hint');
      var hintText = Array.from(hintElements).map(function (element) {
         if (element.classList.contains('uncover')) {
            return element.textContent;
         } else {
            return element.textContent.replace(/_/g, '[^\\s-]');
         }
      }).join('');
      var hintRegExp = new RegExp("^".concat(hintText, "$"));
      var chatTextSpans = chatContent.querySelectorAll('p[style*="var(--COLOR_CHAT_TEXT_BASE)"] span');
      var chatText = Array.from(chatTextSpans).map(function (span) {
         return span.textContent.trim().toLowerCase();
      });
      var filteredWords = wordList.filter(function (word) {
         return hintRegExp.test(word) && !chatText.includes(word.toLowerCase()) && !clickedButtons.has(word);
      });
      suggestionsDiv.innerHTML = '';
      var fragment = document.createDocumentFragment();
      filteredWords.forEach(function (word) {
         if (word.toLowerCase().includes(inputText)) {
            var button = document.createElement('button');
            button.textContent = word;
            button.style.color = 'black';
            button.style.margin = '5px';
            button.style.borderRadius = '5px';
            button.style.userSelect = 'none';
            fragment.appendChild(button);
         }
      });
      suggestionsDiv.appendChild(fragment);
   }
   var debounceTimeout;
   chatInput.addEventListener('input', function () {
      clearTimeout(debounceTimeout);
      debounceTimeout = setTimeout(updateSuggestions, 50);
   });
   suggestionsDiv.addEventListener('mousedown', function (event) {
      if (event.target.tagName === 'BUTTON') {
         event.preventDefault();
         var lowercaseWord = event.target.textContent.toLowerCase();
         chatInput.value = lowercaseWord;
         clickedButtons.add(lowercaseWord);
         var inputEvent = new Event('input', {
            bubbles: true,
            cancelable: true
         });
         chatInput.dispatchEvent(inputEvent);
         var submitEvent = new Event('submit', {
            bubbles: true,
            cancelable: true
         });
         form.dispatchEvent(submitEvent);
      }
   });
   var observerConfig3 = {
      subtree: true,
      childList: true
   };
   var observer3 = new MutationObserver(updateSuggestions);
   observer3.observe(hintsContainer, observerConfig3);
   var chatObserver = new MutationObserver(updateSuggestions);
   chatObserver.observe(chatContent, {
      childList: true,
      subtree: true
   });
   fetchWordList();
   updateSuggestions();
   window.addEventListener('load', changeMaxLength);
   window.addEventListener('load', modifyPlayerName);
})();