diff --git a/CHANGELOG.md b/CHANGELOG.md
index 96fa5d9..2581e32 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
# CHANGELOG
+## v1.0.3
+
+- Removed the option `table formating` because it will now set to true by default
+- Adjusted the abort timeout to 15seconds
+- If an error occur the user can now click back on the question
+- `Textbox, question to answser mode and clipboard mode` is not formatted anymore
+- Fixed many bugs
+- Write AI system instructions
+
## v1.0.2
- Added `mode`
diff --git a/README.md b/README.md
index 5caa984..8426a5f 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
href="https://www.flaticon.com/free-icons/mortarboard" target="_blank" rel="noopener noreferrer"
title="Mortarboard icons created by itim2101 - Flaticon" >
-# MoodleGPT v1.0.2
+# MoodleGPT v1.0.3
This extension allows you to hide CHAT-GPT in a Moodle quiz. You just need to enter the code configured in the extension on the keyboard and then click on the question you want to solve, and CHAT-GPT will automatically provide the answer. However, one needs to be careful because as we know, CHAT-GPT can make errors especially in calculations.
@@ -12,11 +12,11 @@ I'm actually waiting for a review of my extension. It should be available in som
## Summary
-- [MoodleGPT v1.0.2](#moodlegpt-v102)
+- [MoodleGPT v1.0.3](#moodlegpt-v103)
- [Chrome Webstore](#chrome-webstore)
- [Summary](#summary)
- [Disclaimer !](#disclaimer-)
- - [Donation](#donation)
+ - [Donate](#donate)
- [Update](#update)
- [MoodleGPT don't complete my quiz ?](#moodlegpt-dont-complete-my-quiz-)
- [Set up](#set-up)
@@ -24,6 +24,8 @@ I'm actually waiting for a review of my extension. It should be available in som
- [Remove injection](#remove-injection)
- [Mode](#mode)
- [Settings](#settings)
+ - [Internal Features](#internal-features)
+ - [Support table](#support-table)
- [Supported questions type](#supported-questions-type)
- [Select](#select)
- [Put in order question](#put-in-order-question)
@@ -40,9 +42,11 @@ I'm actually waiting for a review of my extension. It should be available in som
I hereby declare that I am not responsible for any misuse or illegal activities carried out using my program. The code is provided for educational and research purposes only, and any use of it outside of these purposes is at the user's own risk.
-## Donation
+## Donate
-Will be a pleasure if you want to support this project :) -> Just right [here](https://www.buymeacoffee.com/yoannchbpro)
+Will be a pleasure if you want to support this project :)
+
+
## Update
@@ -64,7 +68,7 @@ Go to "Manage my extensions" on your browser, then click on "Load unpa
## Inject the code into the moodle
-You just need to enter on the keyboard the code you have set into the extension and clique on the question you want to solve.
+You just need to enter on the keyboard the code you have set into the extension and click on the question you want to solve.
## Remove injection
@@ -95,13 +99,20 @@ Type back the code on the keyboard and the code will be removed from the

- Console logs: show logs into the console.
-- Request timeout: if the request is too long it will be abort after 10seconds.
+- Request timeout: if the request is too long it will be abort after 15seconds.
- Typing effect: create a typing effect for text. Type any text and it will be replaced by the correct one. If you want to stop it press Backspace key.

- Mouseover effect: you will need to hover (or click for select) the question response to complete it automaticaly.


-- Table formatting: format table from the question to make it more readable for CHAT-GPT but cost more tokens (so if the question is too large it will make an error). Example of formatted table:
+
+- Infinite try: click as much as you want on the question (don't forget to reset the question).
+
+## Internal Features
+
+### Support table
+
+Table are formated from the question to make it more readable for CHAT-GPT. Example of formatted table output:
```
| id | name | birthDate | cars |
@@ -110,8 +121,6 @@ Type back the code on the keyboard and the code will be removed from the
| Person 2 | Yann | 19/01/2000 | no |
```
-- Infinite try: click as much as you want on the question (don't forget to reset the question).
-
## Supported questions type
### Select
@@ -154,4 +163,4 @@ To know if the answer has been copied to the clipboard, you can look at the titl
## Test
-To test the code, you can run the index.html file located in the "test" folder. Or a better solution is to install moodle locally.
+To test the code, you can run the index.html file located in the "test/fake-moodle" folder. Or a better solution is to install moodle locally.
diff --git a/TODO.md b/TODO.md
index 73467d0..0ba115e 100644
--- a/TODO.md
+++ b/TODO.md
@@ -2,11 +2,15 @@
## Priority: 1
-- [ ] Fixe `normalizeText` (line break are sometimes removed for nothing e.g: checkbox)
-- [ ] Support math equation from image stocked in the `data-mathml` attribute
+- [ ] Fixe put in order
+- [ ] Make some tests
+
+## Priority: 2
## Priority: 3 (because hard to make)
+- [ ] Increment question when there is statement (hard because it is often on another page)
+- [ ] Support math equation from image stocked in the `data-mathml` attribute
- [ ] Try something to understand images like (image -> ascii or may be using other AI ?)
- [ ] Support multiple input type in a question
- [ ] Support drag and drop quiz
diff --git a/assets/bmc-button.png b/assets/bmc-button.png
new file mode 100644
index 0000000..464bfd9
Binary files /dev/null and b/assets/bmc-button.png differ
diff --git a/assets/mode.png b/assets/mode.png
index 383c76e..7405021 100644
Binary files a/assets/mode.png and b/assets/mode.png differ
diff --git a/assets/popup.png b/assets/popup.png
index 05517f4..673dcab 100644
Binary files a/assets/popup.png and b/assets/popup.png differ
diff --git a/assets/settings.png b/assets/settings.png
index 2ad2976..d85e836 100644
Binary files a/assets/settings.png and b/assets/settings.png differ
diff --git a/extension/128x128.png b/extension/128x128.png
deleted file mode 100644
index 3667307..0000000
Binary files a/extension/128x128.png and /dev/null differ
diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js
index f8f8b99..a44c165 100644
--- a/extension/MoodleGPT.js
+++ b/extension/MoodleGPT.js
@@ -1,477 +1,2 @@
-(function (factory) {
- typeof define === 'function' && define.amd ? define(factory) :
- factory();
-})((function () { 'use strict';
-
- /**
- * Show some informations into the document title and remove it after 3000ms
- * @param text
- */
- function titleIndications(text) {
- const backTitle = document.title;
- document.title = text;
- setTimeout(() => (document.title = backTitle), 3000);
- }
-
- /******************************************************************************
- Copyright (c) Microsoft Corporation.
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
- ***************************************************************************** */
-
- function __awaiter(thisArg, _arguments, P, generator) {
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
- return new (P || (P = Promise))(function (resolve, reject) {
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
- }
-
- class Logs {
- static question(text) {
- const css = "color: cyan";
- console.log("%c[QUESTION]: %s", css, text);
- }
- static responseTry(text, valide) {
- const css = "color: " + (valide ? "green" : "red");
- console.log("%c[CHECKING]: %s", css, text);
- }
- static array(arr) {
- console.log("[CORRECTS] ", arr);
- }
- static response(text) {
- console.log(text);
- }
- }
-
- /**
- * Normlize text
- * @param text
- */
- function normalizeText(text) {
- return text
- .replace(/(\n\s*)+/gi, "\n")
- .replace(/[ \t]+/gi, " ")
- .toLowerCase()
- .trim()
- .replace(/^[a-z\d]\.\s/gi, "") //a. text, b. text, c. text, 1. text, 2. text, 3.text
- .replace(/\n[a-z\d]\.\s/gi, "\n"); //same but with new line
- }
-
- /**
- * Get the response from chatGPT api
- * @param config
- * @param question
- * @returns
- */
- function getChatGPTResponse(config, question) {
- return __awaiter(this, void 0, void 0, function* () {
- const controller = new AbortController();
- const timeoutControler = setTimeout(() => controller.abort(), 10000);
- const req = yield fetch("https://api.openai.com/v1/chat/completions", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- Authorization: `Bearer ${config.apiKey}`,
- },
- signal: config.timeout ? controller.signal : null,
- body: JSON.stringify({
- model: config.model,
- messages: [{ role: "user", content: question }],
- temperature: 0.8,
- top_p: 1.0,
- presence_penalty: 1.0,
- stop: null,
- }),
- });
- clearTimeout(timeoutControler);
- const rep = yield req.json();
- const response = rep.choices[0].message.content;
- return normalizeText(response);
- });
- }
-
- /**
- * Convert table to representating string table
- * @param table
- * @returns
- */
- function htmlTableToString(table) {
- const tab = [];
- const lines = Array.from(table.querySelectorAll("tr"));
- const maxColumnsLength = [];
- lines.map((line) => {
- const cells = Array.from(line.querySelectorAll("td, th"));
- const cellsContent = cells.map((cell, index) => {
- var _a;
- const content = (_a = cell.textContent) === null || _a === void 0 ? void 0 : _a.trim();
- maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content.length || 0);
- return content;
- });
- tab.push(cellsContent);
- });
- const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;
- const lineSeparation = "\n" + Array(lineSeparationSize).fill("-").join("") + "\n";
- const mappedTab = tab.map((line) => {
- const mappedLine = line.map((content, index) => content.padEnd(maxColumnsLength[index], "\u00A0") //for no matching with \s
- );
- return "| " + mappedLine.join(" | ") + " |";
- });
- const head = mappedTab.shift();
- return head + lineSeparation + mappedTab.join("\n");
- }
-
- /**
- * Normalize the question and add sub informations
- * @param langage
- * @param question
- * @returns
- */
- function normalizeQuestion(config, questionContainer) {
- let question = questionContainer.textContent;
- if (config.table) {
- //make table more readable for chat-gpt
- const tables = questionContainer.querySelectorAll(".qtext table");
- for (const table of tables) {
- question = question.replace(table.textContent, "\n" + htmlTableToString(table) + "\n");
- }
- }
- const finalQuestion = `Give a short response as possible for this question, reply in the following question langage and only show the result:
- ${question}
- (If you have to choose between multiple results only show the corrects one, separate them with new line and take the same text as the question)`;
- return normalizeText(finalQuestion);
- }
-
- /**
- * Handle checkbox and input elements
- * @param config
- * @param inputList
- * @param response
- */
- function handleRadioAndCheckbox(config, inputList, response) {
- const input = inputList === null || inputList === void 0 ? void 0 : inputList[0];
- if (!input || (input.type !== "checkbox" && input.type !== "radio"))
- return false;
- for (const input of inputList) {
- const content = normalizeText(input.parentNode.textContent);
- const valide = response.includes(content);
- if (config.logs)
- Logs.responseTry(content, valide);
- if (valide) {
- if (config.mouseover) {
- input.addEventListener("mouseover", () => (input.checked = true), {
- once: true,
- });
- }
- else {
- input.checked = true;
- }
- }
- }
- return true;
- }
-
- /**
- * Handle select elements (and put in order select)
- * @param config
- * @param inputList
- * @param response
- * @returns
- */
- function handleSelect(config, inputList, response) {
- if (inputList.length === 0 || inputList[0].tagName !== "SELECT")
- return false;
- let correct = response.split("\n");
- if (correct.length === 1 && correct.length !== inputList.length)
- correct = response.split(",");
- if (config.logs)
- Logs.array(correct);
- for (let j = 0; j < inputList.length; ++j) {
- const options = inputList[j].querySelectorAll("option");
- for (const option of options) {
- const content = normalizeText(option.textContent);
- const valide = correct[j].includes(content);
- //if it's a put in order
- if (!isNaN(parseInt(content))) {
- const content = normalizeText(option.parentNode
- .closest("tr")
- .querySelector(".text").textContent);
- const index = correct.findIndex((c) => {
- const valide = c.includes(content);
- if (config.logs)
- Logs.responseTry(content, valide);
- return valide;
- });
- if (index !== -1) {
- if (config.mouseover) {
- options[index + 1].closest("select").addEventListener("click", function () {
- options[index + 1].selected = "selected";
- }, { once: true });
- }
- else {
- options[index + 1].selected = "selected";
- }
- break;
- }
- }
- //end put in order
- if (config.logs)
- Logs.responseTry(content, valide);
- if (valide) {
- if (config.mouseover) {
- option
- .closest("select")
- .addEventListener("click", () => (option.selected = true), {
- once: true,
- });
- }
- else {
- option.selected = true;
- }
- break;
- }
- }
- }
- return true;
- }
-
- /**
- * Handle textbox
- * @param config
- * @param inputList
- * @param response
- * @returns
- */
- function handleTextbox(config, inputList, response) {
- const input = inputList[0];
- if (inputList.length !== 1 ||
- (input.tagName !== "TEXTAREA" && input.type !== "text"))
- return false;
- if (config.typing) {
- let index = 0;
- input.addEventListener("keydown", function (event) {
- if (event.key === "Backspace")
- index = response.length + 1;
- if (index > response.length)
- return;
- event.preventDefault();
- input.value = response.slice(0, ++index);
- });
- }
- else {
- input.value = response;
- }
- return true;
- }
-
- /**
- * Copy the response in the clipboard if we can automaticaly fill the question
- * @param config
- * @param inputList
- * @param response
- * @param force Force the copy to clipboard
- * @returns
- */
- function handleClipboard(config, response) {
- if (config.title)
- titleIndications("Copied to clipboard");
- navigator.clipboard.writeText(response);
- }
-
- /**
- * Handle number input
- * @param config
- * @param inputList
- * @param response
- * @returns
- */
- function handleNumber(config, inputList, response) {
- var _a, _b;
- const input = inputList[0];
- if (inputList.length !== 1 || input.type !== "number")
- return false;
- const number = (_b = (_a = response.match(/\d+([,\.]\d+)?/gi)) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.replace(",", ".");
- if (!number)
- return false;
- if (config.typing) {
- let index = 0;
- input.addEventListener("keydown", function (event) {
- if (event.key === "Backspace")
- index = number.length + 1;
- if (index > number.length)
- return;
- event.preventDefault();
- if (number.slice(index, index + 1) === ".")
- ++index;
- input.value = number.slice(0, ++index);
- });
- }
- else {
- input.value = number;
- }
- return true;
- }
-
- function handleContentEditable(config, inputList, response) {
- const input = inputList[0];
- if (inputList.length !== 1 ||
- input.getAttribute("contenteditable") !== "true")
- return false;
- if (config.typing) {
- let index = 0;
- input.addEventListener("keydown", function (event) {
- if (event.key === "Backspace")
- index = response.length + 1;
- if (index > response.length)
- return;
- event.preventDefault();
- input.textContent = response.slice(0, ++index);
- //put the cursor at the end
- input.focus();
- const range = document.createRange();
- range.selectNodeContents(input);
- range.collapse(false);
- const selection = window.getSelection();
- selection.removeAllRanges();
- selection.addRange(range);
- });
- }
- else {
- input.textContent = response;
- }
- return true;
- }
-
- /**
- * Reply to the question
- * @param config
- * @param hiddenButton
- * @param form
- * @param query
- * @returns
- */
- function reply(config, hiddenButton, form, query) {
- var _a;
- return __awaiter(this, void 0, void 0, function* () {
- if (config.cursor)
- hiddenButton.style.cursor = "wait";
- (_a = form.querySelector(".accesshide")) === null || _a === void 0 ? void 0 : _a.remove();
- const question = normalizeQuestion(config, form);
- const inputList = form.querySelectorAll(query);
- const response = yield getChatGPTResponse(config, question).catch((error) => ({
- error,
- }));
- if (config.cursor)
- hiddenButton.style.cursor = config.infinite ? "pointer" : "initial";
- if (typeof response === "object" && "error" in response) {
- console.error(response.error);
- return;
- }
- if (config.logs) {
- Logs.question(question);
- Logs.response(response);
- }
- if (config.mode === "clipboard") {
- return handleClipboard(config, response);
- }
- if (config.mode === "question-to-answer") {
- const questionBackup = form.textContent;
- const questionContainer = form.querySelector(".qtext");
- questionContainer.textContent = response;
- questionContainer.addEventListener("click", function () {
- questionContainer.textContent =
- questionContainer.textContent === questionBackup
- ? response
- : questionBackup;
- });
- return;
- }
- const handlers = [
- handleContentEditable,
- handleTextbox,
- handleNumber,
- handleSelect,
- handleRadioAndCheckbox,
- ];
- for (const handler of handlers) {
- if (handler(config, inputList, response))
- return;
- }
- /** In the case we can't auto complete the question */
- handleClipboard(config, response);
- });
- }
-
- const pressedKeys = [];
- const listeners = [];
- /**
- * Create a listener on the keyboard to inject the code
- * @param config
- */
- function codeListener(config) {
- document.body.addEventListener("keydown", function (event) {
- pressedKeys.push(event.key);
- if (pressedKeys.length > config.code.length)
- pressedKeys.shift();
- if (pressedKeys.join("") === config.code) {
- pressedKeys.length = 0;
- setUpMoodleGpt(config);
- }
- });
- }
- /**
- * Setup moodleGPT into the page (remove/injection)
- * @param config
- * @returns
- */
- function setUpMoodleGpt(config) {
- //removing events
- if (listeners.length > 0) {
- for (const listener of listeners) {
- if (config.cursor)
- listener.element.style.cursor = "initial";
- listener.element.removeEventListener("click", listener.fn);
- }
- if (config.title)
- titleIndications("Removed");
- listeners.length = 0;
- return;
- }
- //injection
- const inputQuery = ["checkbox", "radio", "text", "number"]
- .map((e) => `input[type="${e}"]`)
- .join(",");
- const query = inputQuery + ", textarea, select, [contenteditable]";
- const forms = Array.from(document.querySelectorAll(".formulation"));
- for (const form of forms) {
- const hiddenButton = form.querySelector(".qtext");
- if (config.cursor)
- hiddenButton.style.cursor = "pointer";
- const fn = reply.bind(null, config, hiddenButton, form, query);
- listeners.push({ element: hiddenButton, fn });
- hiddenButton.addEventListener("click", fn, { once: !config.infinite });
- }
- if (config.title)
- titleIndications("Injected");
- }
-
- chrome.storage.sync.get(["moodleGPT"]).then(function (storage) {
- const config = storage.moodleGPT;
- if (!config)
- throw new Error("Please configure MoodleGPT into the extension");
- codeListener(config);
- });
-
-}));
+!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const t=document.title;document.title=e,setTimeout((()=>document.title=t),3e3)}function t(e,t,n,o){return new(n||(n=Promise))((function(r,s){function i(e){try{c(o.next(e))}catch(e){s(e)}}function l(e){try{c(o.throw(e))}catch(e){s(e)}}function c(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,l)}c((o=o.apply(e,t||[])).next())}))}class n{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static responseTry(e,t){const n="color: "+(t?"green":"red");console.log("%c[CHECKING]: %s",n,e)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function o(e,t=!0){let n=e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ");return t&&(n=n.toLowerCase()),n.trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}function r(e){const t=[],n=Array.from(e.querySelectorAll("tr")),o=[];n.map((e=>{const n=Array.from(e.querySelectorAll("td, th")).map(((e,t)=>{var n;const r=null===(n=e.textContent)||void 0===n?void 0:n.trim();return o[t]=Math.max(o[t]||0,r.length||0),r}));t.push(n)}));const r=o.reduce(((e,t)=>e+t))+3*t[0].length+1,s="\n"+Array(r).fill("-").join("")+"\n",i=t.map((e=>"| "+e.map(((e,t)=>e.padEnd(o[t]," "))).join(" | ")+" |"));return i.shift()+s+i.join("\n")}function s(e,t,r){const s=null==t?void 0:t[0];if(!s||"checkbox"!==s.type&&"radio"!==s.type)return!1;for(const s of t){const t=o(s.parentNode.textContent),i=r.normalizedResponse.includes(t);e.logs&&n.responseTry(t,i),i&&(e.mouseover?s.addEventListener("mouseover",(()=>s.checked=!0),{once:!0}):s.checked=!0)}return!0}function i(e,t,r){if(0===t.length||"SELECT"!==t[0].tagName)return!1;let s=r.normalizedResponse.split("\n");e.logs&&n.array(s),s.length===2*t.length&&(s=s.filter(((e,t)=>t%2==1)));for(let r=0;r{const o=t.includes(r);return e.logs&&n.responseTry(r,o),o}));if(-1!==l){e.mouseover?i[l+1].closest("select").addEventListener("click",(function(){i[l+1].selected="selected"}),{once:!0}):i[l+1].selected="selected";break}}if(e.logs&&n.responseTry(l,c),c){e.mouseover?t.closest("select").addEventListener("click",(()=>t.selected=!0),{once:!0}):t.selected=!0;break}}}return!0}function l(e,t,n){const o=t[0];if(1!==t.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(t){"Backspace"===t.key&&(e=n.response.length+1),e>n.response.length||(t.preventDefault(),o.value=n.response.slice(0,++e))}))}else o.value=n.response;return!0}function c(t,n){t.title&&e("Copied to clipboard"),navigator.clipboard.writeText(n.response)}function a(e,t,n){var o,r;const s=t[0];if(1!==t.length||"number"!==s.type)return!1;const i=null===(r=null===(o=n.normalizedResponse.match(/\d+([,\.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(!i)return!1;if(e.typing){let e=0;s.addEventListener("keydown",(function(t){"Backspace"===t.key&&(e=i.length+1),e>i.length||(t.preventDefault(),"."===i.slice(e,e+1)&&++e,s.value=i.slice(0,++e))}))}else s.value=i;return!0}function u(e,t,n){const o=t[0];if(1!==t.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(t){if("Backspace"===t.key&&(e=n.response.length+1),e>n.response.length)return;t.preventDefault(),o.textContent=n.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const s=window.getSelection();s.removeAllRanges(),s.addRange(r)}))}else o.textContent=n.response;return!0}function d(e,d,f,p){return t(this,void 0,void 0,(function*(){e.cursor&&(d.style.cursor="wait");const h=function(e,t){let n=t.innerText;const s=t.querySelectorAll(".accesshide");for(const e of s)n=n.replace(e.innerText,"");const i=t.querySelectorAll(".qtext table");for(const e of i)n=n.replace(e.innerText,"\n"+r(e)+"\n");return o(n,!1)}(0,f),g=f.querySelectorAll(p),y=yield function(e,n){return t(this,void 0,void 0,(function*(){const t=new AbortController,r=setTimeout((()=>t.abort()),15e3),s=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?t.signal:null,body:JSON.stringify({model:e.model,messages:[{role:"system",content:"\nFollow those rules:\n- Sometimes there won't be a question, so just answer the statement as you normally would without following the other rules and give the most detailled and complete answer with explication.\n- For put in order question just give the good order separate by new line\n- Your goal is to understand the statement and to reply to each question by giving only the answer.\n- You will keep the same order for the answers like in the text. \n- You will separate all the answer with new lines and only show the correctes one.\n- You will only give the answers for each question and omit the questions, statement, title or other informations from the response.\n- You will only give answer with exactly the same text as the gived answers.\n- The question always have the good answer so you should always give an answer to the question.\n- You will always respond in the same langage as the user question."},{role:"user",content:n}],temperature:.8,top_p:1,presence_penalty:1,stop:null})});clearTimeout(r);const i=(yield s.json()).choices[0].message.content;return{response:i,normalizedResponse:o(i)}}))}(e,h).catch((e=>({error:e}))),v="object"==typeof y&&"error"in y;if(e.cursor&&(d.style.cursor=e.infinite||v?"pointer":"initial"),v)return void console.error(y.error);if(e.logs&&(n.question(h),n.response(y)),"clipboard"===e.mode)return e.infinite||m(d),c(e,y);if("question-to-answer"===e.mode){m(d);const e=f.querySelector(".qtext"),t=e.textContent;return e.textContent=y.response,e.style.whiteSpace="pre-wrap",void e.addEventListener("click",(function(){const n=e.textContent===t;e.style.whiteSpace=n?"pre-wrap":null,e.textContent=n?y.response:t}))}e.infinite||m(d);const w=[u,l,a,i,s];for(const t of w)if(t(e,g,y))return;c(e,y)}))}const f=[],p=[];function h(t){document.body.addEventListener("keydown",(function(n){f.push(n.key),f.length>t.code.length&&f.shift(),f.join("")===t.code&&(f.length=0,function(t){if(p.length>0){for(const e of p)t.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return t.title&&e("Removed"),void(p.length=0)}const n=["checkbox","radio","text","number"].map((e=>`input[type="${e}"]`)).join(",")+", textarea, select, [contenteditable]",o=document.querySelectorAll(".formulation");for(const e of o){const o=e.querySelector(".qtext");t.cursor&&(o.style.cursor="pointer");const r=d.bind(null,t,o,e,n);p.push({element:o,fn:r}),o.addEventListener("click",r)}t.title&&e("Injected")}(t))}))}function m(e){const t=p.findIndex((t=>t.element===e));if(-1!==t){const e=p.splice(t,1)[0];e.element.removeEventListener("click",e.fn)}}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const t=e.moodleGPT;if(!t)throw new Error("Please configure MoodleGPT into the extension");h(t)}))}));
//# sourceMappingURL=MoodleGPT.js.map
diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map
index 6ee6e3a..e43d28b 100644
--- a/extension/MoodleGPT.js.map
+++ b/extension/MoodleGPT.js.map
@@ -1 +1 @@
-{"version":3,"file":"MoodleGPT.js","sources":["../src/utils/title-indications.ts","../node_modules/tslib/tslib.es6.js","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/core/get-response.ts","../src/utils/html-table-to-string.ts","../src/core/normalize-question.ts","../src/core/questions/radio-checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/questions/clipboard.ts","../src/core/questions/number.ts","../src/core/questions/contenteditable.ts","../src/core/reply.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\r\n * Show some informations into the document title and remove it after 3000ms\r\n * @param text\r\n */\r\nfunction titleIndications(text: string) {\r\n const backTitle = document.title;\r\n document.title = text;\r\n setTimeout(() => (document.title = backTitle), 3000);\r\n}\r\n\r\nexport default titleIndications;\r\n","/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\r\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\r\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\r\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\r\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\r\n var _, done = false;\r\n for (var i = decorators.length - 1; i >= 0; i--) {\r\n var context = {};\r\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\r\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\r\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\r\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\r\n if (kind === \"accessor\") {\r\n if (result === void 0) continue;\r\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\r\n if (_ = accept(result.get)) descriptor.get = _;\r\n if (_ = accept(result.set)) descriptor.set = _;\r\n if (_ = accept(result.init)) initializers.push(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.push(_);\r\n else descriptor[key] = _;\r\n }\r\n }\r\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\r\n done = true;\r\n};\r\n\r\nexport function __runInitializers(thisArg, initializers, value) {\r\n var useValue = arguments.length > 2;\r\n for (var i = 0; i < initializers.length; i++) {\r\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\r\n }\r\n return useValue ? value : void 0;\r\n};\r\n\r\nexport function __propKey(x) {\r\n return typeof x === \"symbol\" ? x : \"\".concat(x);\r\n};\r\n\r\nexport function __setFunctionName(f, name, prefix) {\r\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\r\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\r\n};\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n\r\nexport function __classPrivateFieldIn(state, receiver) {\r\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\r\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\r\n}\r\n","class Logs {\r\n static question(text: string) {\r\n const css = \"color: cyan\";\r\n console.log(\"%c[QUESTION]: %s\", css, text);\r\n }\r\n\r\n static responseTry(text: string, valide: boolean) {\r\n const css = \"color: \" + (valide ? \"green\" : \"red\");\r\n console.log(\"%c[CHECKING]: %s\", css, text);\r\n }\r\n\r\n static array(arr: unknown[]) {\r\n console.log(\"[CORRECTS] \", arr);\r\n }\r\n\r\n static response(text: string) {\r\n console.log(text);\r\n }\r\n}\r\n\r\nexport default Logs;\r\n","/**\r\n * Normlize text\r\n * @param text\r\n */\r\nfunction normalizeText(text: string) {\r\n return text\r\n .replace(/(\\n\\s*)+/gi, \"\\n\")\r\n .replace(/[ \\t]+/gi, \" \")\r\n .toLowerCase()\r\n .trim()\r\n .replace(/^[a-z\\d]\\.\\s/gi, \"\") //a. text, b. text, c. text, 1. text, 2. text, 3.text\r\n .replace(/\\n[a-z\\d]\\.\\s/gi, \"\\n\"); //same but with new line\r\n}\r\n\r\nexport default normalizeText;\r\n","import Config from \"../types/config\";\r\nimport normalizeText from \"../utils/normalize-text\";\r\n\r\n/**\r\n * Get the response from chatGPT api\r\n * @param config\r\n * @param question\r\n * @returns\r\n */\r\nasync function getChatGPTResponse(\r\n config: Config,\r\n question: string\r\n): Promise {\r\n const controller = new AbortController();\r\n const timeoutControler = setTimeout(() => controller.abort(), 10000);\r\n const req = await fetch(\"https://api.openai.com/v1/chat/completions\", {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n Authorization: `Bearer ${config.apiKey}`,\r\n },\r\n signal: config.timeout ? controller.signal : null,\r\n body: JSON.stringify({\r\n model: config.model,\r\n messages: [{ role: \"user\", content: question }],\r\n temperature: 0.8,\r\n top_p: 1.0,\r\n presence_penalty: 1.0,\r\n stop: null,\r\n }),\r\n });\r\n clearTimeout(timeoutControler);\r\n const rep = await req.json();\r\n const response = rep.choices[0].message.content;\r\n return normalizeText(response);\r\n}\r\n\r\nexport default getChatGPTResponse;\r\n","/**\r\n * Convert table to representating string table\r\n * @param table\r\n * @returns\r\n */\r\nfunction htmlTableToString(table: HTMLTableElement) {\r\n const tab: string[][] = [];\r\n const lines = Array.from(table.querySelectorAll(\"tr\"));\r\n const maxColumnsLength: number[] = [];\r\n lines.map((line) => {\r\n const cells = Array.from(line.querySelectorAll(\"td, th\"));\r\n const cellsContent = cells.map((cell, index) => {\r\n const content = cell.textContent?.trim();\r\n maxColumnsLength[index] = Math.max(\r\n maxColumnsLength[index] || 0,\r\n content.length || 0\r\n );\r\n return content;\r\n });\r\n tab.push(cellsContent);\r\n });\r\n\r\n const lineSeparationSize =\r\n maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\r\n const lineSeparation =\r\n \"\\n\" + Array(lineSeparationSize).fill(\"-\").join(\"\") + \"\\n\";\r\n\r\n const mappedTab = tab.map((line) => {\r\n const mappedLine = line.map(\r\n (content, index) => content.padEnd(maxColumnsLength[index], \"\\u00A0\") //for no matching with \\s\r\n );\r\n return \"| \" + mappedLine.join(\" | \") + \" |\";\r\n });\r\n const head = mappedTab.shift();\r\n return head + lineSeparation + mappedTab.join(\"\\n\");\r\n}\r\n\r\nexport default htmlTableToString;\r\n","import Config from \"../types/config\";\r\nimport normalizeText from \"../utils/normalize-text\";\r\nimport htmlTableToString from \"../utils/html-table-to-string\";\r\n\r\n/**\r\n * Normalize the question and add sub informations\r\n * @param langage\r\n * @param question\r\n * @returns\r\n */\r\nfunction normalizeQuestion(config: Config, questionContainer: HTMLElement) {\r\n let question = questionContainer.textContent;\r\n\r\n if (config.table) {\r\n //make table more readable for chat-gpt\r\n const tables: NodeListOf =\r\n questionContainer.querySelectorAll(\".qtext table\");\r\n for (const table of tables) {\r\n question = question.replace(\r\n table.textContent,\r\n \"\\n\" + htmlTableToString(table) + \"\\n\"\r\n );\r\n }\r\n }\r\n\r\n const finalQuestion = `Give a short response as possible for this question, reply in the following question langage and only show the result: \r\n ${question} \r\n (If you have to choose between multiple results only show the corrects one, separate them with new line and take the same text as the question)`;\r\n return normalizeText(finalQuestion);\r\n}\r\n\r\nexport default normalizeQuestion;\r\n","import Config from \"../../types/config\";\r\nimport Logs from \"../../utils/logs\";\r\nimport normalizeText from \"../../utils/normalize-text\";\r\n\r\n/**\r\n * Handle checkbox and input elements\r\n * @param config\r\n * @param inputList\r\n * @param response\r\n */\r\nfunction handleRadioAndCheckbox(\r\n config: Config,\r\n inputList: NodeListOf,\r\n response: string\r\n): boolean {\r\n const input = inputList?.[0] as HTMLInputElement;\r\n\r\n if (!input || (input.type !== \"checkbox\" && input.type !== \"radio\"))\r\n return false;\r\n\r\n for (const input of inputList as NodeListOf) {\r\n const content = normalizeText(input.parentNode.textContent);\r\n const valide = response.includes(content);\r\n if (config.logs) Logs.responseTry(content, valide);\r\n if (valide) {\r\n if (config.mouseover) {\r\n input.addEventListener(\"mouseover\", () => (input.checked = true), {\r\n once: true,\r\n });\r\n } else {\r\n input.checked = true;\r\n }\r\n }\r\n }\r\n return true;\r\n}\r\n\r\nexport default handleRadioAndCheckbox;\r\n","import Config from \"../../types/config\";\r\nimport Logs from \"../../utils/logs\";\r\nimport normalizeText from \"../../utils/normalize-text\";\r\n\r\n/**\r\n * Handle select elements (and put in order select)\r\n * @param config\r\n * @param inputList\r\n * @param response\r\n * @returns\r\n */\r\nfunction handleSelect(\r\n config: Config,\r\n inputList: NodeListOf,\r\n response: string\r\n): boolean {\r\n if (inputList.length === 0 || inputList[0].tagName !== \"SELECT\") return false;\r\n\r\n let correct = response.split(\"\\n\");\r\n if (correct.length === 1 && correct.length !== inputList.length)\r\n correct = response.split(\",\");\r\n\r\n if (config.logs) Logs.array(correct);\r\n\r\n for (let j = 0; j < inputList.length; ++j) {\r\n const options = inputList[j].querySelectorAll(\"option\");\r\n\r\n for (const option of options) {\r\n const content = normalizeText(option.textContent);\r\n const valide = correct[j].includes(content);\r\n\r\n //if it's a put in order\r\n if (!isNaN(parseInt(content))) {\r\n const content = normalizeText(\r\n (option.parentNode as HTMLElement)\r\n .closest(\"tr\")\r\n .querySelector(\".text\").textContent\r\n );\r\n const index = correct.findIndex((c) => {\r\n const valide = c.includes(content);\r\n if (config.logs) Logs.responseTry(content, valide);\r\n return valide;\r\n });\r\n if (index !== -1) {\r\n if (config.mouseover) {\r\n options[index + 1].closest(\"select\").addEventListener(\r\n \"click\",\r\n function () {\r\n options[index + 1].selected = \"selected\" as any;\r\n },\r\n { once: true }\r\n );\r\n } else {\r\n options[index + 1].selected = \"selected\" as any;\r\n }\r\n break;\r\n }\r\n }\r\n //end put in order\r\n\r\n if (config.logs) Logs.responseTry(content, valide);\r\n\r\n if (valide) {\r\n if (config.mouseover) {\r\n option\r\n .closest(\"select\")\r\n .addEventListener(\"click\", () => (option.selected = true), {\r\n once: true,\r\n });\r\n } else {\r\n option.selected = true;\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleSelect;\r\n","import Config from \"../../types/config\";\r\n\r\n/**\r\n * Handle textbox\r\n * @param config\r\n * @param inputList\r\n * @param response\r\n * @returns\r\n */\r\nfunction handleTextbox(\r\n config: Config,\r\n inputList: NodeListOf,\r\n response: string\r\n): boolean {\r\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\r\n\r\n if (\r\n inputList.length !== 1 ||\r\n (input.tagName !== \"TEXTAREA\" && input.type !== \"text\")\r\n )\r\n return false;\r\n\r\n if (config.typing) {\r\n let index = 0;\r\n input.addEventListener(\"keydown\", function (event: KeyboardEvent) {\r\n if (event.key === \"Backspace\") index = response.length + 1;\r\n if (index > response.length) return;\r\n event.preventDefault();\r\n input.value = response.slice(0, ++index);\r\n });\r\n } else {\r\n input.value = response;\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleTextbox;\r\n","import Config from \"../../types/config\";\r\nimport titleIndications from \"../../utils/title-indications\";\r\n\r\n/**\r\n * Copy the response in the clipboard if we can automaticaly fill the question\r\n * @param config\r\n * @param inputList\r\n * @param response\r\n * @param force Force the copy to clipboard\r\n * @returns\r\n */\r\nfunction handleClipboard(config: Config, response: string) {\r\n if (config.title) titleIndications(\"Copied to clipboard\");\r\n navigator.clipboard.writeText(response);\r\n}\r\n\r\nexport default handleClipboard;\r\n","import Config from \"../../types/config\";\r\n\r\n/**\r\n * Handle number input\r\n * @param config\r\n * @param inputList\r\n * @param response\r\n * @returns\r\n */\r\nfunction handleNumber(\r\n config: Config,\r\n inputList: NodeListOf,\r\n response: string\r\n): boolean {\r\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\r\n\r\n if (inputList.length !== 1 || input.type !== \"number\") return false;\r\n\r\n const number = response.match(/\\d+([,\\.]\\d+)?/gi)?.[0]?.replace(\",\", \".\");\r\n\r\n if (!number) return false;\r\n\r\n if (config.typing) {\r\n let index = 0;\r\n input.addEventListener(\"keydown\", function (event: KeyboardEvent) {\r\n if (event.key === \"Backspace\") index = number.length + 1;\r\n if (index > number.length) return;\r\n event.preventDefault();\r\n if (number.slice(index, index + 1) === \".\") ++index;\r\n input.value = number.slice(0, ++index);\r\n });\r\n } else {\r\n input.value = number;\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleNumber;\r\n","import Config from \"../../types/config\";\r\n\r\nfunction handleContentEditable(\r\n config: Config,\r\n inputList: NodeListOf,\r\n response: string\r\n): boolean {\r\n const input = inputList[0];\r\n\r\n if (\r\n inputList.length !== 1 ||\r\n input.getAttribute(\"contenteditable\") !== \"true\"\r\n )\r\n return false;\r\n\r\n if (config.typing) {\r\n let index = 0;\r\n input.addEventListener(\"keydown\", function (event: KeyboardEvent) {\r\n if (event.key === \"Backspace\") index = response.length + 1;\r\n if (index > response.length) return;\r\n event.preventDefault();\r\n input.textContent = response.slice(0, ++index);\r\n\r\n //put the cursor at the end\r\n input.focus();\r\n const range = document.createRange();\r\n range.selectNodeContents(input);\r\n range.collapse(false);\r\n const selection = window.getSelection();\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n });\r\n } else {\r\n input.textContent = response;\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleContentEditable;\r\n","import Config from \"../types/config\";\r\nimport Logs from \"../utils/logs\";\r\nimport getChatGPTResponse from \"./get-response\";\r\nimport normalizeQuestion from \"./normalize-question\";\r\nimport handleRadioAndCheckbox from \"./questions/radio-checkbox\";\r\nimport handleSelect from \"./questions/select\";\r\nimport handleTextbox from \"./questions/textbox\";\r\nimport handleClipboard from \"./questions/clipboard\";\r\nimport handleNumber from \"./questions/number\";\r\nimport handleContentEditable from \"./questions/contenteditable\";\r\n\r\n/**\r\n * Reply to the question\r\n * @param config\r\n * @param hiddenButton\r\n * @param form\r\n * @param query\r\n * @returns\r\n */\r\nasync function reply(\r\n config: Config,\r\n hiddenButton: HTMLElement,\r\n form: HTMLElement,\r\n query: string\r\n) {\r\n if (config.cursor) hiddenButton.style.cursor = \"wait\";\r\n\r\n form.querySelector(\".accesshide\")?.remove();\r\n\r\n const question = normalizeQuestion(config, form);\r\n const inputList: NodeListOf = form.querySelectorAll(query);\r\n\r\n const response = await getChatGPTResponse(config, question).catch(\r\n (error) => ({\r\n error,\r\n })\r\n );\r\n\r\n if (config.cursor)\r\n hiddenButton.style.cursor = config.infinite ? \"pointer\" : \"initial\";\r\n\r\n if (typeof response === \"object\" && \"error\" in response) {\r\n console.error(response.error);\r\n return;\r\n }\r\n\r\n if (config.logs) {\r\n Logs.question(question);\r\n Logs.response(response);\r\n }\r\n\r\n if (config.mode === \"clipboard\") {\r\n return handleClipboard(config, response);\r\n }\r\n\r\n if (config.mode === \"question-to-answer\") {\r\n const questionBackup = form.textContent;\r\n const questionContainer = form.querySelector(\".qtext\");\r\n questionContainer.textContent = response;\r\n questionContainer.addEventListener(\"click\", function () {\r\n questionContainer.textContent =\r\n questionContainer.textContent === questionBackup\r\n ? response\r\n : questionBackup;\r\n });\r\n return;\r\n }\r\n\r\n const handlers = [\r\n handleContentEditable,\r\n handleTextbox,\r\n handleNumber,\r\n handleSelect,\r\n handleRadioAndCheckbox,\r\n ];\r\n\r\n for (const handler of handlers) {\r\n if (handler(config, inputList, response)) return;\r\n }\r\n\r\n /** In the case we can't auto complete the question */\r\n handleClipboard(config, response);\r\n}\r\n\r\nexport default reply;\r\n","import Config from \"../types/config\";\r\nimport titleIndications from \"../utils/title-indications\";\r\nimport reply from \"./reply\";\r\n\r\nconst pressedKeys: string[] = [];\r\nconst listeners: {\r\n element: HTMLElement;\r\n fn: (this: HTMLElement, ev: MouseEvent) => any;\r\n}[] = [];\r\n\r\n/**\r\n * Create a listener on the keyboard to inject the code\r\n * @param config\r\n */\r\nfunction codeListener(config: Config) {\r\n document.body.addEventListener(\"keydown\", function (event) {\r\n pressedKeys.push(event.key);\r\n if (pressedKeys.length > config.code.length) pressedKeys.shift();\r\n if (pressedKeys.join(\"\") === config.code) {\r\n pressedKeys.length = 0;\r\n setUpMoodleGpt(config);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Setup moodleGPT into the page (remove/injection)\r\n * @param config\r\n * @returns\r\n */\r\nfunction setUpMoodleGpt(config: Config) {\r\n //removing events\r\n if (listeners.length > 0) {\r\n for (const listener of listeners) {\r\n if (config.cursor) listener.element.style.cursor = \"initial\";\r\n listener.element.removeEventListener(\"click\", listener.fn);\r\n }\r\n if (config.title) titleIndications(\"Removed\");\r\n listeners.length = 0;\r\n return;\r\n }\r\n\r\n //injection\r\n const inputQuery = [\"checkbox\", \"radio\", \"text\", \"number\"]\r\n .map((e) => `input[type=\"${e}\"]`)\r\n .join(\",\");\r\n const query = inputQuery + \", textarea, select, [contenteditable]\";\r\n const forms = Array.from(document.querySelectorAll(\".formulation\"));\r\n\r\n for (const form of forms) {\r\n const hiddenButton: HTMLElement = form.querySelector(\".qtext\");\r\n\r\n if (config.cursor) hiddenButton.style.cursor = \"pointer\";\r\n const fn = reply.bind(null, config, hiddenButton, form, query);\r\n listeners.push({ element: hiddenButton, fn });\r\n hiddenButton.addEventListener(\"click\", fn, { once: !config.infinite });\r\n }\r\n\r\n if (config.title) titleIndications(\"Injected\");\r\n}\r\n\r\nexport default codeListener;\r\n","import codeListener from \"./core/code-listener\";\r\n\r\nchrome.storage.sync.get([\"moodleGPT\"]).then(function (storage) {\r\n const config = storage.moodleGPT;\r\n\r\n if (!config) throw new Error(\"Please configure MoodleGPT into the extension\");\r\n\r\n codeListener(config);\r\n});\r\n"],"names":[],"mappings":";;;;;EAAA;;;EAGG;EACH,SAAS,gBAAgB,CAAC,IAAY,EAAA;EACpC,IAAA,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC;EACjC,IAAA,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC;EACtB,IAAA,UAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC;EACvD;;ECRA;EACA;AACA;EACA;EACA;AACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAoGA;EACO,SAAS,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE;EAC7D,IAAI,SAAS,KAAK,CAAC,KAAK,EAAE,EAAE,OAAO,KAAK,YAAY,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,UAAU,OAAO,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;EAChH,IAAI,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,EAAE,UAAU,OAAO,EAAE,MAAM,EAAE;EAC/D,QAAQ,SAAS,SAAS,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;EACnG,QAAQ,SAAS,QAAQ,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;EACtG,QAAQ,SAAS,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,EAAE;EACtH,QAAQ,IAAI,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,UAAU,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;EAC9E,KAAK,CAAC,CAAC;EACP;;EC1HA,MAAM,IAAI,CAAA;MACR,OAAO,QAAQ,CAAC,IAAY,EAAA;UAC1B,MAAM,GAAG,GAAG,aAAa,CAAC;UAC1B,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;OAC5C;EAED,IAAA,OAAO,WAAW,CAAC,IAAY,EAAE,MAAe,EAAA;EAC9C,QAAA,MAAM,GAAG,GAAG,SAAS,IAAI,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC,CAAC;UACnD,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;OAC5C;MAED,OAAO,KAAK,CAAC,GAAc,EAAA;EACzB,QAAA,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;OACjC;MAED,OAAO,QAAQ,CAAC,IAAY,EAAA;EAC1B,QAAA,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;OACnB;EACF;;EClBD;;;EAGG;EACH,SAAS,aAAa,CAAC,IAAY,EAAA;EACjC,IAAA,OAAO,IAAI;EACR,SAAA,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC;EAC3B,SAAA,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;EACxB,SAAA,WAAW,EAAE;EACb,SAAA,IAAI,EAAE;EACN,SAAA,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC;EAC7B,SAAA,OAAO,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;EACtC;;ECTA;;;;;EAKG;EACH,SAAe,kBAAkB,CAC/B,MAAc,EACd,QAAgB,EAAA;;EAEhB,QAAA,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;EACzC,QAAA,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,UAAU,CAAC,KAAK,EAAE,EAAE,KAAK,CAAC,CAAC;EACrE,QAAA,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,4CAA4C,EAAE;EACpE,YAAA,MAAM,EAAE,MAAM;EACd,YAAA,OAAO,EAAE;EACP,gBAAA,cAAc,EAAE,kBAAkB;EAClC,gBAAA,aAAa,EAAE,CAAA,OAAA,EAAU,MAAM,CAAC,MAAM,CAAE,CAAA;EACzC,aAAA;EACD,YAAA,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,UAAU,CAAC,MAAM,GAAG,IAAI;EACjD,YAAA,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;kBACnB,KAAK,EAAE,MAAM,CAAC,KAAK;kBACnB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;EAC/C,gBAAA,WAAW,EAAE,GAAG;EAChB,gBAAA,KAAK,EAAE,GAAG;EACV,gBAAA,gBAAgB,EAAE,GAAG;EACrB,gBAAA,IAAI,EAAE,IAAI;eACX,CAAC;EACH,SAAA,CAAC,CAAC;UACH,YAAY,CAAC,gBAAgB,CAAC,CAAC;EAC/B,QAAA,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;EAC7B,QAAA,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;EAChD,QAAA,OAAO,aAAa,CAAC,QAAQ,CAAC,CAAC;OAChC,CAAA,CAAA;EAAA;;ECnCD;;;;EAIG;EACH,SAAS,iBAAiB,CAAC,KAAuB,EAAA;MAChD,MAAM,GAAG,GAAe,EAAE,CAAC;EAC3B,IAAA,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;MACvD,MAAM,gBAAgB,GAAa,EAAE,CAAC;EACtC,IAAA,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,KAAI;EACjB,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC;UAC1D,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,KAAI;;cAC7C,MAAM,OAAO,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,WAAW,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAE,IAAI,EAAE,CAAC;cACzC,gBAAgB,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAChC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,EAC5B,OAAO,CAAC,MAAM,IAAI,CAAC,CACpB,CAAC;EACF,YAAA,OAAO,OAAO,CAAC;EACjB,SAAC,CAAC,CAAC;EACH,QAAA,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;EACzB,KAAC,CAAC,CAAC;EAEH,IAAA,MAAM,kBAAkB,GACtB,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;MACnE,MAAM,cAAc,GAClB,IAAI,GAAG,KAAK,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;MAE7D,MAAM,SAAS,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,KAAI;UACjC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CACzB,CAAC,OAAO,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;WACtE,CAAC;UACF,OAAO,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;EAC9C,KAAC,CAAC,CAAC;EACH,IAAA,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC;MAC/B,OAAO,IAAI,GAAG,cAAc,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;EACtD;;EC/BA;;;;;EAKG;EACH,SAAS,iBAAiB,CAAC,MAAc,EAAE,iBAA8B,EAAA;EACvE,IAAA,IAAI,QAAQ,GAAG,iBAAiB,CAAC,WAAW,CAAC;MAE7C,IAAI,MAAM,CAAC,KAAK,EAAE;;UAEhB,MAAM,MAAM,GACV,iBAAiB,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;EACrD,QAAA,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;EAC1B,YAAA,QAAQ,GAAG,QAAQ,CAAC,OAAO,CACzB,KAAK,CAAC,WAAW,EACjB,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,GAAG,IAAI,CACvC,CAAC;EACH,SAAA;EACF,KAAA;EAED,IAAA,MAAM,aAAa,GAAG,CAAA;QAChB,QAAQ,CAAA;sJACsI,CAAC;EACrJ,IAAA,OAAO,aAAa,CAAC,aAAa,CAAC,CAAC;EACtC;;ECzBA;;;;;EAKG;EACH,SAAS,sBAAsB,CAC7B,MAAc,EACd,SAAkC,EAClC,QAAgB,EAAA;MAEhB,MAAM,KAAK,GAAG,SAAS,KAAT,IAAA,IAAA,SAAS,uBAAT,SAAS,CAAG,CAAC,CAAqB,CAAC;EAEjD,IAAA,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;EACjE,QAAA,OAAO,KAAK,CAAC;EAEf,IAAA,KAAK,MAAM,KAAK,IAAI,SAAyC,EAAE;UAC7D,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;UAC5D,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;UAC1C,IAAI,MAAM,CAAC,IAAI;EAAE,YAAA,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;EACnD,QAAA,IAAI,MAAM,EAAE;cACV,IAAI,MAAM,CAAC,SAAS,EAAE;EACpB,gBAAA,KAAK,CAAC,gBAAgB,CAAC,WAAW,EAAE,OAAO,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE;EAChE,oBAAA,IAAI,EAAE,IAAI;EACX,iBAAA,CAAC,CAAC;EACJ,aAAA;EAAM,iBAAA;EACL,gBAAA,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;EACtB,aAAA;EACF,SAAA;EACF,KAAA;EACD,IAAA,OAAO,IAAI,CAAC;EACd;;EC/BA;;;;;;EAMG;EACH,SAAS,YAAY,CACnB,MAAc,EACd,SAAkC,EAClC,QAAgB,EAAA;EAEhB,IAAA,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,QAAQ;EAAE,QAAA,OAAO,KAAK,CAAC;MAE9E,IAAI,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;EACnC,IAAA,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM;EAC7D,QAAA,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;MAEhC,IAAI,MAAM,CAAC,IAAI;EAAE,QAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;EAErC,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE;UACzC,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;EAExD,QAAA,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;cAC5B,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;cAClD,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;;cAG5C,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE;EAC7B,gBAAA,MAAM,OAAO,GAAG,aAAa,CAC1B,MAAM,CAAC,UAA0B;uBAC/B,OAAO,CAAC,IAAI,CAAC;EACb,qBAAA,aAAa,CAAC,OAAO,CAAC,CAAC,WAAW,CACtC,CAAC;kBACF,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,KAAI;sBACpC,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;sBACnC,IAAI,MAAM,CAAC,IAAI;EAAE,wBAAA,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;EACnD,oBAAA,OAAO,MAAM,CAAC;EAChB,iBAAC,CAAC,CAAC;EACH,gBAAA,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE;sBAChB,IAAI,MAAM,CAAC,SAAS,EAAE;EACpB,wBAAA,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,gBAAgB,CACnD,OAAO,EACP,YAAA;8BACE,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,GAAG,UAAiB,CAAC;EAClD,yBAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAC;EACH,qBAAA;EAAM,yBAAA;0BACL,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,GAAG,UAAiB,CAAC;EACjD,qBAAA;sBACD,MAAM;EACP,iBAAA;EACF,aAAA;;cAGD,IAAI,MAAM,CAAC,IAAI;EAAE,gBAAA,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;EAEnD,YAAA,IAAI,MAAM,EAAE;kBACV,IAAI,MAAM,CAAC,SAAS,EAAE;sBACpB,MAAM;2BACH,OAAO,CAAC,QAAQ,CAAC;EACjB,yBAAA,gBAAgB,CAAC,OAAO,EAAE,OAAO,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE;EACzD,wBAAA,IAAI,EAAE,IAAI;EACX,qBAAA,CAAC,CAAC;EACN,iBAAA;EAAM,qBAAA;EACL,oBAAA,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;EACxB,iBAAA;kBACD,MAAM;EACP,aAAA;EACF,SAAA;EACF,KAAA;EAED,IAAA,OAAO,IAAI,CAAC;EACd;;EC5EA;;;;;;EAMG;EACH,SAAS,aAAa,CACpB,MAAc,EACd,SAAkC,EAClC,QAAgB,EAAA;EAEhB,IAAA,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAA2C,CAAC;EAErE,IAAA,IACE,SAAS,CAAC,MAAM,KAAK,CAAC;WACrB,KAAK,CAAC,OAAO,KAAK,UAAU,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;EAEvD,QAAA,OAAO,KAAK,CAAC;MAEf,IAAI,MAAM,CAAC,MAAM,EAAE;UACjB,IAAI,KAAK,GAAG,CAAC,CAAC;EACd,QAAA,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,UAAU,KAAoB,EAAA;EAC9D,YAAA,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW;EAAE,gBAAA,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;EAC3D,YAAA,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM;kBAAE,OAAO;cACpC,KAAK,CAAC,cAAc,EAAE,CAAC;EACvB,YAAA,KAAK,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;EAC3C,SAAC,CAAC,CAAC;EACJ,KAAA;EAAM,SAAA;EACL,QAAA,KAAK,CAAC,KAAK,GAAG,QAAQ,CAAC;EACxB,KAAA;EAED,IAAA,OAAO,IAAI,CAAC;EACd;;EChCA;;;;;;;EAOG;EACH,SAAS,eAAe,CAAC,MAAc,EAAE,QAAgB,EAAA;MACvD,IAAI,MAAM,CAAC,KAAK;UAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;EAC1D,IAAA,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;EAC1C;;ECZA;;;;;;EAMG;EACH,SAAS,YAAY,CACnB,MAAc,EACd,SAAkC,EAClC,QAAgB,EAAA;;EAEhB,IAAA,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAA2C,CAAC;MAErE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;EAAE,QAAA,OAAO,KAAK,CAAC;MAEpE,MAAM,MAAM,GAAG,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,QAAQ,CAAC,KAAK,CAAC,kBAAkB,CAAC,0CAAG,CAAC,CAAC,0CAAE,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;EAE1E,IAAA,IAAI,CAAC,MAAM;EAAE,QAAA,OAAO,KAAK,CAAC;MAE1B,IAAI,MAAM,CAAC,MAAM,EAAE;UACjB,IAAI,KAAK,GAAG,CAAC,CAAC;EACd,QAAA,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,UAAU,KAAoB,EAAA;EAC9D,YAAA,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW;EAAE,gBAAA,KAAK,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;EACzD,YAAA,IAAI,KAAK,GAAG,MAAM,CAAC,MAAM;kBAAE,OAAO;cAClC,KAAK,CAAC,cAAc,EAAE,CAAC;cACvB,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;EAAE,gBAAA,EAAE,KAAK,CAAC;EACpD,YAAA,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;EACzC,SAAC,CAAC,CAAC;EACJ,KAAA;EAAM,SAAA;EACL,QAAA,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC;EACtB,KAAA;EAED,IAAA,OAAO,IAAI,CAAC;EACd;;EClCA,SAAS,qBAAqB,CAC5B,MAAc,EACd,SAAkC,EAClC,QAAgB,EAAA;EAEhB,IAAA,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;EAE3B,IAAA,IACE,SAAS,CAAC,MAAM,KAAK,CAAC;EACtB,QAAA,KAAK,CAAC,YAAY,CAAC,iBAAiB,CAAC,KAAK,MAAM;EAEhD,QAAA,OAAO,KAAK,CAAC;MAEf,IAAI,MAAM,CAAC,MAAM,EAAE;UACjB,IAAI,KAAK,GAAG,CAAC,CAAC;EACd,QAAA,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,UAAU,KAAoB,EAAA;EAC9D,YAAA,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW;EAAE,gBAAA,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;EAC3D,YAAA,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM;kBAAE,OAAO;cACpC,KAAK,CAAC,cAAc,EAAE,CAAC;EACvB,YAAA,KAAK,CAAC,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;;cAG/C,KAAK,CAAC,KAAK,EAAE,CAAC;EACd,YAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;EACrC,YAAA,KAAK,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;EAChC,YAAA,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;EACtB,YAAA,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;cACxC,SAAS,CAAC,eAAe,EAAE,CAAC;EAC5B,YAAA,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;EAC5B,SAAC,CAAC,CAAC;EACJ,KAAA;EAAM,SAAA;EACL,QAAA,KAAK,CAAC,WAAW,GAAG,QAAQ,CAAC;EAC9B,KAAA;EAED,IAAA,OAAO,IAAI,CAAC;EACd;;EC1BA;;;;;;;EAOG;EACH,SAAe,KAAK,CAClB,MAAc,EACd,YAAyB,EACzB,IAAiB,EACjB,KAAa,EAAA;;;UAEb,IAAI,MAAM,CAAC,MAAM;EAAE,YAAA,YAAY,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;UAEtD,CAAA,EAAA,GAAA,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,MAAA,IAAA,IAAA,EAAA,KAAA,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAE,MAAM,EAAE,CAAC;UAE5C,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;UACjD,MAAM,SAAS,GAA4B,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;EAExE,QAAA,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,KAAK,CAC/D,CAAC,KAAK,MAAM;cACV,KAAK;EACN,SAAA,CAAC,CACH,CAAC;UAEF,IAAI,MAAM,CAAC,MAAM;EACf,YAAA,YAAY,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;UAEtE,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,IAAI,QAAQ,EAAE;EACvD,YAAA,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;cAC9B,OAAO;EACR,SAAA;UAED,IAAI,MAAM,CAAC,IAAI,EAAE;EACf,YAAA,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;EACxB,YAAA,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;EACzB,SAAA;EAED,QAAA,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE;EAC/B,YAAA,OAAO,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;EAC1C,SAAA;EAED,QAAA,IAAI,MAAM,CAAC,IAAI,KAAK,oBAAoB,EAAE;EACxC,YAAA,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC;cACxC,MAAM,iBAAiB,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;EACvD,YAAA,iBAAiB,CAAC,WAAW,GAAG,QAAQ,CAAC;EACzC,YAAA,iBAAiB,CAAC,gBAAgB,CAAC,OAAO,EAAE,YAAA;EAC1C,gBAAA,iBAAiB,CAAC,WAAW;sBAC3B,iBAAiB,CAAC,WAAW,KAAK,cAAc;EAC9C,0BAAE,QAAQ;4BACR,cAAc,CAAC;EACvB,aAAC,CAAC,CAAC;cACH,OAAO;EACR,SAAA;EAED,QAAA,MAAM,QAAQ,GAAG;cACf,qBAAqB;cACrB,aAAa;cACb,YAAY;cACZ,YAAY;cACZ,sBAAsB;WACvB,CAAC;EAEF,QAAA,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;EAC9B,YAAA,IAAI,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC;kBAAE,OAAO;EAClD,SAAA;;EAGD,QAAA,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;;EACnC;;EC9ED,MAAM,WAAW,GAAa,EAAE,CAAC;EACjC,MAAM,SAAS,GAGT,EAAE,CAAC;EAET;;;EAGG;EACH,SAAS,YAAY,CAAC,MAAc,EAAA;MAClC,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,UAAU,KAAK,EAAA;EACvD,QAAA,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;UAC5B,IAAI,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM;cAAE,WAAW,CAAC,KAAK,EAAE,CAAC;UACjE,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,IAAI,EAAE;EACxC,YAAA,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;cACvB,cAAc,CAAC,MAAM,CAAC,CAAC;EACxB,SAAA;EACH,KAAC,CAAC,CAAC;EACL,CAAC;EAED;;;;EAIG;EACH,SAAS,cAAc,CAAC,MAAc,EAAA;;EAEpC,IAAA,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;EACxB,QAAA,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;cAChC,IAAI,MAAM,CAAC,MAAM;kBAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC;cAC7D,QAAQ,CAAC,OAAO,CAAC,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;EAC5D,SAAA;UACD,IAAI,MAAM,CAAC,KAAK;cAAE,gBAAgB,CAAC,SAAS,CAAC,CAAC;EAC9C,QAAA,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;UACrB,OAAO;EACR,KAAA;;MAGD,MAAM,UAAU,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC;WACvD,GAAG,CAAC,CAAC,CAAC,KAAK,CAAA,YAAA,EAAe,CAAC,CAAA,EAAA,CAAI,CAAC;WAChC,IAAI,CAAC,GAAG,CAAC,CAAC;EACb,IAAA,MAAM,KAAK,GAAG,UAAU,GAAG,uCAAuC,CAAC;EACnE,IAAA,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC,CAAC;EAEpE,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;UACxB,MAAM,YAAY,GAAgB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;UAE/D,IAAI,MAAM,CAAC,MAAM;EAAE,YAAA,YAAY,CAAC,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC;EACzD,QAAA,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;UAC/D,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;EAC9C,QAAA,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;EACxE,KAAA;MAED,IAAI,MAAM,CAAC,KAAK;UAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC;EACjD;;ECzDA,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,OAAO,EAAA;EAC3D,IAAA,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;EAEjC,IAAA,IAAI,CAAC,MAAM;EAAE,QAAA,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;MAE9E,YAAY,CAAC,MAAM,CAAC,CAAC;EACvB,CAAC,CAAC;;;;;;","x_google_ignoreList":[1]}
\ No newline at end of file
+{"version":3,"file":"MoodleGPT.js","sources":["../src/utils/title-indications.ts","../node_modules/tslib/tslib.es6.js","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/utils/html-table-to-string.ts","../src/core/questions/radio-checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/questions/clipboard.ts","../src/core/questions/number.ts","../src/core/questions/contenteditable.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/get-response.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\r\n * Show some informations into the document title and remove it after 3000ms\r\n * @param text\r\n */\r\nfunction titleIndications(text: string) {\r\n const backTitle = document.title;\r\n document.title = text;\r\n setTimeout(() => (document.title = backTitle), 3000);\r\n}\r\n\r\nexport default titleIndications;\r\n","/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\r\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\r\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\r\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\r\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\r\n var _, done = false;\r\n for (var i = decorators.length - 1; i >= 0; i--) {\r\n var context = {};\r\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\r\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\r\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\r\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\r\n if (kind === \"accessor\") {\r\n if (result === void 0) continue;\r\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\r\n if (_ = accept(result.get)) descriptor.get = _;\r\n if (_ = accept(result.set)) descriptor.set = _;\r\n if (_ = accept(result.init)) initializers.push(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.push(_);\r\n else descriptor[key] = _;\r\n }\r\n }\r\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\r\n done = true;\r\n};\r\n\r\nexport function __runInitializers(thisArg, initializers, value) {\r\n var useValue = arguments.length > 2;\r\n for (var i = 0; i < initializers.length; i++) {\r\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\r\n }\r\n return useValue ? value : void 0;\r\n};\r\n\r\nexport function __propKey(x) {\r\n return typeof x === \"symbol\" ? x : \"\".concat(x);\r\n};\r\n\r\nexport function __setFunctionName(f, name, prefix) {\r\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\r\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\r\n};\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n\r\nexport function __classPrivateFieldIn(state, receiver) {\r\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\r\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\r\n}\r\n","import GPTAnswer from \"../types/gptAnswer\";\r\nclass Logs {\r\n static question(text: string) {\r\n const css = \"color: cyan\";\r\n console.log(\"%c[QUESTION]: %s\", css, text);\r\n }\r\n\r\n static responseTry(text: string, valide: boolean) {\r\n const css = \"color: \" + (valide ? \"green\" : \"red\");\r\n console.log(\"%c[CHECKING]: %s\", css, text);\r\n }\r\n\r\n static array(arr: unknown[]) {\r\n console.log(\"[CORRECTS] \", arr);\r\n }\r\n\r\n static response(gptAnswer: GPTAnswer) {\r\n console.log(\"Original:\\n\" + gptAnswer.response);\r\n console.log(\"Normalized:\\n\" + gptAnswer.normalizedResponse);\r\n }\r\n}\r\n\r\nexport default Logs;\r\n","/**\r\n * Normlize text\r\n * @param text\r\n */\r\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\r\n let normalizedText = text\r\n .replace(/\\n+/gi, \"\\n\") //remove duplicate new lines\r\n .replace(/(\\n\\s*\\n)+/g, \"\\n\") //remove useless white sapce from textcontent\r\n .replace(/[ \\t]+/gi, \" \"); //replace multiples space or tabs by a space\r\n\r\n if (toLowerCase) normalizedText = normalizedText.toLowerCase();\r\n\r\n return (\r\n normalizedText\r\n .trim()\r\n /* We remove that because sometimes ChatGPT will reply: \"answer d\" */\r\n .replace(/^[a-z\\d]\\.\\s/gi, \"\") //a. text, b. text, c. text, 1. text, 2. text, 3.text\r\n .replace(/\\n[a-z\\d]\\.\\s/gi, \"\\n\") //same but with new line\r\n );\r\n}\r\n\r\nexport default normalizeText;\r\n","/**\r\n * Convert table to representating string table\r\n * @param table\r\n * @returns\r\n */\r\nfunction htmlTableToString(table: HTMLTableElement) {\r\n const tab: string[][] = [];\r\n const lines = Array.from(table.querySelectorAll(\"tr\"));\r\n const maxColumnsLength: number[] = [];\r\n lines.map((line) => {\r\n const cells = Array.from(line.querySelectorAll(\"td, th\"));\r\n const cellsContent = cells.map((cell, index) => {\r\n const content = cell.textContent?.trim();\r\n maxColumnsLength[index] = Math.max(\r\n maxColumnsLength[index] || 0,\r\n content.length || 0\r\n );\r\n return content;\r\n });\r\n tab.push(cellsContent);\r\n });\r\n\r\n const lineSeparationSize =\r\n maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\r\n const lineSeparation =\r\n \"\\n\" + Array(lineSeparationSize).fill(\"-\").join(\"\") + \"\\n\";\r\n\r\n const mappedTab = tab.map((line) => {\r\n const mappedLine = line.map((content, index) =>\r\n content.padEnd(\r\n maxColumnsLength[index],\r\n \"\\u00A0\" /* For no matching with \\s */\r\n )\r\n );\r\n return \"| \" + mappedLine.join(\" | \") + \" |\";\r\n });\r\n const head = mappedTab.shift();\r\n return head + lineSeparation + mappedTab.join(\"\\n\");\r\n}\r\n\r\nexport default htmlTableToString;\r\n","import Config from \"../../types/config\";\r\nimport GPTAnswer from \"../../types/gptAnswer\";\r\nimport Logs from \"../../utils/logs\";\r\nimport normalizeText from \"../../utils/normalize-text\";\r\n\r\n/**\r\n * Handle checkbox and input elements\r\n * @param config\r\n * @param inputList\r\n * @param gptAnswer\r\n */\r\nfunction handleRadioAndCheckbox(\r\n config: Config,\r\n inputList: NodeListOf,\r\n gptAnswer: GPTAnswer\r\n): boolean {\r\n const input = inputList?.[0] as HTMLInputElement;\r\n\r\n if (!input || (input.type !== \"checkbox\" && input.type !== \"radio\"))\r\n return false;\r\n\r\n for (const input of inputList as NodeListOf) {\r\n const content = normalizeText(input.parentNode.textContent);\r\n const valide = gptAnswer.normalizedResponse.includes(content);\r\n if (config.logs) Logs.responseTry(content, valide);\r\n if (valide) {\r\n if (config.mouseover) {\r\n input.addEventListener(\"mouseover\", () => (input.checked = true), {\r\n once: true,\r\n });\r\n } else {\r\n input.checked = true;\r\n }\r\n }\r\n }\r\n return true;\r\n}\r\n\r\nexport default handleRadioAndCheckbox;\r\n","import Config from \"../../types/config\";\r\nimport GPTAnswer from \"../../types/gptAnswer\";\r\nimport Logs from \"../../utils/logs\";\r\nimport normalizeText from \"../../utils/normalize-text\";\r\n\r\n/**\r\n * Handle select elements (and put in order select)\r\n * @param config\r\n * @param inputList\r\n * @param gptAnswer\r\n * @returns\r\n */\r\nfunction handleSelect(\r\n config: Config,\r\n inputList: NodeListOf,\r\n gptAnswer: GPTAnswer\r\n): boolean {\r\n if (inputList.length === 0 || inputList[0].tagName !== \"SELECT\") return false;\r\n\r\n let correct = gptAnswer.normalizedResponse.split(\"\\n\");\r\n\r\n if (config.logs) Logs.array(correct);\r\n\r\n /**\r\n * Sometimes ChatGPT give the question so we should remove them\r\n * Example:\r\n * 5*5\r\n * 25\r\n * 10+10\r\n * 20\r\n * 20-10\r\n * 10\r\n *\r\n * And we only want to keep answers\r\n * 25\r\n * 20\r\n * 10\r\n */\r\n if (correct.length === inputList.length * 2) {\r\n correct = correct.filter((answer, index) => index % 2 === 1);\r\n }\r\n\r\n for (let j = 0; j < inputList.length; ++j) {\r\n const options = inputList[j].querySelectorAll(\"option\");\r\n\r\n for (const option of options) {\r\n const content = normalizeText(option.textContent);\r\n const valide = correct[j].includes(content);\r\n\r\n /* Handle put in order question */\r\n if (!/[^\\d]+/gi.test(content)) {\r\n const elementTitle = (option.parentNode as HTMLElement)\r\n .closest(\"tr\")\r\n .querySelector(\".text\");\r\n const content = normalizeText(elementTitle.textContent);\r\n\r\n const indexCorrectAnswer = correct.findIndex((answer) => {\r\n const valide = answer.includes(content);\r\n if (config.logs) Logs.responseTry(content, valide);\r\n return valide;\r\n });\r\n\r\n if (indexCorrectAnswer !== -1) {\r\n //we do + 1 because we skip the first option: Choose...\r\n if (config.mouseover) {\r\n options[indexCorrectAnswer + 1].closest(\"select\").addEventListener(\r\n \"click\",\r\n function () {\r\n options[indexCorrectAnswer + 1].selected = \"selected\" as any;\r\n },\r\n { once: true }\r\n );\r\n } else {\r\n options[indexCorrectAnswer + 1].selected = \"selected\" as any;\r\n }\r\n break;\r\n }\r\n }\r\n /* End */\r\n\r\n if (config.logs) Logs.responseTry(content, valide);\r\n\r\n if (valide) {\r\n if (config.mouseover) {\r\n option\r\n .closest(\"select\")\r\n .addEventListener(\"click\", () => (option.selected = true), {\r\n once: true,\r\n });\r\n } else {\r\n option.selected = true;\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleSelect;\r\n","import Config from \"../../types/config\";\r\nimport GPTAnswer from \"../../types/gptAnswer\";\r\n\r\n/**\r\n * Handle textbox\r\n * @param config\r\n * @param inputList\r\n * @param gptAnswer\r\n * @returns\r\n */\r\nfunction handleTextbox(\r\n config: Config,\r\n inputList: NodeListOf,\r\n gptAnswer: GPTAnswer\r\n): boolean {\r\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\r\n\r\n if (\r\n inputList.length !== 1 ||\r\n (input.tagName !== \"TEXTAREA\" && input.type !== \"text\")\r\n )\r\n return false;\r\n\r\n if (config.typing) {\r\n let index = 0;\r\n input.addEventListener(\"keydown\", function (event: KeyboardEvent) {\r\n if (event.key === \"Backspace\") index = gptAnswer.response.length + 1;\r\n if (index > gptAnswer.response.length) return;\r\n event.preventDefault();\r\n input.value = gptAnswer.response.slice(0, ++index);\r\n });\r\n } else {\r\n input.value = gptAnswer.response;\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleTextbox;\r\n","import Config from \"../../types/config\";\r\nimport GPTAnswer from \"../../types/gptAnswer\";\r\nimport titleIndications from \"../../utils/title-indications\";\r\n\r\n/**\r\n * Copy the response in the clipboard if we can automaticaly fill the question\r\n * @param config\r\n * @param gptAnswer\r\n */\r\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\r\n if (config.title) titleIndications(\"Copied to clipboard\");\r\n navigator.clipboard.writeText(gptAnswer.response);\r\n}\r\n\r\nexport default handleClipboard;\r\n","import Config from \"../../types/config\";\r\nimport GPTAnswer from \"../../types/gptAnswer\";\r\n\r\n/**\r\n * Handle number input\r\n * @param config\r\n * @param inputList\r\n * @param gptAnswer\r\n * @returns\r\n */\r\nfunction handleNumber(\r\n config: Config,\r\n inputList: NodeListOf,\r\n gptAnswer: GPTAnswer\r\n): boolean {\r\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\r\n\r\n if (inputList.length !== 1 || input.type !== \"number\") return false;\r\n\r\n const number = gptAnswer.normalizedResponse\r\n .match(/\\d+([,\\.]\\d+)?/gi)?.[0]\r\n ?.replace(\",\", \".\");\r\n\r\n if (!number) return false;\r\n\r\n if (config.typing) {\r\n let index = 0;\r\n input.addEventListener(\"keydown\", function (event: KeyboardEvent) {\r\n if (event.key === \"Backspace\") index = number.length + 1;\r\n if (index > number.length) return;\r\n event.preventDefault();\r\n if (number.slice(index, index + 1) === \".\") ++index;\r\n input.value = number.slice(0, ++index);\r\n });\r\n } else {\r\n input.value = number;\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleNumber;\r\n","import Config from \"../../types/config\";\r\nimport GPTAnswer from \"../../types/gptAnswer\";\r\n\r\n/**\r\n * Hanlde contenteditable elements\r\n * @param config\r\n * @param inputList\r\n * @param gptAnswer\r\n * @returns\r\n */\r\nfunction handleContentEditable(\r\n config: Config,\r\n inputList: NodeListOf,\r\n gptAnswer: GPTAnswer\r\n): boolean {\r\n const input = inputList[0];\r\n\r\n if (\r\n inputList.length !== 1 ||\r\n input.getAttribute(\"contenteditable\") !== \"true\"\r\n )\r\n return false;\r\n\r\n if (config.typing) {\r\n let index = 0;\r\n input.addEventListener(\"keydown\", function (event: KeyboardEvent) {\r\n if (event.key === \"Backspace\") index = gptAnswer.response.length + 1;\r\n if (index > gptAnswer.response.length) return;\r\n event.preventDefault();\r\n input.textContent = gptAnswer.response.slice(0, ++index);\r\n\r\n /* Put the cursor at the end of the typed text */\r\n input.focus();\r\n const range = document.createRange();\r\n range.selectNodeContents(input);\r\n range.collapse(false);\r\n const selection = window.getSelection();\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n });\r\n } else {\r\n input.textContent = gptAnswer.response;\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleContentEditable;\r\n","import Config from \"../types/config\";\r\nimport Logs from \"../utils/logs\";\r\nimport getChatGPTResponse from \"./get-response\";\r\nimport createQuestion from \"./create-question\";\r\nimport handleRadioAndCheckbox from \"./questions/radio-checkbox\";\r\nimport handleSelect from \"./questions/select\";\r\nimport handleTextbox from \"./questions/textbox\";\r\nimport handleClipboard from \"./questions/clipboard\";\r\nimport handleNumber from \"./questions/number\";\r\nimport handleContentEditable from \"./questions/contenteditable\";\r\nimport { removeListener } from \"./code-listener\";\r\n\r\n/**\r\n * Reply to the question\r\n * @param config\r\n * @param hiddenButton\r\n * @param form\r\n * @param query\r\n * @returns\r\n */\r\nasync function reply(\r\n config: Config,\r\n hiddenButton: HTMLElement,\r\n form: HTMLElement,\r\n query: string\r\n) {\r\n if (config.cursor) hiddenButton.style.cursor = \"wait\";\r\n\r\n const question = createQuestion(config, form);\r\n const inputList: NodeListOf = form.querySelectorAll(query);\r\n\r\n const gptAnswer = await getChatGPTResponse(config, question).catch(\r\n (error) => ({\r\n error,\r\n })\r\n );\r\n\r\n const haveError = typeof gptAnswer === \"object\" && \"error\" in gptAnswer;\r\n\r\n if (config.cursor)\r\n hiddenButton.style.cursor =\r\n config.infinite || haveError ? \"pointer\" : \"initial\";\r\n\r\n if (haveError) {\r\n console.error(gptAnswer.error);\r\n return;\r\n }\r\n\r\n if (config.logs) {\r\n Logs.question(question);\r\n Logs.response(gptAnswer);\r\n }\r\n\r\n /* Handle clipboard mode */\r\n if (config.mode === \"clipboard\") {\r\n if (!config.infinite) removeListener(hiddenButton);\r\n return handleClipboard(config, gptAnswer);\r\n }\r\n\r\n /* Handle question to answer mode */\r\n if (config.mode === \"question-to-answer\") {\r\n removeListener(hiddenButton);\r\n\r\n const questionContainer = form.querySelector(\".qtext\");\r\n const questionBackup = questionContainer.textContent;\r\n\r\n questionContainer.textContent = gptAnswer.response;\r\n questionContainer.style.whiteSpace = \"pre-wrap\";\r\n\r\n questionContainer.addEventListener(\"click\", function () {\r\n const isNotResponse = questionContainer.textContent === questionBackup;\r\n questionContainer.style.whiteSpace = isNotResponse ? \"pre-wrap\" : null;\r\n questionContainer.textContent = isNotResponse\r\n ? gptAnswer.response\r\n : questionBackup;\r\n });\r\n return;\r\n }\r\n\r\n /* Better then set once on the event because if there is an error the user can click an other time on the question */\r\n if (!config.infinite) removeListener(hiddenButton);\r\n\r\n const handlers = [\r\n handleContentEditable,\r\n handleTextbox,\r\n handleNumber,\r\n handleSelect,\r\n handleRadioAndCheckbox,\r\n ];\r\n\r\n for (const handler of handlers) {\r\n if (handler(config, inputList, gptAnswer)) return;\r\n }\r\n\r\n /* In the case we can't auto complete the question */\r\n handleClipboard(config, gptAnswer);\r\n}\r\n\r\nexport default reply;\r\n","import Config from \"../types/config\";\r\nimport normalizeText from \"../utils/normalize-text\";\r\nimport htmlTableToString from \"../utils/html-table-to-string\";\r\n\r\n/**\r\n * Normalize the question and add sub informations\r\n * @param langage\r\n * @param question\r\n * @returns\r\n */\r\nfunction createQuestion(config: Config, questionContainer: HTMLElement) {\r\n let question = questionContainer.innerText;\r\n\r\n /* We remove unnecessary information */\r\n const accesshideElements: NodeListOf =\r\n questionContainer.querySelectorAll(\".accesshide\");\r\n for (const useless of accesshideElements) {\r\n question = question.replace(useless.innerText, \"\");\r\n }\r\n\r\n /* Make tables more readable for chat-gpt */\r\n const tables: NodeListOf =\r\n questionContainer.querySelectorAll(\".qtext table\");\r\n for (const table of tables) {\r\n question = question.replace(\r\n table.innerText,\r\n \"\\n\" + htmlTableToString(table) + \"\\n\"\r\n );\r\n }\r\n\r\n return normalizeText(question, false);\r\n}\r\n\r\nexport default createQuestion;\r\n","import Config from \"../types/config\";\r\nimport GPTAnswer from \"../types/gptAnswer\";\r\nimport normalizeText from \"../utils/normalize-text\";\r\n\r\n/**\r\n * Get the response from chatGPT api\r\n * @param config\r\n * @param question\r\n * @returns\r\n */\r\nasync function getChatGPTResponse(\r\n config: Config,\r\n question: string\r\n): Promise {\r\n const controller = new AbortController();\r\n const timeoutControler = setTimeout(() => controller.abort(), 15000);\r\n const req = await fetch(\"https://api.openai.com/v1/chat/completions\", {\r\n method: \"POST\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n Authorization: `Bearer ${config.apiKey}`,\r\n },\r\n signal: config.timeout ? controller.signal : null,\r\n body: JSON.stringify({\r\n model: config.model,\r\n messages: [\r\n {\r\n role: \"system\",\r\n content: `\r\nFollow those rules:\r\n- Sometimes there won't be a question, so just answer the statement as you normally would without following the other rules and give the most detailled and complete answer with explication.\r\n- For put in order question just give the good order separate by new line\r\n- Your goal is to understand the statement and to reply to each question by giving only the answer.\r\n- You will keep the same order for the answers like in the text. \r\n- You will separate all the answer with new lines and only show the correctes one.\r\n- You will only give the answers for each question and omit the questions, statement, title or other informations from the response.\r\n- You will only give answer with exactly the same text as the gived answers.\r\n- The question always have the good answer so you should always give an answer to the question.\r\n- You will always respond in the same langage as the user question.`,\r\n },\r\n { role: \"user\", content: question },\r\n ],\r\n temperature: 0.8,\r\n top_p: 1.0,\r\n presence_penalty: 1.0,\r\n stop: null,\r\n }),\r\n });\r\n clearTimeout(timeoutControler);\r\n const rep = await req.json();\r\n const response = rep.choices[0].message.content;\r\n return {\r\n response,\r\n normalizedResponse: normalizeText(response),\r\n };\r\n}\r\n\r\nexport default getChatGPTResponse;\r\n","import Config from \"../types/config\";\r\nimport titleIndications from \"../utils/title-indications\";\r\nimport reply from \"./reply\";\r\n\r\nconst pressedKeys: string[] = [];\r\nconst listeners: {\r\n element: HTMLElement;\r\n fn: (this: HTMLElement, ev: MouseEvent) => any;\r\n}[] = [];\r\n\r\n/**\r\n * Create a listener on the keyboard to inject the code\r\n * @param config\r\n */\r\nfunction codeListener(config: Config) {\r\n document.body.addEventListener(\"keydown\", function (event) {\r\n pressedKeys.push(event.key);\r\n if (pressedKeys.length > config.code.length) pressedKeys.shift();\r\n if (pressedKeys.join(\"\") === config.code) {\r\n pressedKeys.length = 0;\r\n setUpMoodleGpt(config);\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Setup moodleGPT into the page (remove/injection)\r\n * @param config\r\n * @returns\r\n */\r\nfunction setUpMoodleGpt(config: Config) {\r\n /* Removing events */\r\n if (listeners.length > 0) {\r\n for (const listener of listeners) {\r\n if (config.cursor) listener.element.style.cursor = \"initial\";\r\n listener.element.removeEventListener(\"click\", listener.fn);\r\n }\r\n if (config.title) titleIndications(\"Removed\");\r\n listeners.length = 0;\r\n return;\r\n }\r\n\r\n /* Code injection */\r\n const inputQuery = [\"checkbox\", \"radio\", \"text\", \"number\"]\r\n .map((e) => `input[type=\"${e}\"]`)\r\n .join(\",\");\r\n const query = inputQuery + \", textarea, select, [contenteditable]\";\r\n const forms = document.querySelectorAll(\".formulation\");\r\n\r\n for (const form of forms) {\r\n const hiddenButton: HTMLElement = form.querySelector(\".qtext\");\r\n\r\n if (config.cursor) hiddenButton.style.cursor = \"pointer\";\r\n\r\n const injectionFunction = reply.bind(\r\n null,\r\n config,\r\n hiddenButton,\r\n form,\r\n query\r\n );\r\n listeners.push({ element: hiddenButton, fn: injectionFunction });\r\n hiddenButton.addEventListener(\"click\", injectionFunction);\r\n }\r\n\r\n if (config.title) titleIndications(\"Injected\");\r\n}\r\n\r\n/**\r\n * Remove the event listener on a specific question\r\n * @param element\r\n */\r\nfunction removeListener(element: HTMLElement) {\r\n const index = listeners.findIndex((listener) => listener.element === element);\r\n if (index !== -1) {\r\n const listener = listeners.splice(index, 1)[0];\r\n listener.element.removeEventListener(\"click\", listener.fn);\r\n }\r\n}\r\n\r\nexport { codeListener, removeListener };\r\n","import { codeListener } from \"./core/code-listener\";\r\n\r\nchrome.storage.sync.get([\"moodleGPT\"]).then(function (storage) {\r\n const config = storage.moodleGPT;\r\n\r\n if (!config) throw new Error(\"Please configure MoodleGPT into the extension\");\r\n\r\n codeListener(config);\r\n});\r\n"],"names":["titleIndications","text","backTitle","document","title","setTimeout","__awaiter","thisArg","_arguments","P","generator","Promise","resolve","reject","fulfilled","value","step","next","e","rejected","result","done","then","apply","Logs","static","console","log","valide","css","arr","gptAnswer","response","normalizedResponse","normalizeText","toLowerCase","normalizedText","replace","trim","htmlTableToString","table","tab","lines","Array","from","querySelectorAll","maxColumnsLength","map","line","cellsContent","cell","index","content","_a","textContent","Math","max","length","push","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleRadioAndCheckbox","config","inputList","input","type","parentNode","includes","logs","responseTry","mouseover","addEventListener","checked","once","handleSelect","tagName","correct","split","array","filter","answer","j","options","option","test","closest","querySelector","indexCorrectAnswer","findIndex","selected","handleTextbox","typing","event","key","preventDefault","slice","handleClipboard","navigator","clipboard","writeText","handleNumber","number","_b","match","handleContentEditable","getAttribute","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","reply","hiddenButton","form","query","cursor","style","question","questionContainer","innerText","accesshideElements","useless","tables","createQuestion","controller","AbortController","timeoutControler","abort","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","model","messages","role","temperature","top_p","presence_penalty","stop","clearTimeout","json","choices","message","getChatGPTResponse","catch","error","haveError","infinite","mode","removeListener","questionBackup","whiteSpace","isNotResponse","handlers","handler","pressedKeys","listeners","codeListener","code","listener","element","removeEventListener","fn","forms","injectionFunction","bind","setUpMoodleGpt","splice","chrome","storage","sync","get","moodleGPT","Error"],"mappings":"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","x_google_ignoreList":[1]}
\ No newline at end of file
diff --git a/extension/banner.png b/extension/banner.png
deleted file mode 100644
index 11f52e1..0000000
Binary files a/extension/banner.png and /dev/null differ
diff --git a/extension/manifest.json b/extension/manifest.json
index 5b20387..511db99 100644
--- a/extension/manifest.json
+++ b/extension/manifest.json
@@ -1,9 +1,9 @@
{
"manifest_version": 3,
"name": "MoodleGPT",
- "version": "1.0.2",
+ "version": "1.0.3",
"description": "Hidden chat-gpt for your moodle quiz",
- "permissions": ["activeTab", "tabs", "storage"],
+ "permissions": ["storage"],
"action": {
"default_icon": "icon.png",
"default_popup": "./popup/index.html"
diff --git a/extension/popup/index.html b/extension/popup/index.html
index 412168f..caa943c 100644
--- a/extension/popup/index.html
+++ b/extension/popup/index.html
@@ -19,16 +19,18 @@
-
-