diff --git a/an_website/emoji_chat/chat.ts b/an_website/emoji_chat/chat.ts index 3291fec96..e1372b5fe 100644 --- a/an_website/emoji_chat/chat.ts +++ b/an_website/emoji_chat/chat.ts @@ -63,6 +63,7 @@ const displayCurrentUser = (name: string[]) => { }; const emojiToIMG = (emoji: string) => { + // eslint-disable-next-line @typescript-eslint/no-misused-spread const chars = [...emoji]; const emojiCode = ( chars.length == 2 && chars[1] === "\uFE0F" ? [chars[0]!] : chars diff --git a/an_website/hangman_solver/hangman_solver.ts b/an_website/hangman_solver/hangman_solver.ts index 048c52090..68c630c57 100644 --- a/an_website/hangman_solver/hangman_solver.ts +++ b/an_website/hangman_solver/hangman_solver.ts @@ -123,6 +123,7 @@ function getRegex(state: State) { } async function loadWords(state: State): Promise { + // eslint-disable-next-line @typescript-eslint/no-misused-spread const wordLength = [...state.input].length; try { return await _loadWords(state.lang, wordLength); @@ -177,6 +178,7 @@ function updateLettersMap( } return; } + // eslint-disable-next-line @typescript-eslint/no-misused-spread const used = [...inputWithoutWildCards]; for (const char of word) { if (used.includes(char)) { diff --git a/an_website/static/js/emoji_chat/chat.js.map b/an_website/static/js/emoji_chat/chat.js.map index 4bbe5b936..6ec7063b0 100644 --- a/an_website/static/js/emoji_chat/chat.js.map +++ b/an_website/static/js/emoji_chat/chat.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../../../emoji_chat/chat.ts"], - "sourcesContent": ["// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0-or-later\nexport {};\n\nconst messageInput = document.getElementById(\n \"message-input\",\n) as HTMLInputElement;\nconst messageInputForm = messageInput.form!;\nconst messageSection = document.getElementById(\"message-section\")!;\nconst usingOpenMoji = document.getElementById(\"openmoji-attribution\");\nconst openmojiVersion = usingOpenMoji?.getAttribute(\"openmoji-version\");\nconst connectionIndicator = document.getElementById(\"connection-state\")!;\nconst currentUser = document.getElementById(\"current-user\")!;\nlet reconnectTimeout = 100;\nlet reconnectTries = 0;\nlet lastMessage = \"\";\n\nconst timeStampToText = (timestamp: number) => {\n return new Date(timestamp + 1651075200000).toLocaleString();\n};\n\nconst getOpenMojiType = () => usingOpenMoji?.getAttribute(\"type\");\n\ninterface Message {\n author: string[];\n content: string[];\n timestamp: number;\n}\n\nconst appendMessage = (msg: Message) => {\n const el = document.createElement(\"div\");\n const emojiType = getOpenMojiType();\n if (emojiType === \"img\") {\n for (const emoji of msg.author) {\n el.append(emojiToIMG(emoji));\n }\n el.innerHTML += \": \";\n for (const emoji of msg.content) {\n el.append(emojiToIMG(emoji));\n }\n } else {\n el.innerText = `${msg.author.join(\"\")}: ${msg.content.join(\"\")}`;\n if (emojiType) {\n el.classList.add(\"openmoji\");\n }\n }\n el.setAttribute(\"tooltip\", timeStampToText(msg.timestamp));\n messageSection.append(el);\n};\n\nconst displayCurrentUser = (name: string[]) => {\n currentUser.innerHTML = \"\";\n const emojiType = getOpenMojiType();\n if (emojiType === \"img\") {\n for (const emoji of name) {\n currentUser.append(emojiToIMG(emoji));\n }\n return;\n }\n if (emojiType) {\n currentUser.classList.add(\"openmoji\");\n }\n currentUser.innerText = name.join(\"\");\n};\n\nconst emojiToIMG = (emoji: string) => {\n const chars = [...emoji];\n const emojiCode = (\n chars.length == 2 && chars[1] === \"\\uFE0F\" ? [chars[0]!] : chars\n )\n .map((e: string) => e.codePointAt(0)!.toString(16).padStart(4, \"0\"))\n .join(\"-\")\n .toUpperCase();\n\n const imgEl = document.createElement(\"img\");\n\n const path = `/static/openmoji/svg/${emojiCode}.svg`;\n imgEl.src = openmojiVersion ? `${path}?v=${openmojiVersion}` : path;\n\n imgEl.classList.add(\"emoji\");\n imgEl.alt = emoji;\n\n return imgEl;\n};\n\nconst resetLastMessage = () => {\n if (lastMessage && !messageInput.value) {\n messageInput.value = lastMessage;\n lastMessage = \"\";\n }\n};\n\nconst setConnectionState = (state: string) => {\n let tooltip;\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n connectionIndicator.onclick = () => {};\n if (state === \"connecting\") {\n tooltip = \"Versuche mit WebSocket zu verbinden\";\n } else if (state === \"connected\") {\n tooltip = \"Mit WebSocket verbunden!\";\n } else if (state === \"disconnected\") {\n tooltip = \"Verbindung getrennt. Drücke hier um erneut zu versuchen.\";\n connectionIndicator.onclick = () => {\n reconnectTries = 0;\n reconnectTimeout = 500;\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n connectionIndicator.onclick = () => {};\n openWS();\n };\n } else {\n console.error(\"invalid state\", state);\n return;\n }\n connectionIndicator.setAttribute(\"state\", state);\n connectionIndicator.setAttribute(\"tooltip\", tooltip);\n};\n\nconst handleWebSocketData = (event: { data: string }) => {\n const data = JSON.parse(event.data) as {\n type: string;\n // the following are only present depending on the type\n message: Message;\n messages: Message[];\n current_user: string[];\n retry_after: number;\n users: string[];\n error: string;\n };\n switch (data.type) {\n case \"messages\": {\n messageSection.innerText = \"\";\n for (const msg of data.messages) {\n appendMessage(msg);\n }\n break;\n }\n case \"message\": {\n // console.debug(\"New message\", data[\"message\"]);\n appendMessage(data.message);\n break;\n }\n case \"init\": {\n displayCurrentUser(data.current_user);\n console.log(\"Connected as\", data.current_user.join(\"\"));\n setConnectionState(\"connected\");\n reconnectTimeout = 100;\n reconnectTries = 0;\n break;\n }\n case \"users\": {\n // only gets sent in dev mode of website\n console.debug(\"Received users data\", data.users);\n break;\n }\n case \"ratelimit\": {\n resetLastMessage();\n // TODO: Don't use alert\n alert(`Retry after ${data.retry_after} seconds.`);\n break;\n }\n case \"error\": {\n resetLastMessage();\n alert(data.error); // TODO: Don't use alert\n break;\n }\n default: {\n console.error(`Invalid type ${data.type}`);\n }\n }\n};\n\nconst openWS = () => {\n setConnectionState(\"connecting\");\n const ws = new WebSocket(\n (location.protocol === \"https:\" ? \"wss:\" : \"ws:\") +\n `//${location.host}/websocket/emoji-chat`,\n );\n const pingInterval = setInterval(() => {\n ws.send(\"\");\n }, 10000);\n ws.onclose = (event) => {\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n messageInputForm.onsubmit = () => {};\n if (event.wasClean) {\n console.debug(\n `Connection closed cleanly, code=${event.code} reason=${event.reason}`,\n );\n setConnectionState(\"disconnected\");\n return;\n }\n console.debug(\n `Connection closed, reconnecting in ${reconnectTimeout}ms`,\n );\n setConnectionState(\"connecting\");\n clearInterval(pingInterval);\n if (reconnectTries > 20) {\n // ~3 minutes not connected, just give up\n setConnectionState(\"disconnected\");\n return;\n }\n setTimeout(() => {\n reconnectTimeout = Math.max(\n 500, // minimum 500ms, for a better curve\n Math.floor(\n // maximum 15s, so we don't have to wait too long\n Math.min(15000, 1.5 * reconnectTimeout - 200),\n ),\n );\n reconnectTries++;\n openWS(); // restart connection\n }, reconnectTimeout);\n };\n ws.onopen = (event) => {\n console.debug(\"Opened WebSocket\", event);\n };\n ws.onmessage = handleWebSocketData;\n\n messageInputForm.onsubmit = (event) => {\n if (messageInput.value !== \"\") {\n lastMessage = messageInput.value;\n ws.send(\n JSON.stringify({\n type: \"message\",\n message: messageInput.value,\n }),\n );\n messageInput.value = \"\";\n }\n event.preventDefault();\n };\n};\nopenWS();\n"], - "mappings": "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", + "sourcesContent": ["// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0-or-later\nexport {};\n\nconst messageInput = document.getElementById(\n \"message-input\",\n) as HTMLInputElement;\nconst messageInputForm = messageInput.form!;\nconst messageSection = document.getElementById(\"message-section\")!;\nconst usingOpenMoji = document.getElementById(\"openmoji-attribution\");\nconst openmojiVersion = usingOpenMoji?.getAttribute(\"openmoji-version\");\nconst connectionIndicator = document.getElementById(\"connection-state\")!;\nconst currentUser = document.getElementById(\"current-user\")!;\nlet reconnectTimeout = 100;\nlet reconnectTries = 0;\nlet lastMessage = \"\";\n\nconst timeStampToText = (timestamp: number) => {\n return new Date(timestamp + 1651075200000).toLocaleString();\n};\n\nconst getOpenMojiType = () => usingOpenMoji?.getAttribute(\"type\");\n\ninterface Message {\n author: string[];\n content: string[];\n timestamp: number;\n}\n\nconst appendMessage = (msg: Message) => {\n const el = document.createElement(\"div\");\n const emojiType = getOpenMojiType();\n if (emojiType === \"img\") {\n for (const emoji of msg.author) {\n el.append(emojiToIMG(emoji));\n }\n el.innerHTML += \": \";\n for (const emoji of msg.content) {\n el.append(emojiToIMG(emoji));\n }\n } else {\n el.innerText = `${msg.author.join(\"\")}: ${msg.content.join(\"\")}`;\n if (emojiType) {\n el.classList.add(\"openmoji\");\n }\n }\n el.setAttribute(\"tooltip\", timeStampToText(msg.timestamp));\n messageSection.append(el);\n};\n\nconst displayCurrentUser = (name: string[]) => {\n currentUser.innerHTML = \"\";\n const emojiType = getOpenMojiType();\n if (emojiType === \"img\") {\n for (const emoji of name) {\n currentUser.append(emojiToIMG(emoji));\n }\n return;\n }\n if (emojiType) {\n currentUser.classList.add(\"openmoji\");\n }\n currentUser.innerText = name.join(\"\");\n};\n\nconst emojiToIMG = (emoji: string) => {\n // eslint-disable-next-line @typescript-eslint/no-misused-spread\n const chars = [...emoji];\n const emojiCode = (\n chars.length == 2 && chars[1] === \"\\uFE0F\" ? [chars[0]!] : chars\n )\n .map((e: string) => e.codePointAt(0)!.toString(16).padStart(4, \"0\"))\n .join(\"-\")\n .toUpperCase();\n\n const imgEl = document.createElement(\"img\");\n\n const path = `/static/openmoji/svg/${emojiCode}.svg`;\n imgEl.src = openmojiVersion ? `${path}?v=${openmojiVersion}` : path;\n\n imgEl.classList.add(\"emoji\");\n imgEl.alt = emoji;\n\n return imgEl;\n};\n\nconst resetLastMessage = () => {\n if (lastMessage && !messageInput.value) {\n messageInput.value = lastMessage;\n lastMessage = \"\";\n }\n};\n\nconst setConnectionState = (state: string) => {\n let tooltip;\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n connectionIndicator.onclick = () => {};\n if (state === \"connecting\") {\n tooltip = \"Versuche mit WebSocket zu verbinden\";\n } else if (state === \"connected\") {\n tooltip = \"Mit WebSocket verbunden!\";\n } else if (state === \"disconnected\") {\n tooltip = \"Verbindung getrennt. Drücke hier um erneut zu versuchen.\";\n connectionIndicator.onclick = () => {\n reconnectTries = 0;\n reconnectTimeout = 500;\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n connectionIndicator.onclick = () => {};\n openWS();\n };\n } else {\n console.error(\"invalid state\", state);\n return;\n }\n connectionIndicator.setAttribute(\"state\", state);\n connectionIndicator.setAttribute(\"tooltip\", tooltip);\n};\n\nconst handleWebSocketData = (event: { data: string }) => {\n const data = JSON.parse(event.data) as {\n type: string;\n // the following are only present depending on the type\n message: Message;\n messages: Message[];\n current_user: string[];\n retry_after: number;\n users: string[];\n error: string;\n };\n switch (data.type) {\n case \"messages\": {\n messageSection.innerText = \"\";\n for (const msg of data.messages) {\n appendMessage(msg);\n }\n break;\n }\n case \"message\": {\n // console.debug(\"New message\", data[\"message\"]);\n appendMessage(data.message);\n break;\n }\n case \"init\": {\n displayCurrentUser(data.current_user);\n console.log(\"Connected as\", data.current_user.join(\"\"));\n setConnectionState(\"connected\");\n reconnectTimeout = 100;\n reconnectTries = 0;\n break;\n }\n case \"users\": {\n // only gets sent in dev mode of website\n console.debug(\"Received users data\", data.users);\n break;\n }\n case \"ratelimit\": {\n resetLastMessage();\n // TODO: Don't use alert\n alert(`Retry after ${data.retry_after} seconds.`);\n break;\n }\n case \"error\": {\n resetLastMessage();\n alert(data.error); // TODO: Don't use alert\n break;\n }\n default: {\n console.error(`Invalid type ${data.type}`);\n }\n }\n};\n\nconst openWS = () => {\n setConnectionState(\"connecting\");\n const ws = new WebSocket(\n (location.protocol === \"https:\" ? \"wss:\" : \"ws:\") +\n `//${location.host}/websocket/emoji-chat`,\n );\n const pingInterval = setInterval(() => {\n ws.send(\"\");\n }, 10000);\n ws.onclose = (event) => {\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n messageInputForm.onsubmit = () => {};\n if (event.wasClean) {\n console.debug(\n `Connection closed cleanly, code=${event.code} reason=${event.reason}`,\n );\n setConnectionState(\"disconnected\");\n return;\n }\n console.debug(\n `Connection closed, reconnecting in ${reconnectTimeout}ms`,\n );\n setConnectionState(\"connecting\");\n clearInterval(pingInterval);\n if (reconnectTries > 20) {\n // ~3 minutes not connected, just give up\n setConnectionState(\"disconnected\");\n return;\n }\n setTimeout(() => {\n reconnectTimeout = Math.max(\n 500, // minimum 500ms, for a better curve\n Math.floor(\n // maximum 15s, so we don't have to wait too long\n Math.min(15000, 1.5 * reconnectTimeout - 200),\n ),\n );\n reconnectTries++;\n openWS(); // restart connection\n }, reconnectTimeout);\n };\n ws.onopen = (event) => {\n console.debug(\"Opened WebSocket\", event);\n };\n ws.onmessage = handleWebSocketData;\n\n messageInputForm.onsubmit = (event) => {\n if (messageInput.value !== \"\") {\n lastMessage = messageInput.value;\n ws.send(\n JSON.stringify({\n type: \"message\",\n message: messageInput.value,\n }),\n );\n messageInput.value = \"\";\n }\n event.preventDefault();\n };\n};\nopenWS();\n"], + "mappings": "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", "names": ["messageInput", "messageInputForm", "messageSection", "usingOpenMoji", "openmojiVersion", "connectionIndicator", "currentUser", "reconnectTimeout", "reconnectTries", "lastMessage", "timeStampToText", "timestamp", "getOpenMojiType", "appendMessage", "msg", "el", "emojiType", "emoji", "emojiToIMG", "displayCurrentUser", "name", "chars", "emojiCode", "e", "imgEl", "path", "resetLastMessage", "setConnectionState", "state", "tooltip", "openWS", "handleWebSocketData", "event", "data", "ws", "pingInterval"] } diff --git a/an_website/static/js/hangman_solver/hangman_solver.js.map b/an_website/static/js/hangman_solver/hangman_solver.js.map index 200a207ee..a07b5135f 100644 --- a/an_website/static/js/hangman_solver/hangman_solver.js.map +++ b/an_website/static/js/hangman_solver/hangman_solver.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../../../hangman_solver/hangman_solver.ts"], - "sourcesContent": ["// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0-or-later\n// stolen from: https://github.com/asozialesnetzwerk/Hangman-Solver/blob/ba693776f634e682553ac37a45157cd0ceeab6a9/js/index.js\n\nimport { PopStateHandlers, setMultipleURLParams } from \"@utils/utils.js\";\n\nconst wildCardChar = \"_\";\n// to replace \"_\" with regex\nconst wildCardRegex = /_+/g;\n// to replace ?, or # with _\nconst notRealWildCardRegex = /[#?]/g;\n// to remove whitespaces\nconst whiteSpaceRegex = /\\s+/g;\n// to remove duplicate chars:\nconst duplicateCharsRegex = /(.)(?=.*\\1)/g;\n\nfunction getForm() {\n return document.getElementById(\"hangman-solver-form\") as HTMLFormElement;\n}\n\ninterface StringValueObject {\n value: string;\n}\n\nconst _getLowerCaseValueWithoutWhitespace: (\n input: StringValueObject,\n) => string = (input) => input.value.toLowerCase().replace(whiteSpaceRegex, \"\");\n\nfunction getHtmlInputElements() {\n return {\n input: [\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n document.querySelector(\"input[name='input']\") as HTMLInputElement,\n (input: HTMLInputElement) =>\n _getLowerCaseValueWithoutWhitespace(input).replace(\n notRealWildCardRegex,\n wildCardChar,\n ),\n ],\n invalid: [\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n document.querySelector(\"input[name='invalid']\") as HTMLInputElement,\n (input: HTMLInputElement) => {\n // remove invalid chars and normalize\n const value: string = _getLowerCaseValueWithoutWhitespace(input)\n .replace(\n notRealWildCardRegex,\n \"\",\n )\n .replace(wildCardRegex, \"\");\n // remove duplicates\n const arr: string[] = [\n ...new Set(value),\n ];\n // sort\n arr.sort();\n return arr.join(\"\");\n },\n ],\n max_words: [\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n document.querySelector(\n \"input[name='max_words']\",\n ) as HTMLInputElement,\n (input: StringValueObject): number =>\n Number.parseInt(input.value, 10),\n ],\n crossword_mode: [\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n document.querySelector(\n \"input[name='crossword_mode']\",\n ) as HTMLInputElement,\n (input: { checked: boolean }): boolean => input.checked,\n ],\n lang: [\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n document.querySelector(\"select[name='lang']\") as HTMLSelectElement,\n _getLowerCaseValueWithoutWhitespace,\n ],\n } as const;\n}\ntype HtmlInputElements = ReturnType;\ntype State = {\n [TKey in keyof HtmlInputElements]: ReturnType;\n};\n\nfunction getState(): State {\n const inputElements: HtmlInputElements = getHtmlInputElements();\n return {\n input: inputElements.input[1](inputElements.input[0]),\n invalid: inputElements.invalid[1](inputElements.invalid[0]),\n max_words: inputElements.max_words[1](inputElements.max_words[0]),\n crossword_mode: inputElements.crossword_mode[1](\n inputElements.crossword_mode[0],\n ),\n lang: inputElements.lang[1](inputElements.lang[0]),\n };\n}\n\nfunction getHtmlOutputElements() {\n return {\n letterOutput: document.getElementById(\n \"letter-frequency-information\",\n ) as HTMLDivElement,\n wordOutput: document.getElementById(\"matching-words\") as HTMLDivElement,\n };\n}\n\nfunction getInvalidChars(state: State) {\n return ((state.crossword_mode\n ? \"\"\n : state.input.replace(wildCardRegex, \"\")) + state.invalid)\n .toLowerCase()\n .replace(whiteSpaceRegex, \"\")\n .replace(duplicateCharsRegex, \"\");\n}\n\nfunction getRegex(state: State) {\n const invalidChars = \"[^\" + getInvalidChars(state) + \"]\";\n const regexStr = state.input.replace(wildCardRegex, (s) => {\n return invalidChars + (s.length > 1 ? `{${s.length}}` : \"\");\n });\n return new RegExp(\"^\" + regexStr + \"$\", \"u\");\n}\n\nasync function loadWords(state: State): Promise {\n const wordLength = [...state.input].length;\n try {\n return await _loadWords(state.lang, wordLength);\n } catch (e) {\n console.error(\"error loading words\", e);\n return [];\n }\n}\n\nconst _wordsCache = new Map>();\nexport async function _loadWords(\n language: string,\n wordLength: number,\n): Promise {\n let languageCache = _wordsCache.get(language);\n if (languageCache) {\n const words = languageCache.get(wordLength);\n if (words) {\n return words;\n }\n } else {\n languageCache = new Map();\n _wordsCache.set(language, languageCache);\n }\n const response = await fetch(\n `/hangman-loeser/worte/${language.toLowerCase()}/${wordLength}.txt`,\n {\n method: \"GET\",\n headers: { Accept: \"text/plain\" },\n },\n );\n if (response.status !== 200 && response.status !== 404) {\n console.error(\"error loading words\", response);\n }\n const words = response.ok ? (await response.text()).split(\"\\n\") : [];\n languageCache.set(wordLength, words);\n return words;\n}\n\nfunction updateLettersMap(\n letters: Map,\n word: string,\n inputWithoutWildCards: string,\n crossword_mode: boolean,\n) {\n if (crossword_mode) {\n for (const char of inputWithoutWildCards) {\n letters.set(char, (letters.get(char) ?? 0) - 1);\n }\n for (const char of word) {\n letters.set(char, (letters.get(char) ?? 0) + 1);\n }\n return;\n }\n const used = [...inputWithoutWildCards];\n for (const char of word) {\n if (used.includes(char)) {\n continue;\n }\n letters.set(char, (letters.get(char) ?? 0) + 1);\n used.push(char);\n }\n}\n\nasync function solveHangman(\n state: State,\n): Promise<[string[], Map]> {\n const words = await loadWords(state);\n const invalidChars = state.invalid;\n\n const inputWithoutWildCards = state.input.replace(wildCardRegex, \"\");\n const matchesAlways = invalidChars.length === 0 &&\n inputWithoutWildCards.length === 0; // no letter input, only wildcards\n\n if (inputWithoutWildCards.length === state.input.length) { // max one word, without wildcard, just search for it\n const word = inputWithoutWildCards.toLowerCase();\n if (binarySearch(words, word)) { // if the word is present\n return [[word], new Map()];\n }\n return [[], new Map()];\n } else if (matchesAlways) {\n const letters = new Map();\n words.forEach((word) => {\n updateLettersMap(letters, word, \"\", state.crossword_mode);\n });\n return [words, letters];\n } else { // have to search\n const letters = new Map();\n const regex = getRegex(state);\n return [\n words.filter((word) => {\n if (regex.test(word)) {\n updateLettersMap(\n letters,\n word,\n inputWithoutWildCards,\n state.crossword_mode,\n );\n return true;\n }\n return false;\n }),\n letters,\n ];\n }\n}\n\nasync function onStateChange(state: State) {\n console.debug(\"state changed\", state);\n const [foundWords, letters] = await solveHangman(state);\n\n const outputs = getHtmlOutputElements();\n if (foundWords.length > 0) {\n outputs.wordOutput.innerHTML = `${\n Math.min(state.max_words, foundWords.length)\n }/${foundWords.length} passenden Wörter:`;\n const list = document.createElement(\"ul\");\n for (const word of foundWords.slice(0, state.max_words)) {\n const li = document.createElement(\"li\");\n li.innerText = word;\n list.appendChild(li);\n }\n outputs.wordOutput.appendChild(list);\n\n const lettersSorted: [string, number][] = [...letters.entries()].filter(\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n ([_, count]) => count > 0,\n );\n lettersSorted.sort((a, b) => b[1] - a[1]);\n outputs.letterOutput.innerText = \"Mögliche Buchstaben: \" + lettersSorted\n .map((value) => value.join(\": \"))\n .join(\", \");\n } else {\n outputs.letterOutput.innerText = \"Nichts gefunden.\";\n outputs.wordOutput.innerText = \"\";\n }\n}\n\nfunction binarySearch(arr: T[], toSearch: T): boolean {\n let start = 0;\n let end = arr.length - 1;\n // Iterate while start not meets end\n while (start <= end) {\n // Find the mid-index\n const mid = Math.floor((start + end) / 2);\n // If element is present at mid, return True\n if (arr[mid] === toSearch) {\n return true;\n } // Else look in left or right half accordingly\n else if (arr[mid]! < toSearch) {\n start = mid + 1;\n } else {\n end = mid - 1;\n }\n }\n return false;\n}\n\nconst stateType = \"HangmanSolverState\";\nfunction updateCurrentState(event: Event | undefined = undefined) {\n const newState = getState();\n setMultipleURLParams(\n Object.entries(newState).map(([key, value]) => [key, value.toString()]),\n newState,\n stateType,\n );\n event?.preventDefault();\n return onStateChange(newState);\n}\n\nfunction populateFormFromState(state: State) {\n const inputElements = getHtmlInputElements();\n inputElements.input[0].value = state.input;\n inputElements.crossword_mode[0].checked = state.crossword_mode;\n inputElements.invalid[0].value = state.invalid;\n inputElements.max_words[0].value = state.max_words.toString();\n inputElements.lang[0].value = state.lang;\n}\n\nfunction loadFromState(event: PopStateEvent) {\n const state = event.state as State;\n populateFormFromState(state);\n event.preventDefault();\n return onStateChange(state);\n}\n\nfunction addEventListeners() {\n PopStateHandlers[stateType] = loadFromState;\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n getForm().addEventListener(\"submit\", updateCurrentState);\n const inputElements = getHtmlInputElements();\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n inputElements.lang[0].addEventListener(\"change\", updateCurrentState);\n inputElements.crossword_mode[0].addEventListener(\n \"change\",\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n updateCurrentState,\n );\n}\n\naddEventListeners();\n"], - "mappings": "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", + "sourcesContent": ["// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0-or-later\n// stolen from: https://github.com/asozialesnetzwerk/Hangman-Solver/blob/ba693776f634e682553ac37a45157cd0ceeab6a9/js/index.js\n\nimport { PopStateHandlers, setMultipleURLParams } from \"@utils/utils.js\";\n\nconst wildCardChar = \"_\";\n// to replace \"_\" with regex\nconst wildCardRegex = /_+/g;\n// to replace ?, or # with _\nconst notRealWildCardRegex = /[#?]/g;\n// to remove whitespaces\nconst whiteSpaceRegex = /\\s+/g;\n// to remove duplicate chars:\nconst duplicateCharsRegex = /(.)(?=.*\\1)/g;\n\nfunction getForm() {\n return document.getElementById(\"hangman-solver-form\") as HTMLFormElement;\n}\n\ninterface StringValueObject {\n value: string;\n}\n\nconst _getLowerCaseValueWithoutWhitespace: (\n input: StringValueObject,\n) => string = (input) => input.value.toLowerCase().replace(whiteSpaceRegex, \"\");\n\nfunction getHtmlInputElements() {\n return {\n input: [\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n document.querySelector(\"input[name='input']\") as HTMLInputElement,\n (input: HTMLInputElement) =>\n _getLowerCaseValueWithoutWhitespace(input).replace(\n notRealWildCardRegex,\n wildCardChar,\n ),\n ],\n invalid: [\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n document.querySelector(\"input[name='invalid']\") as HTMLInputElement,\n (input: HTMLInputElement) => {\n // remove invalid chars and normalize\n const value: string = _getLowerCaseValueWithoutWhitespace(input)\n .replace(\n notRealWildCardRegex,\n \"\",\n )\n .replace(wildCardRegex, \"\");\n // remove duplicates\n const arr: string[] = [\n ...new Set(value),\n ];\n // sort\n arr.sort();\n return arr.join(\"\");\n },\n ],\n max_words: [\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n document.querySelector(\n \"input[name='max_words']\",\n ) as HTMLInputElement,\n (input: StringValueObject): number =>\n Number.parseInt(input.value, 10),\n ],\n crossword_mode: [\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n document.querySelector(\n \"input[name='crossword_mode']\",\n ) as HTMLInputElement,\n (input: { checked: boolean }): boolean => input.checked,\n ],\n lang: [\n // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style\n document.querySelector(\"select[name='lang']\") as HTMLSelectElement,\n _getLowerCaseValueWithoutWhitespace,\n ],\n } as const;\n}\ntype HtmlInputElements = ReturnType;\ntype State = {\n [TKey in keyof HtmlInputElements]: ReturnType;\n};\n\nfunction getState(): State {\n const inputElements: HtmlInputElements = getHtmlInputElements();\n return {\n input: inputElements.input[1](inputElements.input[0]),\n invalid: inputElements.invalid[1](inputElements.invalid[0]),\n max_words: inputElements.max_words[1](inputElements.max_words[0]),\n crossword_mode: inputElements.crossword_mode[1](\n inputElements.crossword_mode[0],\n ),\n lang: inputElements.lang[1](inputElements.lang[0]),\n };\n}\n\nfunction getHtmlOutputElements() {\n return {\n letterOutput: document.getElementById(\n \"letter-frequency-information\",\n ) as HTMLDivElement,\n wordOutput: document.getElementById(\"matching-words\") as HTMLDivElement,\n };\n}\n\nfunction getInvalidChars(state: State) {\n return ((state.crossword_mode\n ? \"\"\n : state.input.replace(wildCardRegex, \"\")) + state.invalid)\n .toLowerCase()\n .replace(whiteSpaceRegex, \"\")\n .replace(duplicateCharsRegex, \"\");\n}\n\nfunction getRegex(state: State) {\n const invalidChars = \"[^\" + getInvalidChars(state) + \"]\";\n const regexStr = state.input.replace(wildCardRegex, (s) => {\n return invalidChars + (s.length > 1 ? `{${s.length}}` : \"\");\n });\n return new RegExp(\"^\" + regexStr + \"$\", \"u\");\n}\n\nasync function loadWords(state: State): Promise {\n // eslint-disable-next-line @typescript-eslint/no-misused-spread\n const wordLength = [...state.input].length;\n try {\n return await _loadWords(state.lang, wordLength);\n } catch (e) {\n console.error(\"error loading words\", e);\n return [];\n }\n}\n\nconst _wordsCache = new Map>();\nexport async function _loadWords(\n language: string,\n wordLength: number,\n): Promise {\n let languageCache = _wordsCache.get(language);\n if (languageCache) {\n const words = languageCache.get(wordLength);\n if (words) {\n return words;\n }\n } else {\n languageCache = new Map();\n _wordsCache.set(language, languageCache);\n }\n const response = await fetch(\n `/hangman-loeser/worte/${language.toLowerCase()}/${wordLength}.txt`,\n {\n method: \"GET\",\n headers: { Accept: \"text/plain\" },\n },\n );\n if (response.status !== 200 && response.status !== 404) {\n console.error(\"error loading words\", response);\n }\n const words = response.ok ? (await response.text()).split(\"\\n\") : [];\n languageCache.set(wordLength, words);\n return words;\n}\n\nfunction updateLettersMap(\n letters: Map,\n word: string,\n inputWithoutWildCards: string,\n crossword_mode: boolean,\n) {\n if (crossword_mode) {\n for (const char of inputWithoutWildCards) {\n letters.set(char, (letters.get(char) ?? 0) - 1);\n }\n for (const char of word) {\n letters.set(char, (letters.get(char) ?? 0) + 1);\n }\n return;\n }\n // eslint-disable-next-line @typescript-eslint/no-misused-spread\n const used = [...inputWithoutWildCards];\n for (const char of word) {\n if (used.includes(char)) {\n continue;\n }\n letters.set(char, (letters.get(char) ?? 0) + 1);\n used.push(char);\n }\n}\n\nasync function solveHangman(\n state: State,\n): Promise<[string[], Map]> {\n const words = await loadWords(state);\n const invalidChars = state.invalid;\n\n const inputWithoutWildCards = state.input.replace(wildCardRegex, \"\");\n const matchesAlways = invalidChars.length === 0 &&\n inputWithoutWildCards.length === 0; // no letter input, only wildcards\n\n if (inputWithoutWildCards.length === state.input.length) { // max one word, without wildcard, just search for it\n const word = inputWithoutWildCards.toLowerCase();\n if (binarySearch(words, word)) { // if the word is present\n return [[word], new Map()];\n }\n return [[], new Map()];\n } else if (matchesAlways) {\n const letters = new Map();\n words.forEach((word) => {\n updateLettersMap(letters, word, \"\", state.crossword_mode);\n });\n return [words, letters];\n } else { // have to search\n const letters = new Map();\n const regex = getRegex(state);\n return [\n words.filter((word) => {\n if (regex.test(word)) {\n updateLettersMap(\n letters,\n word,\n inputWithoutWildCards,\n state.crossword_mode,\n );\n return true;\n }\n return false;\n }),\n letters,\n ];\n }\n}\n\nasync function onStateChange(state: State) {\n console.debug(\"state changed\", state);\n const [foundWords, letters] = await solveHangman(state);\n\n const outputs = getHtmlOutputElements();\n if (foundWords.length > 0) {\n outputs.wordOutput.innerHTML = `${\n Math.min(state.max_words, foundWords.length)\n }/${foundWords.length} passenden Wörter:`;\n const list = document.createElement(\"ul\");\n for (const word of foundWords.slice(0, state.max_words)) {\n const li = document.createElement(\"li\");\n li.innerText = word;\n list.appendChild(li);\n }\n outputs.wordOutput.appendChild(list);\n\n const lettersSorted: [string, number][] = [...letters.entries()].filter(\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n ([_, count]) => count > 0,\n );\n lettersSorted.sort((a, b) => b[1] - a[1]);\n outputs.letterOutput.innerText = \"Mögliche Buchstaben: \" + lettersSorted\n .map((value) => value.join(\": \"))\n .join(\", \");\n } else {\n outputs.letterOutput.innerText = \"Nichts gefunden.\";\n outputs.wordOutput.innerText = \"\";\n }\n}\n\nfunction binarySearch(arr: T[], toSearch: T): boolean {\n let start = 0;\n let end = arr.length - 1;\n // Iterate while start not meets end\n while (start <= end) {\n // Find the mid-index\n const mid = Math.floor((start + end) / 2);\n // If element is present at mid, return True\n if (arr[mid] === toSearch) {\n return true;\n } // Else look in left or right half accordingly\n else if (arr[mid]! < toSearch) {\n start = mid + 1;\n } else {\n end = mid - 1;\n }\n }\n return false;\n}\n\nconst stateType = \"HangmanSolverState\";\nfunction updateCurrentState(event: Event | undefined = undefined) {\n const newState = getState();\n setMultipleURLParams(\n Object.entries(newState).map(([key, value]) => [key, value.toString()]),\n newState,\n stateType,\n );\n event?.preventDefault();\n return onStateChange(newState);\n}\n\nfunction populateFormFromState(state: State) {\n const inputElements = getHtmlInputElements();\n inputElements.input[0].value = state.input;\n inputElements.crossword_mode[0].checked = state.crossword_mode;\n inputElements.invalid[0].value = state.invalid;\n inputElements.max_words[0].value = state.max_words.toString();\n inputElements.lang[0].value = state.lang;\n}\n\nfunction loadFromState(event: PopStateEvent) {\n const state = event.state as State;\n populateFormFromState(state);\n event.preventDefault();\n return onStateChange(state);\n}\n\nfunction addEventListeners() {\n PopStateHandlers[stateType] = loadFromState;\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n getForm().addEventListener(\"submit\", updateCurrentState);\n const inputElements = getHtmlInputElements();\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n inputElements.lang[0].addEventListener(\"change\", updateCurrentState);\n inputElements.crossword_mode[0].addEventListener(\n \"change\",\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n updateCurrentState,\n );\n}\n\naddEventListeners();\n"], + "mappings": "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", "names": ["PopStateHandlers", "setMultipleURLParams", "wildCardChar", "wildCardRegex", "notRealWildCardRegex", "whiteSpaceRegex", "duplicateCharsRegex", "getForm", "_getLowerCaseValueWithoutWhitespace", "input", "getHtmlInputElements", "value", "arr", "getState", "inputElements", "getHtmlOutputElements", "getInvalidChars", "state", "getRegex", "invalidChars", "regexStr", "s", "loadWords", "wordLength", "_loadWords", "e", "_wordsCache", "language", "languageCache", "words", "response", "updateLettersMap", "letters", "word", "inputWithoutWildCards", "crossword_mode", "_a", "_b", "_c", "char", "used", "solveHangman", "matchesAlways", "binarySearch", "regex", "onStateChange", "foundWords", "outputs", "list", "li", "lettersSorted", "_", "count", "b", "toSearch", "start", "end", "mid", "stateType", "updateCurrentState", "event", "newState", "key", "populateFormFromState", "loadFromState", "addEventListeners"] }