From 8dffb127a513238c19c0f83af12c80218a9ebf5b Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 21 Jun 2023 21:24:46 -0400 Subject: [PATCH 01/87] Update TODO.md --- TODO.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index 0ba115e..98d2cbe 100644 --- a/TODO.md +++ b/TODO.md @@ -3,7 +3,7 @@ ## Priority: 1 - [ ] Fixe put in order -- [ ] Make some tests +- [ ] Option to remove `code` ## Priority: 2 From bc21f665f4285bc75ce6690fbdc595df4c75675d Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Fri, 15 Sep 2023 12:13:55 -0400 Subject: [PATCH 02/87] chrome type update --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0e25c09..908c232 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ }, "homepage": "https://github.com/yoannchb-pro/MoodleGPT#readme", "devDependencies": { - "@types/chrome": "^0.0.224", "@rollup/plugin-terser": "^0.4.3", + "@types/chrome": "^0.0.246", "rollup": "^3.20.0", "rollup-plugin-ts": "^3.2.0", "typescript": "^5.0.2" From 9cc2e68d5c053978be57ea627c27b79a7c1c89a5 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Fri, 15 Sep 2023 12:15:28 -0400 Subject: [PATCH 03/87] Should fixe issue #9 --- extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- src/core/code-listener.ts | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index a44c165..c2cfa6e 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,2 +1,2 @@ -!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)}))})); +!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");if(!o)continue;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 e43d28b..49fad6d 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/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 +{"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 (!hiddenButton) continue;\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/src/core/code-listener.ts b/src/core/code-listener.ts index eb96584..8bbe4f4 100644 --- a/src/core/code-listener.ts +++ b/src/core/code-listener.ts @@ -50,6 +50,8 @@ function setUpMoodleGpt(config: Config) { for (const form of forms) { const hiddenButton: HTMLElement = form.querySelector(".qtext"); + if (!hiddenButton) continue; + if (config.cursor) hiddenButton.style.cursor = "pointer"; const injectionFunction = reply.bind( From 65731fb51b7a8f2128168cdf183cceb9bf022714 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:57:56 -0500 Subject: [PATCH 04/87] Seprated files and fixed button to get last chatgpt version --- extension/popup/index.html | 26 ++++++-- extension/popup/js/gptVersion.js | 49 ++++++++++++++ extension/popup/js/index.js | 104 +----------------------------- extension/popup/js/modeHandler.js | 45 +++++++++++++ extension/popup/js/utils.js | 16 +++++ extension/popup/js/version.js | 12 ++-- 6 files changed, 138 insertions(+), 114 deletions(-) create mode 100644 extension/popup/js/gptVersion.js create mode 100644 extension/popup/js/modeHandler.js create mode 100644 extension/popup/js/utils.js diff --git a/extension/popup/index.html b/extension/popup/index.html index caa943c..1c46e25 100644 --- a/extension/popup/index.html +++ b/extension/popup/index.html @@ -6,8 +6,15 @@ MoodleGPT + + + + + + + +
@@ -33,15 +41,15 @@
- +
- - -
-
- +
+
+ + +

Mode:

@@ -71,7 +83,7 @@

Settings:

-
+
diff --git a/extension/popup/js/gptVersion.js b/extension/popup/js/gptVersion.js new file mode 100644 index 0000000..6939351 --- /dev/null +++ b/extension/popup/js/gptVersion.js @@ -0,0 +1,49 @@ +"use strict"; + +/** + * Get the last ChatGPT version + */ +function getLastChatGPTVersion() { + const apiKeySelector = document.querySelector("#apiKey"); + const reloadModel = document.querySelector("#reloadModel"); + + let apiKey = apiKeySelector.value; + + // If the api key is set we enable the button to get the last chatgpt version + function checkFiledApiKey() { + if (apiKey) { + reloadModel.removeAttribute("disabled"); + reloadModel.setAttribute("title", "Get last ChatGPT version"); + return; + } + + reloadModel.setAttribute("disabled", true); + reloadModel.setAttribute("title", "Provide an api key first"); + } + checkFiledApiKey(); + + // Check if the api key is set + apiKeySelector.addEventListener("input", function () { + apiKey = apiKeySelector.value.trim(); + checkFiledApiKey(); + }); + + // Event listener to handle a click on the relaod icon button + reloadModel.addEventListener("click", async function () { + if (!apiKey) return; + + try { + const req = await fetch("https://api.openai.com/v1/models", { + headers: { + Authorization: `Bearer ${apiKey}`, + }, + }); + const rep = await req.json(); + const model = rep.data.find((model) => model.id.startsWith("gpt")); + document.querySelector("#model").value = model.id; + } catch (err) { + console.error(err); + showMessage("Failed to fetch last ChatGPT version"); + } + }); +} diff --git a/extension/popup/js/index.js b/extension/popup/js/index.js index 304002e..e4ee9c1 100644 --- a/extension/popup/js/index.js +++ b/extension/popup/js/index.js @@ -1,5 +1,4 @@ const saveBtn = document.querySelector(".save"); -const message = document.querySelector("#message"); /* inputs id */ const inputsText = ["apiKey", "code", "model"]; @@ -13,60 +12,6 @@ const inputsCheckbox = [ "timeout", ]; -const mode = document.querySelector("#mode"); -const modes = mode.querySelectorAll("button"); -let actualMode = "autocomplete"; -/* inputs id that need to be disabled for a specific mode */ -const disabledForThisMode = { - autocomplete: [], - clipboard: ["typing", "mouseover"], - "question-to-answer": ["typing", "infinite", "mouseover"], -}; - -/** - * Show message into the popup - * @param {string} messageTxt - * @param {boolean} valide - */ -function showMessage(messageTxt, valide) { - message.style.color = valide ? "limegreen" : "red"; - message.textContent = messageTxt; - message.style.display = "block"; - setTimeout(() => (message.style.display = "none"), 5000); -} - -/** - * Handle when a mode change to show specific input - */ -function handleModeChange() { - const needDisable = disabledForThisMode[actualMode]; - const dontNeedDisable = inputsCheckbox.filter( - (input) => !needDisable.includes(input) - ); - for (const id of needDisable) { - document.querySelector("#" + id).parentElement.style.display = "none"; - } - for (const id of dontNeedDisable) { - document.querySelector("#" + id).parentElement.style.display = null; - } -} - -/* Mode handler */ -modes.forEach((button) => { - button.addEventListener("click", function () { - const value = button.value; - actualMode = value; - for (const mode of modes) { - if (mode.value !== value) { - mode.classList.add("not-selected"); - } else { - mode.classList.remove("not-selected"); - } - } - handleModeChange(); - }); -}); - /* Save the configuration */ saveBtn.addEventListener("click", function () { const [apiKey, code, model] = inputsText.map((selector) => @@ -78,12 +23,12 @@ saveBtn.addEventListener("click", function () { return element.checked && element.parentElement.style.display !== "none"; }); - if (!apiKey || !code || !model) { + if (!apiKey || !model) { showMessage("Please complete all the form"); return; } - if (code.length < 3) { + if (code.length > 0 && code.length < 3) { showMessage("The code should at least contain 3 characters"); return; } @@ -107,51 +52,6 @@ saveBtn.addEventListener("click", function () { showMessage("Configuration saved", true); }); -/** - * Get the last ChatGPT version - */ -function getLastChatGPTVersion() { - const apiKeySelector = document.querySelector("#apiKey"); - const reloadModel = document.querySelector("#reloadModel"); - - let apiKey = apiKeySelector.value; - - function checkFiledApiKey() { - if (apiKey) { - reloadModel.removeAttribute("disabled"); - reloadModel.setAttribute("title", "Get last ChatGPT version"); - return; - } - - reloadModel.setAttribute("disabled", true); - reloadModel.setAttribute("title", "Provide an api key first"); - } - - checkFiledApiKey(); - - apiKeySelector.addEventListener("input", function () { - apiKey = apiKeySelector.value.trim(); - checkFiledApiKey(); - }); - - reloadModel.addEventListener("click", async function () { - if (!apiKey) return; - try { - const req = await fetch("https://api.openai.com/v1/models", { - headers: { - Authorization: `Bearer ${apiKey}`, - }, - }); - const rep = await req.json(); - const model = rep.data.find((model) => model.id.includes("gpt")); - document.querySelector("#model").value = model.root; - } catch (err) { - console.error(err); - showMessage("Failed to fetch last ChatGPT version"); - } - }); -} - /* we load back the configuration */ chrome.storage.sync.get(["moodleGPT"]).then(function (storage) { const config = storage.moodleGPT; diff --git a/extension/popup/js/modeHandler.js b/extension/popup/js/modeHandler.js new file mode 100644 index 0000000..705dd5f --- /dev/null +++ b/extension/popup/js/modeHandler.js @@ -0,0 +1,45 @@ +"use strict"; + +const mode = document.querySelector("#mode"); +const modes = mode.querySelectorAll("button"); + +let actualMode = "autocomplete"; + +/* inputs id that need to be disabled for a specific mode */ +const disabledForThisMode = { + autocomplete: [], + clipboard: ["typing", "mouseover"], + "question-to-answer": ["typing", "infinite", "mouseover"], +}; + +/** + * Handle when a mode change to show specific input or to hide them + */ +function handleModeChange() { + const needDisable = disabledForThisMode[actualMode]; + const dontNeedDisable = inputsCheckbox.filter( + (input) => !needDisable.includes(input) + ); + for (const id of needDisable) { + document.querySelector("#" + id).parentElement.style.display = "none"; + } + for (const id of dontNeedDisable) { + document.querySelector("#" + id).parentElement.style.display = null; + } +} + +/* Mode handler */ +for (const button of modes) { + button.addEventListener("click", function () { + const value = button.value; + actualMode = value; + for (const mode of modes) { + if (mode.value !== value) { + mode.classList.add("not-selected"); + } else { + mode.classList.remove("not-selected"); + } + } + handleModeChange(); + }); +} diff --git a/extension/popup/js/utils.js b/extension/popup/js/utils.js new file mode 100644 index 0000000..821646d --- /dev/null +++ b/extension/popup/js/utils.js @@ -0,0 +1,16 @@ +"use strict"; + +const message = document.querySelector("#message"); + +/** + * Show message into the popup + * @param {string} messageTxt + * @param {boolean} valide + * @param {boolean} infinite + */ +function showMessage(messageTxt, valide, infinite) { + message.style.color = valide ? "limegreen" : "red"; + message.textContent = messageTxt; + message.style.display = "block"; + if (!infinite) setTimeout(() => (message.style.display = "none"), 5000); +} diff --git a/extension/popup/js/version.js b/extension/popup/js/version.js index dd745a7..3f5ee5b 100644 --- a/extension/popup/js/version.js +++ b/extension/popup/js/version.js @@ -1,4 +1,6 @@ -const currentVersion = "1.0.3"; +"use strict"; + +const CURRENT_VERSION = "1.0.4"; const versionDisplay = document.querySelector("#version"); /** @@ -35,16 +37,16 @@ function setVersion(version, isCurrent = true) { } /** - * Check the extension neeed an update or no + * Check if the extension neeed an update or not */ async function notifyUpdate() { const lastVersion = await getLastVersion().catch((err) => { console.error(err); - return currentVersion; + return CURRENT_VERSION; }); const lastVertionSplitted = lastVersion.split("."); - const currentVersionSplitted = currentVersion.split("."); + const currentVersionSplitted = CURRENT_VERSION.split("."); const minVersionLength = Math.min( lastVertionSplitted.length, currentVersionSplitted.length @@ -55,7 +57,7 @@ async function notifyUpdate() { return setVersion(lastVersion, false); } - setVersion(currentVersion); + setVersion(CURRENT_VERSION); } notifyUpdate(); From 5826cd35c87de985a4d69bf0175a216b0a3e15de Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:58:16 -0500 Subject: [PATCH 05/87] v1.0.4 --- CHANGELOG.md | 6 ++++++ README.md | 4 ++-- extension/manifest.json | 2 +- package.json | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2581e32..bfb5c78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## v1.0.4 + +- Code is not required anymore +- Issue [#9](https://github.com/yoannchb-pro/MoodleGPT/issues/9) resolved +- GPT version button fixed + ## v1.0.3 - Removed the option `table formating` because it will now set to true by default diff --git a/README.md b/README.md index d27055c..7b6d42d 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" >Mortarboard icons created by itim2101 - Flaticon

-# MoodleGPT v1.0.3 +# MoodleGPT 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,7 +12,7 @@ Find the extension on the Chrome Webstore right [here](https://chrome.google.com ## Summary -- [MoodleGPT v1.0.3](#moodlegpt-v103) +- [MoodleGPT](#moodlegpt) - [Chrome Webstore](#chrome-webstore) - [Summary](#summary) - [Disclaimer !](#disclaimer-) diff --git a/extension/manifest.json b/extension/manifest.json index 511db99..7053f8a 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "MoodleGPT", - "version": "1.0.3", + "version": "1.0.4", "description": "Hidden chat-gpt for your moodle quiz", "permissions": ["storage"], "action": { diff --git a/package.json b/package.json index 908c232..8c6d1ae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "moodlegpt", - "version": "1.0.3", + "version": "1.0.4", "description": "This extension allows you to hide CHAT-GPT in a Moodle quiz.", "scripts": { "build": "rollup -c" From b41ec54a82a0805d737fa97e6eb1a63196eda528 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:58:50 -0500 Subject: [PATCH 06/87] The code is not required anymore --- extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- src/core/code-listener.ts | 10 ++++++---- src/index.ts | 11 ++++++++--- src/types/config.ts | 2 +- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index c2cfa6e..4c35cf5 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,2 +1,2 @@ -!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");if(!o)continue;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)}))})); +!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())}))}"function"==typeof SuppressedError&&SuppressedError;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,p,f){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,p),y=p.querySelectorAll(f),g=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 g&&"error"in g;if(e.cursor&&(d.style.cursor=e.infinite||v?"pointer":"initial"),v)return void console.error(g.error);if(e.logs&&(n.question(h),n.response(g)),"clipboard"===e.mode)return e.infinite||m(d),c(e,g);if("question-to-answer"===e.mode){m(d);const e=p.querySelector(".qtext"),t=e.textContent;return e.textContent=g.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?g.response:t}))}e.infinite||m(d);const w=[u,l,a,i,s];for(const t of w)if(t(e,y,g))return;c(e,g)}))}const p=[],f=[];function h(t){if(f.length>0){for(const e of f)t.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return t.title&&e("Removed"),void(f.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");if(!o)continue;t.cursor&&(o.style.cursor="pointer");const r=d.bind(null,t,o,e,n);f.push({element:o,fn:r}),o.addEventListener("click",r)}t.title&&e("Injected")}function m(e){const t=f.findIndex((t=>t.element===e));if(-1!==t){const e=f.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");t.code?function(e){document.body.addEventListener("keydown",(function(t){p.push(t.key),p.length>e.code.length&&p.shift(),p.join("")===e.code&&(p.length=0,h(e))}))}(t):h(t)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index 49fad6d..3f1abdc 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/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 (!hiddenButton) continue;\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 +{"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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\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\ntype Listener = {\r\n element: HTMLElement;\r\n fn: (this: HTMLElement, ev: MouseEvent) => any;\r\n};\r\n\r\nconst pressedKeys: string[] = [];\r\nconst listeners: Listener[] = [];\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 (!hiddenButton) continue;\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, setUpMoodleGpt };\r\n","import { codeListener, setUpMoodleGpt } from \"./core/code-listener\";\r\nimport type Config from \"./types/config\";\r\n\r\nchrome.storage.sync.get([\"moodleGPT\"]).then(function (storage) {\r\n const config: Config = storage.moodleGPT;\r\n\r\n if (!config) throw new Error(\"Please configure MoodleGPT into the extension\");\r\n\r\n if (config.code) {\r\n codeListener(config);\r\n } else {\r\n setUpMoodleGpt(config);\r\n }\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","SuppressedError","Logs","question","console","log","responseTry","valide","css","array","arr","response","gptAnswer","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","mouseover","addEventListener","checked","once","handleSelect","tagName","correct","split","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","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","setUpMoodleGpt","listener","element","removeEventListener","fn","forms","injectionFunction","bind","splice","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file diff --git a/src/core/code-listener.ts b/src/core/code-listener.ts index 8bbe4f4..a635cb9 100644 --- a/src/core/code-listener.ts +++ b/src/core/code-listener.ts @@ -2,11 +2,13 @@ import Config from "../types/config"; import titleIndications from "../utils/title-indications"; import reply from "./reply"; -const pressedKeys: string[] = []; -const listeners: { +type Listener = { element: HTMLElement; fn: (this: HTMLElement, ev: MouseEvent) => any; -}[] = []; +}; + +const pressedKeys: string[] = []; +const listeners: Listener[] = []; /** * Create a listener on the keyboard to inject the code @@ -80,4 +82,4 @@ function removeListener(element: HTMLElement) { } } -export { codeListener, removeListener }; +export { codeListener, removeListener, setUpMoodleGpt }; diff --git a/src/index.ts b/src/index.ts index fe3c403..93409fc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,14 @@ -import { codeListener } from "./core/code-listener"; +import { codeListener, setUpMoodleGpt } from "./core/code-listener"; +import type Config from "./types/config"; chrome.storage.sync.get(["moodleGPT"]).then(function (storage) { - const config = storage.moodleGPT; + const config: Config = storage.moodleGPT; if (!config) throw new Error("Please configure MoodleGPT into the extension"); - codeListener(config); + if (config.code) { + codeListener(config); + } else { + setUpMoodleGpt(config); + } }); diff --git a/src/types/config.ts b/src/types/config.ts index c2d101f..b252f39 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -1,6 +1,6 @@ type Config = { apiKey: string; - code: string; + code?: string; model?: string; infinite?: boolean; typing?: boolean; From 1d3583fe0f65f4f1b9481cf2a94c4e8862f4a773 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:58:59 -0500 Subject: [PATCH 07/87] required fields style --- extension/popup/style.css | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/extension/popup/style.css b/extension/popup/style.css index 93df10a..1629eae 100644 --- a/extension/popup/style.css +++ b/extension/popup/style.css @@ -57,10 +57,16 @@ a { } .line .textLabel { - width: 6rem; + width: 5rem; + text-align: left; text-transform: uppercase; } +.line .textLabel .required { + color: var(--btn-color); + font-weight: bold; +} + .line input[type="text"], .line input[type="password"] { flex: 1 1; From 90bc94343a50ad769d8e6174dd12bfe677a78297 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 8 Jan 2024 16:13:22 -0500 Subject: [PATCH 08/87] better import with alias for paths --- extension/MoodleGPT.js.map | 2 +- src/core/code-listener.ts | 4 ++-- src/core/create-question.ts | 6 +++--- src/core/get-response.ts | 6 +++--- src/core/questions/clipboard.ts | 6 +++--- src/core/questions/contenteditable.ts | 4 ++-- src/core/questions/number.ts | 4 ++-- src/core/questions/radio-checkbox.ts | 8 ++++---- src/core/questions/select.ts | 8 ++++---- src/core/questions/textbox.ts | 4 ++-- src/core/reply.ts | 4 ++-- src/index.ts | 2 +- src/utils/logs.ts | 3 ++- tsconfig.json | 11 +++++++++-- 14 files changed, 40 insertions(+), 32 deletions(-) diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index 3f1abdc..72557cd 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/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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\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\ntype Listener = {\r\n element: HTMLElement;\r\n fn: (this: HTMLElement, ev: MouseEvent) => any;\r\n};\r\n\r\nconst pressedKeys: string[] = [];\r\nconst listeners: Listener[] = [];\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 (!hiddenButton) continue;\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, setUpMoodleGpt };\r\n","import { codeListener, setUpMoodleGpt } from \"./core/code-listener\";\r\nimport type Config from \"./types/config\";\r\n\r\nchrome.storage.sync.get([\"moodleGPT\"]).then(function (storage) {\r\n const config: Config = storage.moodleGPT;\r\n\r\n if (!config) throw new Error(\"Please configure MoodleGPT into the extension\");\r\n\r\n if (config.code) {\r\n codeListener(config);\r\n } else {\r\n setUpMoodleGpt(config);\r\n }\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","SuppressedError","Logs","question","console","log","responseTry","valide","css","array","arr","response","gptAnswer","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","mouseover","addEventListener","checked","once","handleSelect","tagName","correct","split","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","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","setUpMoodleGpt","listener","element","removeEventListener","fn","forms","injectionFunction","bind","splice","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file +{"version":3,"file":"MoodleGPT.js","sources":["../src/utils/title-indications.ts","../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","import GPTAnswer from \"@typing/gptAnswer\";\r\n\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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/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 type Config from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport titleIndications from \"@utils/title-indications\";\r\nimport reply from \"./reply\";\r\n\r\ntype Listener = {\r\n element: HTMLElement;\r\n fn: (this: HTMLElement, ev: MouseEvent) => any;\r\n};\r\n\r\nconst pressedKeys: string[] = [];\r\nconst listeners: Listener[] = [];\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 (!hiddenButton) continue;\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, setUpMoodleGpt };\r\n","import type Config from \"@typing/config\";\r\nimport { codeListener, setUpMoodleGpt } from \"./core/code-listener\";\r\n\r\nchrome.storage.sync.get([\"moodleGPT\"]).then(function (storage) {\r\n const config: Config = storage.moodleGPT;\r\n\r\n if (!config) throw new Error(\"Please configure MoodleGPT into the extension\");\r\n\r\n if (config.code) {\r\n codeListener(config);\r\n } else {\r\n setUpMoodleGpt(config);\r\n }\r\n});\r\n"],"names":["titleIndications","text","backTitle","document","title","setTimeout","Logs","question","console","log","responseTry","valide","css","array","arr","response","gptAnswer","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","mouseover","addEventListener","checked","once","handleSelect","tagName","correct","split","filter","answer","j","options","option","test","closest","querySelector","indexCorrectAnswer","findIndex","selected","handleTextbox","typing","event","key","preventDefault","value","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","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","setUpMoodleGpt","listener","element","removeEventListener","fn","e","forms","injectionFunction","bind","splice","chrome","storage","sync","get","then","moodleGPT","Error","code","codeListener"],"mappings":"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"} \ No newline at end of file diff --git a/src/core/code-listener.ts b/src/core/code-listener.ts index a635cb9..ed4ced2 100644 --- a/src/core/code-listener.ts +++ b/src/core/code-listener.ts @@ -1,5 +1,5 @@ -import Config from "../types/config"; -import titleIndications from "../utils/title-indications"; +import type Config from "@typing/config"; +import titleIndications from "@utils/title-indications"; import reply from "./reply"; type Listener = { diff --git a/src/core/create-question.ts b/src/core/create-question.ts index d94abf0..9dee9f8 100644 --- a/src/core/create-question.ts +++ b/src/core/create-question.ts @@ -1,6 +1,6 @@ -import Config from "../types/config"; -import normalizeText from "../utils/normalize-text"; -import htmlTableToString from "../utils/html-table-to-string"; +import type Config from "@typing/config"; +import normalizeText from "@utils/normalize-text"; +import htmlTableToString from "@utils/html-table-to-string"; /** * Normalize the question and add sub informations diff --git a/src/core/get-response.ts b/src/core/get-response.ts index d5dcc7b..c94009b 100644 --- a/src/core/get-response.ts +++ b/src/core/get-response.ts @@ -1,6 +1,6 @@ -import Config from "../types/config"; -import GPTAnswer from "../types/gptAnswer"; -import normalizeText from "../utils/normalize-text"; +import type Config from "@typing/config"; +import type GPTAnswer from "@typing/gptAnswer"; +import normalizeText from "@utils/normalize-text"; /** * Get the response from chatGPT api diff --git a/src/core/questions/clipboard.ts b/src/core/questions/clipboard.ts index 563bbe5..c661953 100644 --- a/src/core/questions/clipboard.ts +++ b/src/core/questions/clipboard.ts @@ -1,6 +1,6 @@ -import Config from "../../types/config"; -import GPTAnswer from "../../types/gptAnswer"; -import titleIndications from "../../utils/title-indications"; +import type Config from "@typing/config"; +import type GPTAnswer from "@typing/gptAnswer"; +import titleIndications from "@utils/title-indications"; /** * Copy the response in the clipboard if we can automaticaly fill the question diff --git a/src/core/questions/contenteditable.ts b/src/core/questions/contenteditable.ts index ea8b661..1f3174b 100644 --- a/src/core/questions/contenteditable.ts +++ b/src/core/questions/contenteditable.ts @@ -1,5 +1,5 @@ -import Config from "../../types/config"; -import GPTAnswer from "../../types/gptAnswer"; +import type Config from "@typing/config"; +import type GPTAnswer from "@typing/gptAnswer"; /** * Hanlde contenteditable elements diff --git a/src/core/questions/number.ts b/src/core/questions/number.ts index 3171928..3d49d11 100644 --- a/src/core/questions/number.ts +++ b/src/core/questions/number.ts @@ -1,5 +1,5 @@ -import Config from "../../types/config"; -import GPTAnswer from "../../types/gptAnswer"; +import type Config from "@typing/config"; +import type GPTAnswer from "@typing/gptAnswer"; /** * Handle number input diff --git a/src/core/questions/radio-checkbox.ts b/src/core/questions/radio-checkbox.ts index ea9de1f..14a6909 100644 --- a/src/core/questions/radio-checkbox.ts +++ b/src/core/questions/radio-checkbox.ts @@ -1,7 +1,7 @@ -import Config from "../../types/config"; -import GPTAnswer from "../../types/gptAnswer"; -import Logs from "../../utils/logs"; -import normalizeText from "../../utils/normalize-text"; +import type Config from "@typing/config"; +import type GPTAnswer from "@typing/gptAnswer"; +import Logs from "@utils/logs"; +import normalizeText from "@utils/normalize-text"; /** * Handle checkbox and input elements diff --git a/src/core/questions/select.ts b/src/core/questions/select.ts index 0ebcbb2..c4c94cc 100644 --- a/src/core/questions/select.ts +++ b/src/core/questions/select.ts @@ -1,7 +1,7 @@ -import Config from "../../types/config"; -import GPTAnswer from "../../types/gptAnswer"; -import Logs from "../../utils/logs"; -import normalizeText from "../../utils/normalize-text"; +import type Config from "@typing/config"; +import type GPTAnswer from "@typing/gptAnswer"; +import Logs from "@utils/logs"; +import normalizeText from "@utils/normalize-text"; /** * Handle select elements (and put in order select) diff --git a/src/core/questions/textbox.ts b/src/core/questions/textbox.ts index 8712b45..ddbb4a8 100644 --- a/src/core/questions/textbox.ts +++ b/src/core/questions/textbox.ts @@ -1,5 +1,5 @@ -import Config from "../../types/config"; -import GPTAnswer from "../../types/gptAnswer"; +import type Config from "@typing/config"; +import type GPTAnswer from "@typing/gptAnswer"; /** * Handle textbox diff --git a/src/core/reply.ts b/src/core/reply.ts index 44ae04b..b598977 100644 --- a/src/core/reply.ts +++ b/src/core/reply.ts @@ -1,5 +1,5 @@ -import Config from "../types/config"; -import Logs from "../utils/logs"; +import type Config from "@typing/config"; +import Logs from "@utils/logs"; import getChatGPTResponse from "./get-response"; import createQuestion from "./create-question"; import handleRadioAndCheckbox from "./questions/radio-checkbox"; diff --git a/src/index.ts b/src/index.ts index 93409fc..804df57 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ +import type Config from "@typing/config"; import { codeListener, setUpMoodleGpt } from "./core/code-listener"; -import type Config from "./types/config"; chrome.storage.sync.get(["moodleGPT"]).then(function (storage) { const config: Config = storage.moodleGPT; diff --git a/src/utils/logs.ts b/src/utils/logs.ts index 41cacde..5648f5b 100644 --- a/src/utils/logs.ts +++ b/src/utils/logs.ts @@ -1,4 +1,5 @@ -import GPTAnswer from "../types/gptAnswer"; +import GPTAnswer from "@typing/gptAnswer"; + class Logs { static question(text: string) { const css = "color: cyan"; diff --git a/tsconfig.json b/tsconfig.json index c7d476b..ebef21a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "baseUrl": "src", "module": "CommonJS", "esModuleInterop": true, "allowSyntheticDefaultImports": true, @@ -10,7 +11,13 @@ "outDir": "extension", "resolveJsonModule": true, "types": ["node", "chrome"], - "typeRoots": ["node_modules/@types"] + "typeRoots": ["node_modules/@types"], + "paths": { + "@typing/*": ["types/*"], + "@utils/*": ["utils/*"], + "@core/*": ["core/*"], + "@questions/*": ["core/question/*"] + } }, - "include": ["src/**/*"] + "include": ["**/*"] } From ea4c9f04355e6c1dfa6549a6741f007093487d65 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:22:59 -0500 Subject: [PATCH 09/87] Added test --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7b6d42d..af44f4a 100644 --- a/README.md +++ b/README.md @@ -163,4 +163,5 @@ 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/fake-moodle" folder. Or a better solution is to install moodle locally. +- Solution 1: Go on [this moodle test page](https://school.moodledemo.net/login/index.php) (username: `student`, password: `moodle`) and choose any quiz. +- Solution 2: Run the `index.html` file located in the `test/fake-moodle` folder. From a3fa1fd8342fdf4cb2b9f9ecda0dfed7933ba700 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:23:09 -0500 Subject: [PATCH 10/87] eslint and prettier --- package.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 8c6d1ae..24603de 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,9 @@ "version": "1.0.4", "description": "This extension allows you to hide CHAT-GPT in a Moodle quiz.", "scripts": { - "build": "rollup -c" + "build": "rollup -c", + "lint": "eslint . --ext .ts", + "prettier": "prettier --write ." }, "repository": { "type": "git", @@ -25,6 +27,11 @@ "devDependencies": { "@rollup/plugin-terser": "^0.4.3", "@types/chrome": "^0.0.246", + "@typescript-eslint/eslint-plugin": "^7.1.0", + "@typescript-eslint/parser": "^7.1.0", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "prettier": "^3.2.5", "rollup": "^3.20.0", "rollup-plugin-ts": "^3.2.0", "typescript": "^5.0.2" From dc298f338a69fdab7e5e6f0a183aebcfdf86fa47 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:23:17 -0500 Subject: [PATCH 11/87] eslint configuration --- .eslintrc.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..39f743d --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,18 @@ +module.exports = { + root: true, + parser: "@typescript-eslint/parser", + plugins: ["@typescript-eslint"], + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "prettier", + ], + ignorePatterns: ["node_modules/"], + overrides: [ + { + files: ["extension/popup/*.js", "src/**/*.ts"], + rules: {}, + }, + ], +}; From 21058fd4632298fdf1e8d44965f545b3a67b4aea Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:23:25 -0500 Subject: [PATCH 12/87] git hooks --- .githooks/pre-commit | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .githooks/pre-commit diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100644 index 0000000..3e0eb2c --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,3 @@ +#!/bin/bash +npm run prettier +npm run lint \ No newline at end of file From 40af472af43f0e001fe6ba803da9751b2a16173b Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:23:33 -0500 Subject: [PATCH 13/87] md templates --- .github/ISSUE_TEMPLATE/BUG_REPORT.md | 28 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/FEATURE_REQUEST.md | 16 +++++++++++++ .github/pull_request_template.md | 28 +++++++++++++++++++++++ CONTRIBUTE.md | 3 +++ 4 files changed, 75 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/BUG_REPORT.md create mode 100644 .github/ISSUE_TEMPLATE/FEATURE_REQUEST.md create mode 100644 .github/pull_request_template.md create mode 100644 CONTRIBUTE.md diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.md b/.github/ISSUE_TEMPLATE/BUG_REPORT.md new file mode 100644 index 0000000..bda7baf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.md @@ -0,0 +1,28 @@ +## Bug Report + +**Description of the Bug** +A clear and concise description of the bug. + +**Steps to Reproduce** + +1. Step 1 +2. Step 2 +3. ... + +**Expected Behavior** +A clear and concise description of what you expected to happen. + +**Actual Behavior** +A clear and concise description of what actually happens. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Tried Solutions** +Have you tried anything to solve the problem? If yes, what? + +**Additional Context** +Add any other context about the problem here. + +**Additional Information** +Add any other information you think is relevant. diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md new file mode 100644 index 0000000..3a24437 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md @@ -0,0 +1,16 @@ +## Feature Request + +**Description of the Feature** +A clear and concise description of the feature you'd like to see added. + +**Motivation** +An explanation of the motivation behind this feature. How would it improve the user experience or utility of the software? + +**Screenshot (Optional)** +If possible, add a screenshot or illustration of the feature you're proposing. + +**Additional Context** +Add any other context or information about the feature that you think is relevant. + +**Additional Information** +Add any other information you think is relevant. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..1849f5e --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,28 @@ +## Pull Request + +**Description** +A brief description of the changes in this pull request. + +**Related Issue** + +- Fixes # (issue number) +- Addresses # (issue number) + +**Changes Made** +Describe the changes you've made. Provide a high-level overview of what has been done in this pull request. + +**Screenshots (if applicable)** +Add screenshots or GIFs to demonstrate the changes, if applicable. + +**Checklist** + +- [ ] I have tested the changes locally. +- [ ] I have updated the documentation accordingly. +- [ ] I have added necessary comments to the code. +- [ ] All tests pass successfully. + +**Additional Notes** +Add any additional notes or comments about the pull request here. + +**Reviewer(s)** +@username1, @username2 diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md new file mode 100644 index 0000000..cf7d5a3 --- /dev/null +++ b/CONTRIBUTE.md @@ -0,0 +1,3 @@ +# CONTRIBUTE + +`git config --local core.hooksPath .githooks/` From 44706e5c3337081c22c695336a56193122dee8ef Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:24:02 -0500 Subject: [PATCH 14/87] v1.0.4 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfb5c78..4569ccc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ - Code is not required anymore - Issue [#9](https://github.com/yoannchb-pro/MoodleGPT/issues/9) resolved - GPT version button fixed +- Better algo to find the correct answer +- Better chatGPT prompt +- Added `history` to the configuration ## v1.0.3 From 3ee84f0b31334f5adaef56a935da8ef47cb085b5 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:24:11 -0500 Subject: [PATCH 15/87] build --- extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index 4c35cf5..f5cd786 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,2 +1,2 @@ -!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())}))}"function"==typeof SuppressedError&&SuppressedError;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,p,f){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,p),y=p.querySelectorAll(f),g=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 g&&"error"in g;if(e.cursor&&(d.style.cursor=e.infinite||v?"pointer":"initial"),v)return void console.error(g.error);if(e.logs&&(n.question(h),n.response(g)),"clipboard"===e.mode)return e.infinite||m(d),c(e,g);if("question-to-answer"===e.mode){m(d);const e=p.querySelector(".qtext"),t=e.textContent;return e.textContent=g.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?g.response:t}))}e.infinite||m(d);const w=[u,l,a,i,s];for(const t of w)if(t(e,y,g))return;c(e,g)}))}const p=[],f=[];function h(t){if(f.length>0){for(const e of f)t.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return t.title&&e("Removed"),void(f.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");if(!o)continue;t.cursor&&(o.style.cursor="pointer");const r=d.bind(null,t,o,e,n);f.push({element:o,fn:r}),o.addEventListener("click",r)}t.title&&e("Injected")}function m(e){const t=f.findIndex((t=>t.element===e));if(-1!==t){const e=f.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");t.code?function(e){document.body.addEventListener("keydown",(function(t){p.push(t.key),p.length>e.code.length&&p.shift(),p.join("")===e.code&&(p.length=0,h(e))}))}(t):h(t)}))})); +!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){return n&&(e=e.toLowerCase()),e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={}));const l="\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),c={url:null,system:{role:s.SYSTEM,content:l},history:[]};function a(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function u(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function f(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function d(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,\.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function m(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function p(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function h(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function g(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function v(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+a(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),l=yield function(e,t){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&c.url===n||(c.url=n,c.history=[]);const o=new AbortController,r=setTimeout((()=>o.abort()),15e3),l={role:s.USER,content:t},a=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?o.signal:null,body:JSON.stringify({model:e.model,messages:[c.system,...c.history,l],temperature:.8,top_p:1,presence_penalty:1,stop:null})});clearTimeout(r);const u=(yield a.json()).choices[0].message.content;return e.history&&(c.history.push(l),c.history.push({role:s.ASSISTANT,content:u})),{question:t,response:u,normalizedResponse:i(u)}}))}(e.config,t).catch((e=>({error:e}))),v="object"==typeof l&&"error"in l;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||v?"pointer":"initial"),v)console.error(l.error);else switch(e.config.logs&&(r.question(t),r.response(l)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),u(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:l,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap",n.addEventListener("click",(function(){n.style.whiteSpace="",n.textContent=t}))}({gptAnswer:l,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[f,g,d,h,m,p];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;u(e.config,e.gptAnswer)}({config:e.config,gptAnswer:l,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const y=[],w=[];function A(e){const n=w.findIndex((n=>n.element===e));if(-1!==n){const e=w.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function E(n){if(w.length>0){for(const e of w)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(w.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=v.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>A(o)});w.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){y.push(n.key),y.length>e.code.length&&y.shift(),y.join("")===e.code&&(y.length=0,E(e))}))}(n):E(n)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index 72557cd..3d3eac4 100644 --- a/extension/MoodleGPT.js.map +++ b/extension/MoodleGPT.js.map @@ -1 +1 @@ -{"version":3,"file":"MoodleGPT.js","sources":["../src/utils/title-indications.ts","../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","import GPTAnswer from \"@typing/gptAnswer\";\r\n\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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/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 type Config from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport titleIndications from \"@utils/title-indications\";\r\nimport reply from \"./reply\";\r\n\r\ntype Listener = {\r\n element: HTMLElement;\r\n fn: (this: HTMLElement, ev: MouseEvent) => any;\r\n};\r\n\r\nconst pressedKeys: string[] = [];\r\nconst listeners: Listener[] = [];\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 (!hiddenButton) continue;\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, setUpMoodleGpt };\r\n","import type Config from \"@typing/config\";\r\nimport { codeListener, setUpMoodleGpt } from \"./core/code-listener\";\r\n\r\nchrome.storage.sync.get([\"moodleGPT\"]).then(function (storage) {\r\n const config: Config = storage.moodleGPT;\r\n\r\n if (!config) throw new Error(\"Please configure MoodleGPT into the extension\");\r\n\r\n if (config.code) {\r\n codeListener(config);\r\n } else {\r\n setUpMoodleGpt(config);\r\n }\r\n});\r\n"],"names":["titleIndications","text","backTitle","document","title","setTimeout","Logs","question","console","log","responseTry","valide","css","array","arr","response","gptAnswer","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","mouseover","addEventListener","checked","once","handleSelect","tagName","correct","split","filter","answer","j","options","option","test","closest","querySelector","indexCorrectAnswer","findIndex","selected","handleTextbox","typing","event","key","preventDefault","value","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","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","setUpMoodleGpt","listener","element","removeEventListener","fn","e","forms","injectionFunction","bind","splice","chrome","storage","sync","get","then","moodleGPT","Error","code","codeListener"],"mappings":"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"} \ 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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/core/get-response.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\r\n similarity: number;\r\n value: string | null;\r\n element: HTMLElement | null;\r\n};\r\n\r\ntype ResponsesBySimilarity = {\r\n similarity: number;\r\n value: string;\r\n element: HTMLElement;\r\n};\r\n\r\n/**\r\n * Calculate the levenshtein distance between two sentence\r\n * @param str1\r\n * @param str2\r\n * @returns\r\n */\r\nfunction levenshteinDistance(str1: string, str2: string) {\r\n if (str1.length === 0) return str2.length;\r\n if (str2.length === 0) return str1.length;\r\n\r\n const matrix: number[][] = [];\r\n const str1WithoutSpaces = str1.replace(/\\s+/, \"\");\r\n const str2WithoutSpaces = str2.replace(/\\s+/, \"\");\r\n\r\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\r\n matrix.push([i]);\r\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\r\n matrix[i][j] =\r\n i === 0\r\n ? j\r\n : Math.min(\r\n matrix[i - 1][j] + 1,\r\n matrix[i][j - 1] + 1,\r\n matrix[i - 1][j - 1] +\r\n (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\r\n );\r\n }\r\n }\r\n\r\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\r\n}\r\n\r\n/**\r\n * Calculate the similarity between two sentences from 0 to 1 (best)\r\n * @param str1\r\n * @param str2\r\n * @returns\r\n */\r\nfunction sentenceSimilarity(str1: string, str2: string) {\r\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\r\n if (longerLength === 0) return 1;\r\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\r\n}\r\n\r\n/**\r\n * Pick the best sentence that correspond to the answer\r\n * @param arr\r\n * @param answer\r\n * @returns\r\n */\r\nexport function pickBestReponse(\r\n answer: string,\r\n arr: { element: HTMLElement; value: string }[]\r\n): BestResponse {\r\n let bestResponse: BestResponse = {\r\n element: null,\r\n similarity: 0,\r\n value: null,\r\n };\r\n for (const obj of arr) {\r\n const similarity = sentenceSimilarity(obj.value, answer);\r\n if (similarity === 1) {\r\n return { element: obj.element, value: obj.value, similarity };\r\n }\r\n if (similarity > bestResponse.similarity) {\r\n bestResponse = { element: obj.element, value: obj.value, similarity };\r\n }\r\n }\r\n return bestResponse;\r\n}\r\n\r\n/**\r\n * Return the sentences sorted by score with a score superior or equal to what is asked\r\n * @param answer\r\n * @param arr\r\n * @param score\r\n * @returns\r\n */\r\nexport function pickResponsesWithSimilarityGreaterThan(\r\n answer: string,\r\n arr: { element: HTMLElement; value: string }[],\r\n score: number\r\n): ResponsesBySimilarity[] {\r\n const responses: ResponsesBySimilarity[] = [];\r\n for (const obj of arr) {\r\n const similarity = sentenceSimilarity(obj.value, answer);\r\n if (similarity >= score)\r\n responses.push({\r\n similarity,\r\n value: obj.value,\r\n element: obj.element,\r\n });\r\n }\r\n return responses.sort((a, b) => a.similarity - b.similarity);\r\n}\r\n\r\n/**\r\n * Convert a number to a readable string pourcentage\r\n * @param similarity\r\n */\r\nexport function toPourcentage(similarity: number): string {\r\n return Math.round(similarity * 100 * 100) / 100 + \"%\";\r\n}\r\n","import GPTAnswer from \"@typing/gptAnswer\";\r\nimport { toPourcentage } from \"./pick-best-response\";\r\n\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 bestAnswer(answer: string, similarity: number) {\r\n const css = \"color: green\";\r\n console.log(\r\n \"%c[BEST ANSWER]: %s\",\r\n css,\r\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\r\n );\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 if (toLowerCase) text = text.toLowerCase();\r\n\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 space from textcontent\r\n .replace(/[ \\t]+/gi, \" \") //replace multiples space or tabs by a space\r\n .trim()\r\n // We remove the following content 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 return normalizedText;\r\n}\r\n\r\nexport default normalizeText;\r\n","import type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/gptAnswer\";\r\nimport normalizeText from \"@utils/normalize-text\";\r\n\r\ntype History = {\r\n url: string | null;\r\n system: { role: ROLE; content: string };\r\n history: { role: ROLE; content: string }[];\r\n};\r\n\r\nenum ROLE {\r\n SYSTEM = \"system\",\r\n USER = \"user\",\r\n ASSISTANT = \"assistant\",\r\n}\r\n\r\nconst INSTRUCTION: string = `\r\nAct as a quiz solver for the best notation with the following rules:\r\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\r\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\r\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\r\n- Always reply in the format: '\\n\\n...'.\r\n- Retain only the correct answer(s).\r\n- Maintain the same order for the answers as in the text.\r\n- Retain all text from the answer with its description, content or definition.\r\n- Only provide answers that exactly match the given answer in the text.\r\n- The question always has the correct answer(s), so you should always provide an answer.\r\n- Always respond in the same language as the user's question.\r\n`.trim();\r\n\r\nconst history: History = {\r\n url: null,\r\n system: {\r\n role: ROLE.SYSTEM,\r\n content: INSTRUCTION,\r\n },\r\n history: [],\r\n};\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 URL = location.hostname + location.pathname;\r\n\r\n // We reset the history when we enter a new moodle quiz or when it's desactivate\r\n if (!config.history || history.url !== URL) {\r\n history.url = URL;\r\n history.history = [];\r\n }\r\n\r\n const controller = new AbortController();\r\n const timeoutControler = setTimeout(() => controller.abort(), 15 * 1000);\r\n\r\n const message = { role: ROLE.USER, content: question };\r\n\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: [history.system, ...history.history, message],\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\r\n clearTimeout(timeoutControler);\r\n\r\n const rep = await req.json();\r\n const response = rep.choices[0].message.content;\r\n\r\n // Register the conversation\r\n if (config.history) {\r\n history.history.push(message);\r\n history.history.push({ role: ROLE.ASSISTANT, content: response });\r\n }\r\n\r\n return {\r\n question,\r\n response,\r\n normalizedResponse: normalizeText(response),\r\n };\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((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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 || // for now we don't handle many input for editable textcontent\r\n input.getAttribute(\"contenteditable\") !== \"true\"\r\n ) {\r\n return false;\r\n }\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 if (selection !== null) {\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n }\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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 (\r\n inputList.length !== 1 || // for now we don't handle many input number\r\n input.type !== \"number\"\r\n ) {\r\n return false;\r\n }\r\n\r\n const number = gptAnswer.normalizedResponse\r\n .match(/\\d+([,\\.]\\d+)?/gi)?.[0]\r\n ?.replace(\",\", \".\");\r\n\r\n if (number === undefined) return false;\r\n\r\n if (config.typing) {\r\n let index = 0;\r\n input.addEventListener(\"keydown\", function (event: Event) {\r\n event.preventDefault();\r\n if ((event).key === \"Backspace\") index = number.length + 1;\r\n if (index > number.length) return;\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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/gptAnswer\";\r\nimport Logs from \"@utils/logs\";\r\nimport normalizeText from \"@utils/normalize-text\";\r\nimport { pickBestReponse, toPourcentage } from \"@utils/pick-best-response\";\r\n\r\n/**\r\n * Handle input radio elements\r\n * @param config\r\n * @param inputList\r\n * @param gptAnswer\r\n */\r\nfunction handleRadio(\r\n config: Config,\r\n inputList: NodeListOf,\r\n gptAnswer: GPTAnswer\r\n): boolean {\r\n const firstInput = inputList?.[0] as HTMLInputElement;\r\n\r\n // Handle the case the input is not a radio\r\n if (!firstInput || firstInput.type !== \"radio\") {\r\n return false;\r\n }\r\n\r\n const possibleAnswers = Array.from(inputList)\r\n .map((inp) => ({\r\n element: inp,\r\n value: normalizeText(inp?.parentElement?.textContent ?? \"\"),\r\n }))\r\n .filter((obj) => obj.value !== \"\");\r\n\r\n const bestAnswer = pickBestReponse(\r\n gptAnswer.normalizedResponse,\r\n possibleAnswers\r\n );\r\n\r\n if (config.logs && bestAnswer.value) {\r\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\r\n }\r\n\r\n const correctInput = bestAnswer.element as HTMLInputElement;\r\n if (config.mouseover) {\r\n correctInput.addEventListener(\r\n \"mouseover\",\r\n () => (correctInput.checked = true),\r\n {\r\n once: true,\r\n }\r\n );\r\n } else {\r\n correctInput.checked = true;\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleRadio;\r\n","import type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/gptAnswer\";\r\nimport Logs from \"@utils/logs\";\r\nimport normalizeText from \"@utils/normalize-text\";\r\nimport { pickBestReponse, toPourcentage } from \"@utils/pick-best-response\";\r\n\r\n/**\r\n * Handle input checkbox elements\r\n * @param config\r\n * @param inputList\r\n * @param gptAnswer\r\n */\r\nfunction handleCheckbox(\r\n config: Config,\r\n inputList: NodeListOf,\r\n gptAnswer: GPTAnswer\r\n): boolean {\r\n const firstInput = inputList?.[0] as HTMLInputElement;\r\n\r\n // Handle the case the input is not a checkbox\r\n if (!firstInput || firstInput.type !== \"checkbox\") {\r\n return false;\r\n }\r\n\r\n const corrects = gptAnswer.normalizedResponse.split(\"\\n\");\r\n\r\n const possibleAnswers = Array.from(inputList)\r\n .map((inp) => ({\r\n element: inp,\r\n value: normalizeText(inp?.parentElement?.textContent ?? \"\"),\r\n }))\r\n .filter((obj) => obj.value !== \"\");\r\n\r\n for (const correct of corrects) {\r\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\r\n\r\n if (config.logs && bestAnswer.value) {\r\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\r\n }\r\n\r\n const correctInput = bestAnswer.element as HTMLInputElement;\r\n if (config.mouseover) {\r\n correctInput.addEventListener(\r\n \"mouseover\",\r\n () => (correctInput.checked = true),\r\n {\r\n once: true,\r\n }\r\n );\r\n } else {\r\n correctInput.checked = true;\r\n }\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleCheckbox;\r\n","import type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/gptAnswer\";\r\nimport Logs from \"@utils/logs\";\r\nimport normalizeText from \"@utils/normalize-text\";\r\nimport { pickBestReponse, toPourcentage } from \"@utils/pick-best-response\";\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 const corrects = gptAnswer.normalizedResponse.split(\"\\n\");\r\n\r\n if (config.logs) Logs.array(corrects);\r\n\r\n for (let i = 0; i < inputList.length; ++i) {\r\n if (!corrects[i]) break;\r\n\r\n const options = inputList[i].querySelectorAll(\"option\");\r\n\r\n const possibleAnswers = Array.from(options)\r\n .map((opt) => ({\r\n element: opt,\r\n value: normalizeText(opt.textContent ?? \"\"),\r\n }))\r\n .filter((obj) => obj.value !== \"\");\r\n\r\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\r\n\r\n if (config.logs && bestAnswer.value) {\r\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\r\n }\r\n\r\n const correctOption = bestAnswer.element as HTMLOptionElement;\r\n const currentSelect = correctOption.closest(\"select\");\r\n\r\n if (currentSelect === null) continue;\r\n\r\n if (config.mouseover) {\r\n currentSelect.addEventListener(\r\n \"click\",\r\n () => (correctOption.selected = true),\r\n {\r\n once: true,\r\n }\r\n );\r\n } else {\r\n correctOption.selected = true;\r\n }\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleSelect;\r\n","import type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 || // for now we don't handle many input text\r\n (input.tagName !== \"TEXTAREA\" && input.type !== \"text\")\r\n ) {\r\n return false;\r\n }\r\n\r\n if (config.typing) {\r\n let index = 0;\r\n input.addEventListener(\"keydown\", function (event: Event) {\r\n event.preventDefault();\r\n if ((event).key === \"Backspace\") {\r\n index = gptAnswer.response.length + 1;\r\n }\r\n if (index > gptAnswer.response.length) return;\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 type Config from \"@typing/config\";\r\nimport Logs from \"@utils/logs\";\r\nimport getChatGPTResponse from \"./get-response\";\r\nimport createAndNormalizeQuestion from \"./create-question\";\r\nimport clipboardMode from \"./modes/clipboard\";\r\nimport questionToAnswerMode from \"./modes/question-to-answer\";\r\nimport autoCompleteMode from \"./modes/autocomplete\";\r\n\r\ntype Props = {\r\n config: Config;\r\n questionElement: HTMLElement;\r\n form: HTMLElement;\r\n inputQuery: string;\r\n removeListener: () => void;\r\n};\r\n\r\n/**\r\n * Reply to the question\r\n * @param props\r\n * @returns\r\n */\r\nasync function reply(props: Props): Promise {\r\n if (props.config.cursor) props.questionElement.style.cursor = \"wait\";\r\n\r\n const question = createAndNormalizeQuestion(props.form);\r\n const inputList: NodeListOf = props.form.querySelectorAll(\r\n props.inputQuery\r\n );\r\n\r\n const gptAnswer = await getChatGPTResponse(props.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 (props.config.cursor) {\r\n props.questionElement.style.cursor =\r\n props.config.infinite || haveError ? \"pointer\" : \"initial\";\r\n }\r\n\r\n if (haveError) {\r\n console.error(gptAnswer.error);\r\n return;\r\n }\r\n\r\n if (props.config.logs) {\r\n Logs.question(question);\r\n Logs.response(gptAnswer);\r\n }\r\n\r\n switch (props.config.mode) {\r\n case \"clipboard\":\r\n clipboardMode({\r\n config: props.config,\r\n questionElement: props.questionElement,\r\n gptAnswer,\r\n removeListener: props.removeListener,\r\n });\r\n break;\r\n case \"question-to-answer\":\r\n questionToAnswerMode({\r\n gptAnswer,\r\n questionElement: props.questionElement,\r\n removeListener: props.removeListener,\r\n });\r\n break;\r\n case \"autocomplete\":\r\n autoCompleteMode({\r\n config: props.config,\r\n gptAnswer,\r\n inputList,\r\n questionElement: props.questionElement,\r\n removeListener: props.removeListener,\r\n });\r\n break;\r\n }\r\n}\r\n\r\nexport default reply;\r\n","import normalizeText from \"@utils/normalize-text\";\r\nimport htmlTableToString from \"@utils/html-table-to-string\";\r\n\r\n/**\r\n * Normalize the question as text and add sub informations\r\n * @param langage\r\n * @param question\r\n * @returns\r\n */\r\nfunction createAndNormalizeQuestion(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 createAndNormalizeQuestion;\r\n","import type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/gptAnswer\";\r\nimport handleClipboard from \"@core/questions/clipboard\";\r\n\r\ntype Props = {\r\n config: Config;\r\n questionElement: HTMLElement;\r\n gptAnswer: GPTAnswer;\r\n removeListener: () => void;\r\n};\r\n\r\n/**\r\n * Clipboard mode:\r\n * Simply copy the answer into the clipboard\r\n * @param props\r\n */\r\nfunction clipboardMode(props: Props) {\r\n if (!props.config.infinite) props.removeListener();\r\n handleClipboard(props.config, props.gptAnswer);\r\n}\r\n\r\nexport default clipboardMode;\r\n","import type GPTAnswer from \"@typing/gptAnswer\";\r\n\r\ntype Props = {\r\n questionElement: HTMLElement;\r\n gptAnswer: GPTAnswer;\r\n removeListener: () => void;\r\n};\r\n\r\n/**\r\n * Question to answer mode:\r\n * Simply turn the question into the answer by clicking on it\r\n * @param props\r\n */\r\nfunction questionToAnswerMode(props: Props) {\r\n const questionElement = props.questionElement;\r\n\r\n props.removeListener();\r\n\r\n const questionBackup = questionElement.textContent;\r\n\r\n questionElement.textContent = props.gptAnswer.response;\r\n\r\n // Format the content\r\n questionElement.style.whiteSpace = \"pre-wrap\";\r\n\r\n // To go back to the question / answer\r\n let contentIsResponse = true;\r\n questionElement.addEventListener(\"click\", function () {\r\n questionElement.style.whiteSpace = contentIsResponse ? \"\" : \"pre-warp\";\r\n questionElement.textContent = contentIsResponse\r\n ? questionBackup\r\n : props.gptAnswer.response;\r\n });\r\n}\r\n\r\nexport default questionToAnswerMode;\r\n","import type GPTAnswer from \"@typing/gptAnswer\";\r\nimport type Config from \"@typing/config\";\r\nimport handleClipboard from \"@core/questions/clipboard\";\r\nimport handleContentEditable from \"@core/questions/contenteditable\";\r\nimport handleNumber from \"@core/questions/number\";\r\nimport handleRadio from \"@core/questions/radio\";\r\nimport handleCheckbox from \"@core/questions/checkbox\";\r\nimport handleSelect from \"@core/questions/select\";\r\nimport handleTextbox from \"@core/questions/textbox\";\r\n\r\ntype Props = {\r\n config: Config;\r\n questionElement: HTMLElement;\r\n inputList: NodeListOf;\r\n gptAnswer: GPTAnswer;\r\n removeListener: () => void;\r\n};\r\n\r\n/**\r\n * Autocomplete mode:\r\n * Autocomplete the question by checking the good answer\r\n * @param props\r\n * @returns\r\n */\r\nfunction autoCompleteMode(props: Props) {\r\n if (!props.config.infinite) props.removeListener();\r\n\r\n const handlers = [\r\n handleContentEditable,\r\n handleTextbox,\r\n handleNumber,\r\n handleSelect,\r\n handleRadio,\r\n handleCheckbox,\r\n ];\r\n\r\n for (const handler of handlers) {\r\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\r\n }\r\n\r\n // In the case we can't auto complete the question\r\n handleClipboard(props.config, props.gptAnswer);\r\n}\r\n\r\nexport default autoCompleteMode;\r\n","import type Config from \"@typing/config\";\r\nimport titleIndications from \"@utils/title-indications\";\r\nimport reply from \"./reply\";\r\n\r\ntype Listener = {\r\n element: HTMLElement;\r\n fn: (this: HTMLElement, ev: MouseEvent) => any;\r\n};\r\n\r\nconst pressedKeys: string[] = [];\r\nconst listeners: Listener[] = [];\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 * 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\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 if there are already declared\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 // Query to find inputs and forms\r\n const inputTypeQuery = [\"checkbox\", \"radio\", \"text\", \"number\"]\r\n .map((e) => `input[type=\"${e}\"]`)\r\n .join(\",\");\r\n const inputQuery = inputTypeQuery + \", textarea, select, [contenteditable]\";\r\n const forms = document.querySelectorAll(\".formulation\");\r\n\r\n // For each form we inject a function on the queqtion\r\n for (const form of forms) {\r\n const questionElement: HTMLElement | null = form.querySelector(\".qtext\");\r\n\r\n if (questionElement === null) continue;\r\n\r\n if (config.cursor) questionElement.style.cursor = \"pointer\";\r\n\r\n const injectionFunction = reply.bind(null, {\r\n config,\r\n questionElement,\r\n form: form as HTMLElement,\r\n inputQuery,\r\n removeListener: () => removeListener(questionElement),\r\n });\r\n\r\n listeners.push({ element: questionElement, fn: injectionFunction });\r\n questionElement.addEventListener(\"click\", injectionFunction);\r\n }\r\n\r\n if (config.title) titleIndications(\"Injected\");\r\n}\r\n\r\nexport { codeListener, removeListener, setUpMoodleGpt };\r\n","import type Config from \"@typing/config\";\r\nimport { codeListener, setUpMoodleGpt } from \"./core/code-listener\";\r\n\r\nchrome.storage.sync.get([\"moodleGPT\"]).then(function (storage) {\r\n const config: Config = storage.moodleGPT;\r\n\r\n if (!config) throw new Error(\"Please configure MoodleGPT into the extension\");\r\n\r\n if (config.code) {\r\n codeListener(config);\r\n } else {\r\n setUpMoodleGpt(config);\r\n }\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","INSTRUCTION","history","url","system","role","SYSTEM","content","htmlTableToString","table","tab","lines","Array","from","querySelectorAll","maxColumnsLength","map","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","config","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","type","number","_b","match","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","filter","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","questionElement","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","model","messages","temperature","top_p","presence_penalty","stop","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","error","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file From b4372ca422f6c12a305215dbdf43f824b8e487ad Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:24:26 -0500 Subject: [PATCH 16/87] refactoring and added history --- extension/popup/index.html | 4 ++++ extension/popup/js/gptVersion.js | 2 +- extension/popup/js/index.js | 13 +++++++++---- extension/popup/js/utils.js | 12 ++++-------- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/extension/popup/index.html b/extension/popup/index.html index 1c46e25..0494b8c 100644 --- a/extension/popup/index.html +++ b/extension/popup/index.html @@ -115,6 +115,10 @@
+
+ + +

Message

diff --git a/extension/popup/js/gptVersion.js b/extension/popup/js/gptVersion.js index 6939351..312df3e 100644 --- a/extension/popup/js/gptVersion.js +++ b/extension/popup/js/gptVersion.js @@ -43,7 +43,7 @@ function getLastChatGPTVersion() { document.querySelector("#model").value = model.id; } catch (err) { console.error(err); - showMessage("Failed to fetch last ChatGPT version"); + showMessage({ msg: "Failed to fetch last ChatGPT version", error: true }); } }); } diff --git a/extension/popup/js/index.js b/extension/popup/js/index.js index e4ee9c1..421f95f 100644 --- a/extension/popup/js/index.js +++ b/extension/popup/js/index.js @@ -10,6 +10,7 @@ const inputsCheckbox = [ "mouseover", "infinite", "timeout", + "history", ]; /* Save the configuration */ @@ -17,19 +18,22 @@ saveBtn.addEventListener("click", function () { const [apiKey, code, model] = inputsText.map((selector) => document.querySelector("#" + selector).value.trim() ); - const [logs, title, cursor, typing, mouseover, infinite, timeout] = + const [logs, title, cursor, typing, mouseover, infinite, timeout, history] = inputsCheckbox.map((selector) => { const element = document.querySelector("#" + selector); return element.checked && element.parentElement.style.display !== "none"; }); if (!apiKey || !model) { - showMessage("Please complete all the form"); + showMessage({ msg: "Please complete all the form", error: true }); return; } if (code.length > 0 && code.length < 3) { - showMessage("The code should at least contain 3 characters"); + showMessage({ + msg: "The code should at least contain 3 characters", + error: true, + }); return; } @@ -45,11 +49,12 @@ saveBtn.addEventListener("click", function () { mouseover, infinite, timeout, + history, mode: actualMode, }, }); - showMessage("Configuration saved", true); + showMessage({ msg: "Configuration saved" }); }); /* we load back the configuration */ diff --git a/extension/popup/js/utils.js b/extension/popup/js/utils.js index 821646d..5b69d3a 100644 --- a/extension/popup/js/utils.js +++ b/extension/popup/js/utils.js @@ -1,16 +1,12 @@ "use strict"; -const message = document.querySelector("#message"); - /** * Show message into the popup - * @param {string} messageTxt - * @param {boolean} valide - * @param {boolean} infinite */ -function showMessage(messageTxt, valide, infinite) { - message.style.color = valide ? "limegreen" : "red"; - message.textContent = messageTxt; +function showMessage({ msg, error, infinite }) { + const message = document.querySelector("#message"); + message.style.color = error ? "red" : "limegreen"; + message.textContent = msg; message.style.display = "block"; if (!infinite) setTimeout(() => (message.style.display = "none"), 5000); } From 2ca0318c220c45fcab28963dd822403ca7f03a41 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:25:01 -0500 Subject: [PATCH 17/87] better algo, added history, fixed bugs and refactoring --- src/core/code-listener.ts | 94 ++++++++++---------- src/core/create-question.ts | 11 ++- src/core/get-response.ts | 76 +++++++++++++---- src/core/modes/autocomplete.ts | 45 ++++++++++ src/core/modes/clipboard.ts | 22 +++++ src/core/modes/question-to-answer.ts | 36 ++++++++ src/core/questions/checkbox.ts | 58 +++++++++++++ src/core/questions/contenteditable.ts | 13 +-- src/core/questions/number.ts | 15 ++-- src/core/questions/radio-checkbox.ts | 39 --------- src/core/questions/radio.ts | 57 +++++++++++++ src/core/questions/select.ts | 97 +++++++-------------- src/core/questions/textbox.ts | 13 +-- src/core/reply.ts | 118 +++++++++++--------------- src/types/config.ts | 1 + src/types/gptAnswer.ts | 1 + src/utils/html-table-to-string.ts | 6 +- src/utils/logs.ts | 11 ++- src/utils/normalize-text.ts | 20 ++--- src/utils/pick-best-response.ts | 115 +++++++++++++++++++++++++ 20 files changed, 572 insertions(+), 276 deletions(-) create mode 100644 src/core/modes/autocomplete.ts create mode 100644 src/core/modes/clipboard.ts create mode 100644 src/core/modes/question-to-answer.ts create mode 100644 src/core/questions/checkbox.ts delete mode 100644 src/core/questions/radio-checkbox.ts create mode 100644 src/core/questions/radio.ts create mode 100644 src/utils/pick-best-response.ts diff --git a/src/core/code-listener.ts b/src/core/code-listener.ts index ed4ced2..896dab3 100644 --- a/src/core/code-listener.ts +++ b/src/core/code-listener.ts @@ -17,7 +17,7 @@ const listeners: Listener[] = []; function codeListener(config: Config) { document.body.addEventListener("keydown", function (event) { pressedKeys.push(event.key); - if (pressedKeys.length > config.code.length) pressedKeys.shift(); + if (pressedKeys.length > config.code!.length) pressedKeys.shift(); if (pressedKeys.join("") === config.code) { pressedKeys.length = 0; setUpMoodleGpt(config); @@ -25,51 +25,6 @@ function codeListener(config: Config) { }); } -/** - * Setup moodleGPT into the page (remove/injection) - * @param config - * @returns - */ -function setUpMoodleGpt(config: 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; - } - - /* Code injection */ - const inputQuery = ["checkbox", "radio", "text", "number"] - .map((e) => `input[type="${e}"]`) - .join(","); - const query = inputQuery + ", textarea, select, [contenteditable]"; - const forms = document.querySelectorAll(".formulation"); - - for (const form of forms) { - const hiddenButton: HTMLElement = form.querySelector(".qtext"); - - if (!hiddenButton) continue; - - if (config.cursor) hiddenButton.style.cursor = "pointer"; - - const injectionFunction = reply.bind( - null, - config, - hiddenButton, - form, - query - ); - listeners.push({ element: hiddenButton, fn: injectionFunction }); - hiddenButton.addEventListener("click", injectionFunction); - } - - if (config.title) titleIndications("Injected"); -} - /** * Remove the event listener on a specific question * @param element @@ -82,4 +37,51 @@ function removeListener(element: HTMLElement) { } } +/** + * Setup moodleGPT into the page (remove/injection) + * @param config + * @returns + */ +function setUpMoodleGpt(config: Config) { + // Removing events if there are already declared + 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; + } + + // Query to find inputs and forms + const inputTypeQuery = ["checkbox", "radio", "text", "number"] + .map((e) => `input[type="${e}"]`) + .join(","); + const inputQuery = inputTypeQuery + ", textarea, select, [contenteditable]"; + const forms = document.querySelectorAll(".formulation"); + + // For each form we inject a function on the queqtion + for (const form of forms) { + const questionElement: HTMLElement | null = form.querySelector(".qtext"); + + if (questionElement === null) continue; + + if (config.cursor) questionElement.style.cursor = "pointer"; + + const injectionFunction = reply.bind(null, { + config, + questionElement, + form: form as HTMLElement, + inputQuery, + removeListener: () => removeListener(questionElement), + }); + + listeners.push({ element: questionElement, fn: injectionFunction }); + questionElement.addEventListener("click", injectionFunction); + } + + if (config.title) titleIndications("Injected"); +} + export { codeListener, removeListener, setUpMoodleGpt }; diff --git a/src/core/create-question.ts b/src/core/create-question.ts index 9dee9f8..fbd68a5 100644 --- a/src/core/create-question.ts +++ b/src/core/create-question.ts @@ -1,24 +1,23 @@ -import type Config from "@typing/config"; import normalizeText from "@utils/normalize-text"; import htmlTableToString from "@utils/html-table-to-string"; /** - * Normalize the question and add sub informations + * Normalize the question as text and add sub informations * @param langage * @param question * @returns */ -function createQuestion(config: Config, questionContainer: HTMLElement) { +function createAndNormalizeQuestion(questionContainer: HTMLElement) { let question = questionContainer.innerText; - /* We remove unnecessary information */ + // We remove unnecessary information const accesshideElements: NodeListOf = questionContainer.querySelectorAll(".accesshide"); for (const useless of accesshideElements) { question = question.replace(useless.innerText, ""); } - /* Make tables more readable for chat-gpt */ + // Make tables more readable for chat-gpt const tables: NodeListOf = questionContainer.querySelectorAll(".qtext table"); for (const table of tables) { @@ -31,4 +30,4 @@ function createQuestion(config: Config, questionContainer: HTMLElement) { return normalizeText(question, false); } -export default createQuestion; +export default createAndNormalizeQuestion; diff --git a/src/core/get-response.ts b/src/core/get-response.ts index c94009b..007e154 100644 --- a/src/core/get-response.ts +++ b/src/core/get-response.ts @@ -2,6 +2,41 @@ import type Config from "@typing/config"; import type GPTAnswer from "@typing/gptAnswer"; import normalizeText from "@utils/normalize-text"; +type History = { + url: string | null; + system: { role: ROLE; content: string }; + history: { role: ROLE; content: string }[]; +}; + +enum ROLE { + SYSTEM = "system", + USER = "user", + ASSISTANT = "assistant", +} + +const INSTRUCTION: string = ` +Act as a quiz solver for the best notation with the following rules: +- When asked for the result of an equation, provide only the result without any other information and skip the other rules. +- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. +- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...' +- Always reply in the format: '\n\n...'. +- Retain only the correct answer(s). +- Maintain the same order for the answers as in the text. +- Retain all text from the answer with its description, content or definition. +- Only provide answers that exactly match the given answer in the text. +- The question always has the correct answer(s), so you should always provide an answer. +- Always respond in the same language as the user's question. +`.trim(); + +const history: History = { + url: null, + system: { + role: ROLE.SYSTEM, + content: INSTRUCTION, + }, + history: [], +}; + /** * Get the response from chatGPT api * @param config @@ -12,8 +47,19 @@ async function getChatGPTResponse( config: Config, question: string ): Promise { + const URL = location.hostname + location.pathname; + + // We reset the history when we enter a new moodle quiz or when it's desactivate + if (!config.history || history.url !== URL) { + history.url = URL; + history.history = []; + } + const controller = new AbortController(); - const timeoutControler = setTimeout(() => controller.abort(), 15000); + const timeoutControler = setTimeout(() => controller.abort(), 15 * 1000); + + const message = { role: ROLE.USER, content: question }; + const req = await fetch("https://api.openai.com/v1/chat/completions", { method: "POST", headers: { @@ -23,33 +69,27 @@ async function getChatGPTResponse( signal: config.timeout ? controller.signal : null, body: JSON.stringify({ model: config.model, - messages: [ - { - role: "system", - content: ` -Follow those rules: -- 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. -- For put in order question just give the good order separate by new line -- Your goal is to understand the statement and to reply to each question by giving only the answer. -- You will keep the same order for the answers like in the text. -- You will separate all the answer with new lines and only show the correctes one. -- You will only give the answers for each question and omit the questions, statement, title or other informations from the response. -- You will only give answer with exactly the same text as the gived answers. -- The question always have the good answer so you should always give an answer to the question. -- You will always respond in the same langage as the user question.`, - }, - { role: "user", content: question }, - ], + messages: [history.system, ...history.history, message], temperature: 0.8, top_p: 1.0, presence_penalty: 1.0, stop: null, }), }); + clearTimeout(timeoutControler); + const rep = await req.json(); const response = rep.choices[0].message.content; + + // Register the conversation + if (config.history) { + history.history.push(message); + history.history.push({ role: ROLE.ASSISTANT, content: response }); + } + return { + question, response, normalizedResponse: normalizeText(response), }; diff --git a/src/core/modes/autocomplete.ts b/src/core/modes/autocomplete.ts new file mode 100644 index 0000000..d3f384a --- /dev/null +++ b/src/core/modes/autocomplete.ts @@ -0,0 +1,45 @@ +import type GPTAnswer from "@typing/gptAnswer"; +import type Config from "@typing/config"; +import handleClipboard from "@core/questions/clipboard"; +import handleContentEditable from "@core/questions/contenteditable"; +import handleNumber from "@core/questions/number"; +import handleRadio from "@core/questions/radio"; +import handleCheckbox from "@core/questions/checkbox"; +import handleSelect from "@core/questions/select"; +import handleTextbox from "@core/questions/textbox"; + +type Props = { + config: Config; + questionElement: HTMLElement; + inputList: NodeListOf; + gptAnswer: GPTAnswer; + removeListener: () => void; +}; + +/** + * Autocomplete mode: + * Autocomplete the question by checking the good answer + * @param props + * @returns + */ +function autoCompleteMode(props: Props) { + if (!props.config.infinite) props.removeListener(); + + const handlers = [ + handleContentEditable, + handleTextbox, + handleNumber, + handleSelect, + handleRadio, + handleCheckbox, + ]; + + for (const handler of handlers) { + if (handler(props.config, props.inputList, props.gptAnswer)) return; + } + + // In the case we can't auto complete the question + handleClipboard(props.config, props.gptAnswer); +} + +export default autoCompleteMode; diff --git a/src/core/modes/clipboard.ts b/src/core/modes/clipboard.ts new file mode 100644 index 0000000..0c37151 --- /dev/null +++ b/src/core/modes/clipboard.ts @@ -0,0 +1,22 @@ +import type Config from "@typing/config"; +import type GPTAnswer from "@typing/gptAnswer"; +import handleClipboard from "@core/questions/clipboard"; + +type Props = { + config: Config; + questionElement: HTMLElement; + gptAnswer: GPTAnswer; + removeListener: () => void; +}; + +/** + * Clipboard mode: + * Simply copy the answer into the clipboard + * @param props + */ +function clipboardMode(props: Props) { + if (!props.config.infinite) props.removeListener(); + handleClipboard(props.config, props.gptAnswer); +} + +export default clipboardMode; diff --git a/src/core/modes/question-to-answer.ts b/src/core/modes/question-to-answer.ts new file mode 100644 index 0000000..21bb904 --- /dev/null +++ b/src/core/modes/question-to-answer.ts @@ -0,0 +1,36 @@ +import type GPTAnswer from "@typing/gptAnswer"; + +type Props = { + questionElement: HTMLElement; + gptAnswer: GPTAnswer; + removeListener: () => void; +}; + +/** + * Question to answer mode: + * Simply turn the question into the answer by clicking on it + * @param props + */ +function questionToAnswerMode(props: Props) { + const questionElement = props.questionElement; + + props.removeListener(); + + const questionBackup = questionElement.textContent; + + questionElement.textContent = props.gptAnswer.response; + + // Format the content + questionElement.style.whiteSpace = "pre-wrap"; + + // To go back to the question / answer + let contentIsResponse = true; + questionElement.addEventListener("click", function () { + questionElement.style.whiteSpace = contentIsResponse ? "" : "pre-warp"; + questionElement.textContent = contentIsResponse + ? questionBackup + : props.gptAnswer.response; + }); +} + +export default questionToAnswerMode; diff --git a/src/core/questions/checkbox.ts b/src/core/questions/checkbox.ts new file mode 100644 index 0000000..ac2e152 --- /dev/null +++ b/src/core/questions/checkbox.ts @@ -0,0 +1,58 @@ +import type Config from "@typing/config"; +import type GPTAnswer from "@typing/gptAnswer"; +import Logs from "@utils/logs"; +import normalizeText from "@utils/normalize-text"; +import { pickBestReponse, toPourcentage } from "@utils/pick-best-response"; + +/** + * Handle input checkbox elements + * @param config + * @param inputList + * @param gptAnswer + */ +function handleCheckbox( + config: Config, + inputList: NodeListOf, + gptAnswer: GPTAnswer +): boolean { + const firstInput = inputList?.[0] as HTMLInputElement; + + // Handle the case the input is not a checkbox + if (!firstInput || firstInput.type !== "checkbox") { + return false; + } + + const corrects = gptAnswer.normalizedResponse.split("\n"); + + const possibleAnswers = Array.from(inputList) + .map((inp) => ({ + element: inp, + value: normalizeText(inp?.parentElement?.textContent ?? ""), + })) + .filter((obj) => obj.value !== ""); + + for (const correct of corrects) { + const bestAnswer = pickBestReponse(correct, possibleAnswers); + + if (config.logs && bestAnswer.value) { + Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity); + } + + const correctInput = bestAnswer.element as HTMLInputElement; + if (config.mouseover) { + correctInput.addEventListener( + "mouseover", + () => (correctInput.checked = true), + { + once: true, + } + ); + } else { + correctInput.checked = true; + } + } + + return true; +} + +export default handleCheckbox; diff --git a/src/core/questions/contenteditable.ts b/src/core/questions/contenteditable.ts index 1f3174b..742d68b 100644 --- a/src/core/questions/contenteditable.ts +++ b/src/core/questions/contenteditable.ts @@ -16,10 +16,11 @@ function handleContentEditable( const input = inputList[0]; if ( - inputList.length !== 1 || + inputList.length !== 1 || // for now we don't handle many input for editable textcontent input.getAttribute("contenteditable") !== "true" - ) + ) { return false; + } if (config.typing) { let index = 0; @@ -29,14 +30,16 @@ function handleContentEditable( event.preventDefault(); input.textContent = gptAnswer.response.slice(0, ++index); - /* Put the cursor at the end of the typed text */ + // Put the cursor at the end of the typed text input.focus(); const range = document.createRange(); range.selectNodeContents(input); range.collapse(false); const selection = window.getSelection(); - selection.removeAllRanges(); - selection.addRange(range); + if (selection !== null) { + selection.removeAllRanges(); + selection.addRange(range); + } }); } else { input.textContent = gptAnswer.response; diff --git a/src/core/questions/number.ts b/src/core/questions/number.ts index 3d49d11..d86d153 100644 --- a/src/core/questions/number.ts +++ b/src/core/questions/number.ts @@ -15,20 +15,25 @@ function handleNumber( ): boolean { const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement; - if (inputList.length !== 1 || input.type !== "number") return false; + if ( + inputList.length !== 1 || // for now we don't handle many input number + input.type !== "number" + ) { + return false; + } const number = gptAnswer.normalizedResponse .match(/\d+([,\.]\d+)?/gi)?.[0] ?.replace(",", "."); - if (!number) return false; + if (number === undefined) return false; if (config.typing) { let index = 0; - input.addEventListener("keydown", function (event: KeyboardEvent) { - if (event.key === "Backspace") index = number.length + 1; - if (index > number.length) return; + input.addEventListener("keydown", function (event: Event) { event.preventDefault(); + if ((event).key === "Backspace") index = number.length + 1; + if (index > number.length) return; if (number.slice(index, index + 1) === ".") ++index; input.value = number.slice(0, ++index); }); diff --git a/src/core/questions/radio-checkbox.ts b/src/core/questions/radio-checkbox.ts deleted file mode 100644 index 14a6909..0000000 --- a/src/core/questions/radio-checkbox.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type Config from "@typing/config"; -import type GPTAnswer from "@typing/gptAnswer"; -import Logs from "@utils/logs"; -import normalizeText from "@utils/normalize-text"; - -/** - * Handle checkbox and input elements - * @param config - * @param inputList - * @param gptAnswer - */ -function handleRadioAndCheckbox( - config: Config, - inputList: NodeListOf, - gptAnswer: GPTAnswer -): boolean { - const input = inputList?.[0] as HTMLInputElement; - - if (!input || (input.type !== "checkbox" && input.type !== "radio")) - return false; - - for (const input of inputList as NodeListOf) { - const content = normalizeText(input.parentNode.textContent); - const valide = gptAnswer.normalizedResponse.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; -} - -export default handleRadioAndCheckbox; diff --git a/src/core/questions/radio.ts b/src/core/questions/radio.ts new file mode 100644 index 0000000..ad8ab4f --- /dev/null +++ b/src/core/questions/radio.ts @@ -0,0 +1,57 @@ +import type Config from "@typing/config"; +import type GPTAnswer from "@typing/gptAnswer"; +import Logs from "@utils/logs"; +import normalizeText from "@utils/normalize-text"; +import { pickBestReponse, toPourcentage } from "@utils/pick-best-response"; + +/** + * Handle input radio elements + * @param config + * @param inputList + * @param gptAnswer + */ +function handleRadio( + config: Config, + inputList: NodeListOf, + gptAnswer: GPTAnswer +): boolean { + const firstInput = inputList?.[0] as HTMLInputElement; + + // Handle the case the input is not a radio + if (!firstInput || firstInput.type !== "radio") { + return false; + } + + const possibleAnswers = Array.from(inputList) + .map((inp) => ({ + element: inp, + value: normalizeText(inp?.parentElement?.textContent ?? ""), + })) + .filter((obj) => obj.value !== ""); + + const bestAnswer = pickBestReponse( + gptAnswer.normalizedResponse, + possibleAnswers + ); + + if (config.logs && bestAnswer.value) { + Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity); + } + + const correctInput = bestAnswer.element as HTMLInputElement; + if (config.mouseover) { + correctInput.addEventListener( + "mouseover", + () => (correctInput.checked = true), + { + once: true, + } + ); + } else { + correctInput.checked = true; + } + + return true; +} + +export default handleRadio; diff --git a/src/core/questions/select.ts b/src/core/questions/select.ts index c4c94cc..6c5c3b3 100644 --- a/src/core/questions/select.ts +++ b/src/core/questions/select.ts @@ -2,6 +2,7 @@ import type Config from "@typing/config"; import type GPTAnswer from "@typing/gptAnswer"; import Logs from "@utils/logs"; import normalizeText from "@utils/normalize-text"; +import { pickBestReponse, toPourcentage } from "@utils/pick-best-response"; /** * Handle select elements (and put in order select) @@ -17,81 +18,43 @@ function handleSelect( ): boolean { if (inputList.length === 0 || inputList[0].tagName !== "SELECT") return false; - let correct = gptAnswer.normalizedResponse.split("\n"); + const corrects = gptAnswer.normalizedResponse.split("\n"); - if (config.logs) Logs.array(correct); + if (config.logs) Logs.array(corrects); - /** - * Sometimes ChatGPT give the question so we should remove them - * Example: - * 5*5 - * 25 - * 10+10 - * 20 - * 20-10 - * 10 - * - * And we only want to keep answers - * 25 - * 20 - * 10 - */ - if (correct.length === inputList.length * 2) { - correct = correct.filter((answer, index) => index % 2 === 1); - } + for (let i = 0; i < inputList.length; ++i) { + if (!corrects[i]) break; - for (let j = 0; j < inputList.length; ++j) { - const options = inputList[j].querySelectorAll("option"); + const options = inputList[i].querySelectorAll("option"); - for (const option of options) { - const content = normalizeText(option.textContent); - const valide = correct[j].includes(content); + const possibleAnswers = Array.from(options) + .map((opt) => ({ + element: opt, + value: normalizeText(opt.textContent ?? ""), + })) + .filter((obj) => obj.value !== ""); - /* Handle put in order question */ - if (!/[^\d]+/gi.test(content)) { - const elementTitle = (option.parentNode as HTMLElement) - .closest("tr") - .querySelector(".text"); - const content = normalizeText(elementTitle.textContent); + const bestAnswer = pickBestReponse(corrects[i], possibleAnswers); - const indexCorrectAnswer = correct.findIndex((answer) => { - const valide = answer.includes(content); - if (config.logs) Logs.responseTry(content, valide); - return valide; - }); + if (config.logs && bestAnswer.value) { + Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity); + } - if (indexCorrectAnswer !== -1) { - //we do + 1 because we skip the first option: Choose... - if (config.mouseover) { - options[indexCorrectAnswer + 1].closest("select").addEventListener( - "click", - function () { - options[indexCorrectAnswer + 1].selected = "selected" as any; - }, - { once: true } - ); - } else { - options[indexCorrectAnswer + 1].selected = "selected" as any; - } - break; + const correctOption = bestAnswer.element as HTMLOptionElement; + const currentSelect = correctOption.closest("select"); + + if (currentSelect === null) continue; + + if (config.mouseover) { + currentSelect.addEventListener( + "click", + () => (correctOption.selected = true), + { + once: true, } - } - /* End */ - - 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; - } + ); + } else { + correctOption.selected = true; } } diff --git a/src/core/questions/textbox.ts b/src/core/questions/textbox.ts index ddbb4a8..b817fa0 100644 --- a/src/core/questions/textbox.ts +++ b/src/core/questions/textbox.ts @@ -16,17 +16,20 @@ function handleTextbox( const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement; if ( - inputList.length !== 1 || + inputList.length !== 1 || // for now we don't handle many input text (input.tagName !== "TEXTAREA" && input.type !== "text") - ) + ) { return false; + } if (config.typing) { let index = 0; - input.addEventListener("keydown", function (event: KeyboardEvent) { - if (event.key === "Backspace") index = gptAnswer.response.length + 1; - if (index > gptAnswer.response.length) return; + input.addEventListener("keydown", function (event: Event) { event.preventDefault(); + if ((event).key === "Backspace") { + index = gptAnswer.response.length + 1; + } + if (index > gptAnswer.response.length) return; input.value = gptAnswer.response.slice(0, ++index); }); } else { diff --git a/src/core/reply.ts b/src/core/reply.ts index b598977..f7aba91 100644 --- a/src/core/reply.ts +++ b/src/core/reply.ts @@ -1,35 +1,33 @@ import type Config from "@typing/config"; import Logs from "@utils/logs"; import getChatGPTResponse from "./get-response"; -import createQuestion from "./create-question"; -import handleRadioAndCheckbox from "./questions/radio-checkbox"; -import handleSelect from "./questions/select"; -import handleTextbox from "./questions/textbox"; -import handleClipboard from "./questions/clipboard"; -import handleNumber from "./questions/number"; -import handleContentEditable from "./questions/contenteditable"; -import { removeListener } from "./code-listener"; +import createAndNormalizeQuestion from "./create-question"; +import clipboardMode from "./modes/clipboard"; +import questionToAnswerMode from "./modes/question-to-answer"; +import autoCompleteMode from "./modes/autocomplete"; + +type Props = { + config: Config; + questionElement: HTMLElement; + form: HTMLElement; + inputQuery: string; + removeListener: () => void; +}; /** * Reply to the question - * @param config - * @param hiddenButton - * @param form - * @param query + * @param props * @returns */ -async function reply( - config: Config, - hiddenButton: HTMLElement, - form: HTMLElement, - query: string -) { - if (config.cursor) hiddenButton.style.cursor = "wait"; +async function reply(props: Props): Promise { + if (props.config.cursor) props.questionElement.style.cursor = "wait"; - const question = createQuestion(config, form); - const inputList: NodeListOf = form.querySelectorAll(query); + const question = createAndNormalizeQuestion(props.form); + const inputList: NodeListOf = props.form.querySelectorAll( + props.inputQuery + ); - const gptAnswer = await getChatGPTResponse(config, question).catch( + const gptAnswer = await getChatGPTResponse(props.config, question).catch( (error) => ({ error, }) @@ -37,63 +35,47 @@ async function reply( const haveError = typeof gptAnswer === "object" && "error" in gptAnswer; - if (config.cursor) - hiddenButton.style.cursor = - config.infinite || haveError ? "pointer" : "initial"; + if (props.config.cursor) { + props.questionElement.style.cursor = + props.config.infinite || haveError ? "pointer" : "initial"; + } if (haveError) { console.error(gptAnswer.error); return; } - if (config.logs) { + if (props.config.logs) { Logs.question(question); Logs.response(gptAnswer); } - /* Handle clipboard mode */ - if (config.mode === "clipboard") { - if (!config.infinite) removeListener(hiddenButton); - return handleClipboard(config, gptAnswer); + switch (props.config.mode) { + case "clipboard": + clipboardMode({ + config: props.config, + questionElement: props.questionElement, + gptAnswer, + removeListener: props.removeListener, + }); + break; + case "question-to-answer": + questionToAnswerMode({ + gptAnswer, + questionElement: props.questionElement, + removeListener: props.removeListener, + }); + break; + case "autocomplete": + autoCompleteMode({ + config: props.config, + gptAnswer, + inputList, + questionElement: props.questionElement, + removeListener: props.removeListener, + }); + break; } - - /* Handle question to answer mode */ - if (config.mode === "question-to-answer") { - removeListener(hiddenButton); - - const questionContainer = form.querySelector(".qtext"); - const questionBackup = questionContainer.textContent; - - questionContainer.textContent = gptAnswer.response; - questionContainer.style.whiteSpace = "pre-wrap"; - - questionContainer.addEventListener("click", function () { - const isNotResponse = questionContainer.textContent === questionBackup; - questionContainer.style.whiteSpace = isNotResponse ? "pre-wrap" : null; - questionContainer.textContent = isNotResponse - ? gptAnswer.response - : questionBackup; - }); - return; - } - - /* Better then set once on the event because if there is an error the user can click an other time on the question */ - if (!config.infinite) removeListener(hiddenButton); - - const handlers = [ - handleContentEditable, - handleTextbox, - handleNumber, - handleSelect, - handleRadioAndCheckbox, - ]; - - for (const handler of handlers) { - if (handler(config, inputList, gptAnswer)) return; - } - - /* In the case we can't auto complete the question */ - handleClipboard(config, gptAnswer); } export default reply; diff --git a/src/types/config.ts b/src/types/config.ts index b252f39..c317e68 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -9,6 +9,7 @@ type Config = { logs?: boolean; title?: boolean; timeout?: boolean; + history?: boolean; mode?: "autocomplete" | "question-to-answer" | "clipboard"; }; diff --git a/src/types/gptAnswer.ts b/src/types/gptAnswer.ts index 4742310..32a7694 100644 --- a/src/types/gptAnswer.ts +++ b/src/types/gptAnswer.ts @@ -1,4 +1,5 @@ type GPTAnswer = { + question: string; response: string; normalizedResponse: string; }; diff --git a/src/utils/html-table-to-string.ts b/src/utils/html-table-to-string.ts index 0d23c7c..c06ae6d 100644 --- a/src/utils/html-table-to-string.ts +++ b/src/utils/html-table-to-string.ts @@ -13,9 +13,9 @@ function htmlTableToString(table: HTMLTableElement) { const content = cell.textContent?.trim(); maxColumnsLength[index] = Math.max( maxColumnsLength[index] || 0, - content.length || 0 + content?.length || 0 ); - return content; + return content ?? ""; }); tab.push(cellsContent); }); @@ -29,7 +29,7 @@ function htmlTableToString(table: HTMLTableElement) { const mappedLine = line.map((content, index) => content.padEnd( maxColumnsLength[index], - "\u00A0" /* For no matching with \s */ + "\u00A0" // For no matching with \s ) ); return "| " + mappedLine.join(" | ") + " |"; diff --git a/src/utils/logs.ts b/src/utils/logs.ts index 5648f5b..0483ddb 100644 --- a/src/utils/logs.ts +++ b/src/utils/logs.ts @@ -1,4 +1,5 @@ import GPTAnswer from "@typing/gptAnswer"; +import { toPourcentage } from "./pick-best-response"; class Logs { static question(text: string) { @@ -6,9 +7,13 @@ class Logs { console.log("%c[QUESTION]: %s", css, text); } - static responseTry(text: string, valide: boolean) { - const css = "color: " + (valide ? "green" : "red"); - console.log("%c[CHECKING]: %s", css, text); + static bestAnswer(answer: string, similarity: number) { + const css = "color: green"; + console.log( + "%c[BEST ANSWER]: %s", + css, + `"${answer}" with a similarity of ${toPourcentage(similarity)}` + ); } static array(arr: unknown[]) { diff --git a/src/utils/normalize-text.ts b/src/utils/normalize-text.ts index dd314d3..40d0a83 100644 --- a/src/utils/normalize-text.ts +++ b/src/utils/normalize-text.ts @@ -3,20 +3,18 @@ * @param text */ function normalizeText(text: string, toLowerCase: boolean = true) { + if (toLowerCase) text = text.toLowerCase(); + let normalizedText = text .replace(/\n+/gi, "\n") //remove duplicate new lines - .replace(/(\n\s*\n)+/g, "\n") //remove useless white sapce from textcontent - .replace(/[ \t]+/gi, " "); //replace multiples space or tabs by a space + .replace(/(\n\s*\n)+/g, "\n") //remove useless white space from textcontent + .replace(/[ \t]+/gi, " ") //replace multiples space or tabs by a space + .trim() + // We remove the following content because sometimes ChatGPT will reply: "answer d" + .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 - if (toLowerCase) normalizedText = normalizedText.toLowerCase(); - - return ( - normalizedText - .trim() - /* We remove that because sometimes ChatGPT will reply: "answer d" */ - .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 - ); + return normalizedText; } export default normalizeText; diff --git a/src/utils/pick-best-response.ts b/src/utils/pick-best-response.ts new file mode 100644 index 0000000..7956419 --- /dev/null +++ b/src/utils/pick-best-response.ts @@ -0,0 +1,115 @@ +type BestResponse = { + similarity: number; + value: string | null; + element: HTMLElement | null; +}; + +type ResponsesBySimilarity = { + similarity: number; + value: string; + element: HTMLElement; +}; + +/** + * Calculate the levenshtein distance between two sentence + * @param str1 + * @param str2 + * @returns + */ +function levenshteinDistance(str1: string, str2: string) { + if (str1.length === 0) return str2.length; + if (str2.length === 0) return str1.length; + + const matrix: number[][] = []; + const str1WithoutSpaces = str1.replace(/\s+/, ""); + const str2WithoutSpaces = str2.replace(/\s+/, ""); + + for (let i = 0; i <= str1WithoutSpaces.length; ++i) { + matrix.push([i]); + for (let j = 1; j <= str2WithoutSpaces.length; ++j) { + matrix[i][j] = + i === 0 + ? j + : Math.min( + matrix[i - 1][j] + 1, + matrix[i][j - 1] + 1, + matrix[i - 1][j - 1] + + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1) + ); + } + } + + return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length]; +} + +/** + * Calculate the similarity between two sentences from 0 to 1 (best) + * @param str1 + * @param str2 + * @returns + */ +function sentenceSimilarity(str1: string, str2: string) { + const longerLength = str1.length > str2.length ? str1.length : str2.length; + if (longerLength === 0) return 1; + return (longerLength - levenshteinDistance(str1, str2)) / longerLength; +} + +/** + * Pick the best sentence that correspond to the answer + * @param arr + * @param answer + * @returns + */ +export function pickBestReponse( + answer: string, + arr: { element: HTMLElement; value: string }[] +): BestResponse { + let bestResponse: BestResponse = { + element: null, + similarity: 0, + value: null, + }; + for (const obj of arr) { + const similarity = sentenceSimilarity(obj.value, answer); + if (similarity === 1) { + return { element: obj.element, value: obj.value, similarity }; + } + if (similarity > bestResponse.similarity) { + bestResponse = { element: obj.element, value: obj.value, similarity }; + } + } + return bestResponse; +} + +/** + * Return the sentences sorted by score with a score superior or equal to what is asked + * @param answer + * @param arr + * @param score + * @returns + */ +export function pickResponsesWithSimilarityGreaterThan( + answer: string, + arr: { element: HTMLElement; value: string }[], + score: number +): ResponsesBySimilarity[] { + const responses: ResponsesBySimilarity[] = []; + for (const obj of arr) { + const similarity = sentenceSimilarity(obj.value, answer); + if (similarity >= score) + responses.push({ + similarity, + value: obj.value, + element: obj.element, + }); + } + return responses.sort((a, b) => a.similarity - b.similarity); +} + +/** + * Convert a number to a readable string pourcentage + * @param similarity + */ +export function toPourcentage(similarity: number): string { + return Math.round(similarity * 100 * 100) / 100 + "%"; +} From 1003074adfe8fd3fa728d7b486a58f0df839b0dc Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:25:14 -0500 Subject: [PATCH 18/87] harder question added --- test/fake-moodle/index.html | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/fake-moodle/index.html b/test/fake-moodle/index.html index 9f8bef2..4b333fe 100644 --- a/test/fake-moodle/index.html +++ b/test/fake-moodle/index.html @@ -8,6 +8,36 @@ + +
+
+

Which are the roles of an informatician ?

+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
From 8ed47748cb2e4d74bb73efe23373ccaa7fe07e10 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:25:18 -0500 Subject: [PATCH 19/87] Update TODO.md --- TODO.md | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/TODO.md b/TODO.md index 98d2cbe..804306b 100644 --- a/TODO.md +++ b/TODO.md @@ -1,16 +1,7 @@ # TODO -## Priority: 1 - -- [ ] Fixe put in order -- [ ] Option to remove `code` - -## 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 +- Historic for questions (implemented but need testing) +- Contributing.md +- Better prompt (Fixe put in order question, Fixe calculation question) +- Support math equation from image stocked in the `data-mathml` attribute +- Better assets From ddc21a654e5b56c96f9b8e36c2728a2b66f96e0b Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:25:52 -0500 Subject: [PATCH 20/87] strict mode, bind types and fixed include to point on src --- tsconfig.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index ebef21a..3be788f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "strict": true, "baseUrl": "src", "module": "CommonJS", "esModuleInterop": true, @@ -12,6 +13,7 @@ "resolveJsonModule": true, "types": ["node", "chrome"], "typeRoots": ["node_modules/@types"], + "strictBindCallApply": true, "paths": { "@typing/*": ["types/*"], "@utils/*": ["utils/*"], @@ -19,5 +21,5 @@ "@questions/*": ["core/question/*"] } }, - "include": ["**/*"] + "include": ["src/**/*"] } From c43cb8e2de7f8b82bb2aef5127e8f3429a6d6d9d Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:31:31 -0500 Subject: [PATCH 21/87] lint fixes --- src/core/code-listener.ts | 2 +- src/core/modes/question-to-answer.ts | 2 ++ src/core/questions/checkbox.ts | 2 +- src/core/questions/number.ts | 2 +- src/core/questions/radio.ts | 2 +- src/core/questions/select.ts | 2 +- src/utils/normalize-text.ts | 2 +- 7 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/core/code-listener.ts b/src/core/code-listener.ts index 896dab3..76284ba 100644 --- a/src/core/code-listener.ts +++ b/src/core/code-listener.ts @@ -4,7 +4,7 @@ import reply from "./reply"; type Listener = { element: HTMLElement; - fn: (this: HTMLElement, ev: MouseEvent) => any; + fn: (this: HTMLElement, ev: MouseEvent) => void; }; const pressedKeys: string[] = []; diff --git a/src/core/modes/question-to-answer.ts b/src/core/modes/question-to-answer.ts index 21bb904..1e4a33d 100644 --- a/src/core/modes/question-to-answer.ts +++ b/src/core/modes/question-to-answer.ts @@ -30,6 +30,8 @@ function questionToAnswerMode(props: Props) { questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response; + + contentIsResponse = !contentIsResponse; }); } diff --git a/src/core/questions/checkbox.ts b/src/core/questions/checkbox.ts index ac2e152..3c3150b 100644 --- a/src/core/questions/checkbox.ts +++ b/src/core/questions/checkbox.ts @@ -2,7 +2,7 @@ import type Config from "@typing/config"; import type GPTAnswer from "@typing/gptAnswer"; import Logs from "@utils/logs"; import normalizeText from "@utils/normalize-text"; -import { pickBestReponse, toPourcentage } from "@utils/pick-best-response"; +import { pickBestReponse } from "@utils/pick-best-response"; /** * Handle input checkbox elements diff --git a/src/core/questions/number.ts b/src/core/questions/number.ts index d86d153..2134904 100644 --- a/src/core/questions/number.ts +++ b/src/core/questions/number.ts @@ -23,7 +23,7 @@ function handleNumber( } const number = gptAnswer.normalizedResponse - .match(/\d+([,\.]\d+)?/gi)?.[0] + .match(/\d+([,.]\d+)?/gi)?.[0] ?.replace(",", "."); if (number === undefined) return false; diff --git a/src/core/questions/radio.ts b/src/core/questions/radio.ts index ad8ab4f..67b5d8d 100644 --- a/src/core/questions/radio.ts +++ b/src/core/questions/radio.ts @@ -2,7 +2,7 @@ import type Config from "@typing/config"; import type GPTAnswer from "@typing/gptAnswer"; import Logs from "@utils/logs"; import normalizeText from "@utils/normalize-text"; -import { pickBestReponse, toPourcentage } from "@utils/pick-best-response"; +import { pickBestReponse } from "@utils/pick-best-response"; /** * Handle input radio elements diff --git a/src/core/questions/select.ts b/src/core/questions/select.ts index 6c5c3b3..f0e3e58 100644 --- a/src/core/questions/select.ts +++ b/src/core/questions/select.ts @@ -2,7 +2,7 @@ import type Config from "@typing/config"; import type GPTAnswer from "@typing/gptAnswer"; import Logs from "@utils/logs"; import normalizeText from "@utils/normalize-text"; -import { pickBestReponse, toPourcentage } from "@utils/pick-best-response"; +import { pickBestReponse } from "@utils/pick-best-response"; /** * Handle select elements (and put in order select) diff --git a/src/utils/normalize-text.ts b/src/utils/normalize-text.ts index 40d0a83..a5321a4 100644 --- a/src/utils/normalize-text.ts +++ b/src/utils/normalize-text.ts @@ -5,7 +5,7 @@ function normalizeText(text: string, toLowerCase: boolean = true) { if (toLowerCase) text = text.toLowerCase(); - let normalizedText = text + const normalizedText = text .replace(/\n+/gi, "\n") //remove duplicate new lines .replace(/(\n\s*\n)+/g, "\n") //remove useless white space from textcontent .replace(/[ \t]+/gi, " ") //replace multiples space or tabs by a space From 54c1c1498d982fa63c32d311f344451984adf640 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 16:51:59 -0500 Subject: [PATCH 22/87] Update CONTRIBUTE.md --- CONTRIBUTE.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md index cf7d5a3..c43a67b 100644 --- a/CONTRIBUTE.md +++ b/CONTRIBUTE.md @@ -1,3 +1,28 @@ # CONTRIBUTE -`git config --local core.hooksPath .githooks/` +This file is not completed yet and still under devlopement + +## Steps to work on the project + +``` +node: 18.13.0 +npm: 8.19.2 +``` + +### 1. Install dependencies + +``` +$ npm install +``` + +## 2. Setup Git hooks + +``` +$ git config --local core.hooksPath .githooks/ +``` + +## 3. Build project + +``` +$ npm run build +``` From 00c053b04e3344c12e1ae9b89a2f7bf7583406ad Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 16:52:01 -0500 Subject: [PATCH 23/87] Update CHANGELOG.md --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4569ccc..a95951e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,12 @@ ## v1.0.4 -- Code is not required anymore +- `code` is not required anymore - Issue [#9](https://github.com/yoannchb-pro/MoodleGPT/issues/9) resolved - GPT version button fixed -- Better algo to find the correct answer -- Better chatGPT prompt -- Added `history` to the configuration +- Better algorithm to find the correct answer (levenshtein distance) +- Better ChatGPT prompt +- Added `history` to the options/configuration ## v1.0.3 From 8c364e286b99eec30cda4a4907c2a8416962de9c Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 17:02:23 -0500 Subject: [PATCH 24/87] Create CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..b16e98b --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq From 6a5e1eb8c3fb5b1362e229faaa2558f367646261 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 19:07:19 -0500 Subject: [PATCH 25/87] prettier formatage --- .eslintrc.js | 22 +- .prettierrc | 10 + CHANGELOG.md | 66 ++-- README.md | 334 ++++++++++---------- TODO.md | 14 +- extension/MoodleGPT.js | 419 +++++++++++++++++++++++++- extension/manifest.json | 52 ++-- extension/popup/index.html | 302 +++++++++---------- extension/popup/js/gptVersion.js | 30 +- extension/popup/js/index.js | 65 ++-- extension/popup/js/modeHandler.js | 26 +- extension/popup/js/utils.js | 10 +- extension/popup/js/version.js | 33 +- extension/popup/style.css | 292 +++++++++--------- rollup.config.js | 32 +- src/core/code-listener.ts | 174 +++++------ src/core/create-question.ts | 16 +- src/core/get-response.ts | 193 ++++++------ src/core/modes/autocomplete.ts | 20 +- src/core/modes/clipboard.ts | 6 +- src/core/modes/question-to-answer.ts | 12 +- src/core/questions/checkbox.ts | 30 +- src/core/questions/clipboard.ts | 30 +- src/core/questions/contenteditable.ts | 10 +- src/core/questions/number.ts | 92 +++--- src/core/questions/radio.ts | 33 +- src/core/questions/select.ts | 124 ++++---- src/core/questions/textbox.ts | 84 +++--- src/core/reply.ts | 157 +++++----- src/index.ts | 28 +- src/types/config.ts | 2 +- src/utils/html-table-to-string.ts | 27 +- src/utils/logs.ts | 58 ++-- src/utils/normalize-text.ts | 40 +-- src/utils/pick-best-response.ts | 13 +- src/utils/title-indications.ts | 22 +- test/fake-moodle/css/style.css | 2 +- test/fake-moodle/index.html | 19 +- test/reset-moodle-inputs/reset.js | 12 +- tsconfig.json | 50 +-- 40 files changed, 1666 insertions(+), 1295 deletions(-) create mode 100644 .prettierrc diff --git a/.eslintrc.js b/.eslintrc.js index 39f743d..2f4fec9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,18 +1,18 @@ module.exports = { root: true, - parser: "@typescript-eslint/parser", - plugins: ["@typescript-eslint"], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], extends: [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "prettier", + 'eslint:recommended', + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + 'prettier' ], - ignorePatterns: ["node_modules/"], + ignorePatterns: ['node_modules/'], overrides: [ { - files: ["extension/popup/*.js", "src/**/*.ts"], - rules: {}, - }, - ], + files: ['extension/popup/*.js', 'src/**/*.ts'], + rules: {} + } + ] }; diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..24b36d7 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "useTabs": false, + "printWidth": 100, + "trailingComma": "none", + "arrowParens": "avoid", + "endOfLine": "auto" +} diff --git a/CHANGELOG.md b/CHANGELOG.md index a95951e..ab221b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,33 +1,33 @@ -# CHANGELOG - -## v1.0.4 - -- `code` is not required anymore -- Issue [#9](https://github.com/yoannchb-pro/MoodleGPT/issues/9) resolved -- GPT version button fixed -- Better algorithm to find the correct answer (levenshtein distance) -- Better ChatGPT prompt -- Added `history` to the options/configuration - -## 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` - -## v1.0.1 - -- Removed langage -- Added a button next to model to get the last ChatGPT version -- Added update message - -## v1.0.0 - -- Initial commit +# CHANGELOG + +## v1.0.4 + +- `code` is not required anymore +- Issue [#9](https://github.com/yoannchb-pro/MoodleGPT/issues/9) resolved +- GPT version button fixed +- Better algorithm to find the correct answer (levenshtein distance) +- Better ChatGPT prompt +- Added `history` to the options/configuration + +## 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` + +## v1.0.1 + +- Removed langage +- Added a button next to model to get the last ChatGPT version +- Added update message + +## v1.0.0 + +- Initial commit diff --git a/README.md b/README.md index af44f4a..662f5ef 100644 --- a/README.md +++ b/README.md @@ -1,167 +1,167 @@ -

Mortarboard icons created by itim2101 - Flaticon

- -# MoodleGPT - -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. - -## Chrome Webstore - -Find the extension on the Chrome Webstore right [here](https://chrome.google.com/webstore/detail/moodlegpt/fgiepdkoifhpcgdhbiikpgdapjdoemko) - -## Summary - -- [MoodleGPT](#moodlegpt) - - [Chrome Webstore](#chrome-webstore) - - [Summary](#summary) - - [Disclaimer !](#disclaimer-) - - [Donate](#donate) - - [Update](#update) - - [MoodleGPT don't complete my quiz ?](#moodlegpt-dont-complete-my-quiz-) - - [Set up](#set-up) - - [Inject the code into the moodle](#inject-the-code-into-the-moodle) - - [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) - - [Resolve equation](#resolve-equation) - - [One response (radio button)](#one-response-radio-button) - - [Multiples responses (checkbox)](#multiples-responses-checkbox) - - [True or false](#true-or-false) - - [Number](#number) - - [Text](#text) - - [What about if the question can't be completed ?](#what-about-if-the-question-cant-be-completed-) - - [Test](#test) - -## Disclaimer ! - -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. - -## Donate - -Will be a pleasure if you want to support this project :) -
-Mortarboard icons created by itim2101 - Flaticon - -## Update - -See [changelog](./CHANGELOG.md) - -## MoodleGPT don't complete my quiz ? - -If MoodleGPT cannot complete one of your moodle quiz please provide the html code of the page. It will help us to add it in the futur version of MoodleGPT ! Check the [TODO](./TODO.md) to see what is comming in the futur version. - -## Set up - -> NOTE: This extension only works on Chromium-based browsers like Edge, Chrome, etc. Unfortunately, Firefox requires a click on the extension, which is not very discreet. - -

-Popup -

- -Go to "Manage my extensions" on your browser, then click on "Load unpacked extension" and select the "extension" folder. Afterwards, click on the extension icon and enter the apiKey obtained from [openai](https://platform.openai.com/) and enter a code that will activate the extension on your moodle page. Finally, click on the reload button next to model (it should give you the last ChatGPT version, otherwise enter it by your self) and click on the save button (The extension need to be configured before entering the moodle quiz). - -## Inject the code into the moodle - -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 - -Type back the code on the keyboard and the code will be removed from the current page. - -## Mode - -

-Popup -

- -- Autocomplete: The extension will complete the question for you. -- Clipboard: The response is copied into the clipboard. -- Question to answer: The question is converted to the answer and you can click on it to show back the question (or show back the answer). -
Question to Answer - -## Settings - -

-Popup -

- -- Api key: the openai api key. -- Code: code that you will need to inject/remove the code. -- GPT Model: the gpt model you want to use. You can click on the reload button to get the latest version of available gpt model for your account but you need to enter the api key first. -- Cursor indication: show a pointer cursor and a hourglass to know when the request is finished. -- Title indication: show some informations into the title to know for example if the code have been injected. -
![Injected](./assets/title-injected.png) -- Console logs: show logs into the console. -
Logs -- 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. -
![Typing](./assets/typing.gif) -- Mouseover effect: you will need to hover (or click for select) the question response to complete it automaticaly. -
![Mouseover](./assets/mouseover.gif) -
![Mouseover2](./assets/mouseover2.gif) - -- 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 | ----------------------------------------- -| Person 1 | Yvick | 15/08/1999 | yes | -| Person 2 | Yann | 19/01/2000 | no | -``` - -## Supported questions type - -### Select - -![Select](./assets/select.gif) - -### Put in order question - -![Order](./assets/order.gif) - -### Resolve equation - -![Equations](./assets/equations.gif) - -### One response (radio button) - -![Radio](./assets/radio.gif) - -### Multiples responses (checkbox) - -![Checkbox](./assets/checkbox.gif) - -### True or false - -![True-false](./assets/true-false.gif) - -### Number - -![Number](./assets/number.gif) - -### Text - -![Text](./assets/text.gif) - -## What about if the question can't be completed ? - -To know if the answer has been copied to the clipboard, you can look at the title of the page which will become "Copied to clipboard" for 3 seconds. - -![Clipboard](./assets/clipboard.gif) - -## Test - -- Solution 1: Go on [this moodle test page](https://school.moodledemo.net/login/index.php) (username: `student`, password: `moodle`) and choose any quiz. -- Solution 2: Run the `index.html` file located in the `test/fake-moodle` folder. +

Mortarboard icons created by itim2101 - Flaticon

+ +# MoodleGPT + +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. + +## Chrome Webstore + +Find the extension on the Chrome Webstore right [here](https://chrome.google.com/webstore/detail/moodlegpt/fgiepdkoifhpcgdhbiikpgdapjdoemko) + +## Summary + +- [MoodleGPT](#moodlegpt) + - [Chrome Webstore](#chrome-webstore) + - [Summary](#summary) + - [Disclaimer !](#disclaimer-) + - [Donate](#donate) + - [Update](#update) + - [MoodleGPT don't complete my quiz ?](#moodlegpt-dont-complete-my-quiz-) + - [Set up](#set-up) + - [Inject the code into the moodle](#inject-the-code-into-the-moodle) + - [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) + - [Resolve equation](#resolve-equation) + - [One response (radio button)](#one-response-radio-button) + - [Multiples responses (checkbox)](#multiples-responses-checkbox) + - [True or false](#true-or-false) + - [Number](#number) + - [Text](#text) + - [What about if the question can't be completed ?](#what-about-if-the-question-cant-be-completed-) + - [Test](#test) + +## Disclaimer ! + +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. + +## Donate + +Will be a pleasure if you want to support this project :) +
+Mortarboard icons created by itim2101 - Flaticon + +## Update + +See [changelog](./CHANGELOG.md) + +## MoodleGPT don't complete my quiz ? + +If MoodleGPT cannot complete one of your moodle quiz please provide the html code of the page. It will help us to add it in the futur version of MoodleGPT ! Check the [TODO](./TODO.md) to see what is comming in the futur version. + +## Set up + +> NOTE: This extension only works on Chromium-based browsers like Edge, Chrome, etc. Unfortunately, Firefox requires a click on the extension, which is not very discreet. + +

+Popup +

+ +Go to "Manage my extensions" on your browser, then click on "Load unpacked extension" and select the "extension" folder. Afterwards, click on the extension icon and enter the apiKey obtained from [openai](https://platform.openai.com/) and enter a code that will activate the extension on your moodle page. Finally, click on the reload button next to model (it should give you the last ChatGPT version, otherwise enter it by your self) and click on the save button (The extension need to be configured before entering the moodle quiz). + +## Inject the code into the moodle + +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 + +Type back the code on the keyboard and the code will be removed from the current page. + +## Mode + +

+Popup +

+ +- Autocomplete: The extension will complete the question for you. +- Clipboard: The response is copied into the clipboard. +- Question to answer: The question is converted to the answer and you can click on it to show back the question (or show back the answer). +
Question to Answer + +## Settings + +

+Popup +

+ +- Api key: the openai api key. +- Code: code that you will need to inject/remove the code. +- GPT Model: the gpt model you want to use. You can click on the reload button to get the latest version of available gpt model for your account but you need to enter the api key first. +- Cursor indication: show a pointer cursor and a hourglass to know when the request is finished. +- Title indication: show some informations into the title to know for example if the code have been injected. +
![Injected](./assets/title-injected.png) +- Console logs: show logs into the console. +
Logs +- 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. +
![Typing](./assets/typing.gif) +- Mouseover effect: you will need to hover (or click for select) the question response to complete it automaticaly. +
![Mouseover](./assets/mouseover.gif) +
![Mouseover2](./assets/mouseover2.gif) + +- 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 | +---------------------------------------- +| Person 1 | Yvick | 15/08/1999 | yes | +| Person 2 | Yann | 19/01/2000 | no | +``` + +## Supported questions type + +### Select + +![Select](./assets/select.gif) + +### Put in order question + +![Order](./assets/order.gif) + +### Resolve equation + +![Equations](./assets/equations.gif) + +### One response (radio button) + +![Radio](./assets/radio.gif) + +### Multiples responses (checkbox) + +![Checkbox](./assets/checkbox.gif) + +### True or false + +![True-false](./assets/true-false.gif) + +### Number + +![Number](./assets/number.gif) + +### Text + +![Text](./assets/text.gif) + +## What about if the question can't be completed ? + +To know if the answer has been copied to the clipboard, you can look at the title of the page which will become "Copied to clipboard" for 3 seconds. + +![Clipboard](./assets/clipboard.gif) + +## Test + +- Solution 1: Go on [this moodle test page](https://school.moodledemo.net/login/index.php) (username: `student`, password: `moodle`) and choose any quiz. +- Solution 2: Run the `index.html` file located in the `test/fake-moodle` folder. diff --git a/TODO.md b/TODO.md index 804306b..0e08c01 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,7 @@ -# TODO - -- Historic for questions (implemented but need testing) -- Contributing.md -- Better prompt (Fixe put in order question, Fixe calculation question) -- Support math equation from image stocked in the `data-mathml` attribute -- Better assets +# TODO + +- Historic for questions (implemented but need testing) +- Contributing.md / Fixe readme.md 'MoodleGPT don't complete my quiz ?' +- Better prompt (Fixe put in order question, Fixe calculation question) +- Support math equation from image stocked in the `data-mathml` attribute +- Better assets diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index f5cd786..1c4959d 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,2 +1,419 @@ -!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){return n&&(e=e.toLowerCase()),e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={}));const l="\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),c={url:null,system:{role:s.SYSTEM,content:l},history:[]};function a(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function u(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function f(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function d(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,\.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function m(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function p(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function h(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function g(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function v(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+a(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),l=yield function(e,t){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&c.url===n||(c.url=n,c.history=[]);const o=new AbortController,r=setTimeout((()=>o.abort()),15e3),l={role:s.USER,content:t},a=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?o.signal:null,body:JSON.stringify({model:e.model,messages:[c.system,...c.history,l],temperature:.8,top_p:1,presence_penalty:1,stop:null})});clearTimeout(r);const u=(yield a.json()).choices[0].message.content;return e.history&&(c.history.push(l),c.history.push({role:s.ASSISTANT,content:u})),{question:t,response:u,normalizedResponse:i(u)}}))}(e.config,t).catch((e=>({error:e}))),v="object"==typeof l&&"error"in l;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||v?"pointer":"initial"),v)console.error(l.error);else switch(e.config.logs&&(r.question(t),r.response(l)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),u(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:l,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap",n.addEventListener("click",(function(){n.style.whiteSpace="",n.textContent=t}))}({gptAnswer:l,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[f,g,d,h,m,p];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;u(e.config,e.gptAnswer)}({config:e.config,gptAnswer:l,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const y=[],w=[];function A(e){const n=w.findIndex((n=>n.element===e));if(-1!==n){const e=w.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function E(n){if(w.length>0){for(const e of w)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(w.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=v.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>A(o)});w.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){y.push(n.key),y.length>e.code.length&&y.shift(),y.join("")===e.code&&(y.length=0,E(e))}))}(n):E(n)}))})); +!(function (e) { + 'function' == typeof define && define.amd ? define(e) : e(); +})(function () { + 'use strict'; + function e(e) { + const n = document.title; + (document.title = e), setTimeout(() => (document.title = n), 3e3); + } + function n(e, n, t, o) { + return new (t || (t = Promise))(function (r, i) { + function s(e) { + try { + c(o.next(e)); + } catch (e) { + i(e); + } + } + function l(e) { + try { + c(o.throw(e)); + } catch (e) { + i(e); + } + } + function c(e) { + var n; + e.done + ? r(e.value) + : ((n = e.value), + n instanceof t + ? n + : new t(function (e) { + e(n); + })).then(s, l); + } + c((o = o.apply(e, n || [])).next()); + }); + } + function t(e, n) { + const t = e.length > n.length ? e.length : n.length; + return 0 === t + ? 1 + : (t - + (function (e, n) { + if (0 === e.length) return n.length; + if (0 === n.length) return e.length; + const t = [], + o = e.replace(/\s+/, ''), + r = n.replace(/\s+/, ''); + for (let e = 0; e <= o.length; ++e) { + t.push([e]); + for (let n = 1; n <= r.length; ++n) + t[e][n] = + 0 === e + ? n + : Math.min( + t[e - 1][n] + 1, + t[e][n - 1] + 1, + t[e - 1][n - 1] + (o[e - 1] === r[n - 1] ? 0 : 1) + ); + } + return t[o.length][r.length]; + })(e, n)) / + t; + } + function o(e, n) { + let o = { element: null, similarity: 0, value: null }; + for (const r of n) { + const n = t(r.value, e); + if (1 === n) return { element: r.element, value: r.value, similarity: n }; + n > o.similarity && (o = { element: r.element, value: r.value, similarity: n }); + } + return o; + } + 'function' == typeof SuppressedError && SuppressedError; + class r { + static question(e) { + console.log('%c[QUESTION]: %s', 'color: cyan', e); + } + static bestAnswer(e, n) { + console.log( + '%c[BEST ANSWER]: %s', + 'color: green', + `"${e}" with a similarity of ${(function (e) { + return Math.round(100 * e * 100) / 100 + '%'; + })(n)}` + ); + } + static array(e) { + console.log('[CORRECTS] ', e); + } + static response(e) { + console.log('Original:\n' + e.response), console.log('Normalized:\n' + e.normalizedResponse); + } + } + function i(e, n = !0) { + return ( + n && (e = e.toLowerCase()), + e + .replace(/\n+/gi, '\n') + .replace(/(\n\s*\n)+/g, '\n') + .replace(/[ \t]+/gi, ' ') + .trim() + .replace(/^[a-z\d]\.\s/gi, '') + .replace(/\n[a-z\d]\.\s/gi, '\n') + ); + } + var s; + !(function (e) { + (e.SYSTEM = 'system'), (e.USER = 'user'), (e.ASSISTANT = 'assistant'); + })(s || (s = {})); + const l = + "\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(), + c = { url: null, system: { role: s.SYSTEM, content: l }, history: [] }; + function a(e) { + const n = [], + t = Array.from(e.querySelectorAll('tr')), + o = []; + t.map(e => { + const t = Array.from(e.querySelectorAll('td, th')).map((e, n) => { + var t; + const r = null === (t = e.textContent) || void 0 === t ? void 0 : t.trim(); + return ( + (o[n] = Math.max(o[n] || 0, (null == r ? void 0 : r.length) || 0)), null != r ? r : '' + ); + }); + n.push(t); + }); + const r = o.reduce((e, n) => e + n) + 3 * n[0].length + 1, + i = '\n' + Array(r).fill('-').join('') + '\n', + s = n.map(e => '| ' + e.map((e, n) => e.padEnd(o[n], ' ')).join(' | ') + ' |'); + return s.shift() + i + s.join('\n'); + } + function u(n, t) { + n.title && e('Copied to clipboard'), navigator.clipboard.writeText(t.response); + } + function f(e, n, t) { + const o = n[0]; + if (1 !== n.length || 'true' !== o.getAttribute('contenteditable')) return !1; + if (e.typing) { + let e = 0; + o.addEventListener('keydown', function (n) { + if (('Backspace' === n.key && (e = t.response.length + 1), e > t.response.length)) return; + n.preventDefault(), (o.textContent = t.response.slice(0, ++e)), o.focus(); + const r = document.createRange(); + r.selectNodeContents(o), r.collapse(!1); + const i = window.getSelection(); + null !== i && (i.removeAllRanges(), i.addRange(r)); + }); + } else o.textContent = t.response; + return !0; + } + function d(e, n, t) { + var o, r; + const i = n[0]; + if (1 !== n.length || 'number' !== i.type) return !1; + const s = + null === + (r = + null === (o = t.normalizedResponse.match(/\d+([,\.]\d+)?/gi)) || void 0 === o + ? void 0 + : o[0]) || void 0 === r + ? void 0 + : r.replace(',', '.'); + if (void 0 === s) return !1; + if (e.typing) { + let e = 0; + i.addEventListener('keydown', function (n) { + n.preventDefault(), + 'Backspace' === n.key && (e = s.length + 1), + e > s.length || ('.' === s.slice(e, e + 1) && ++e, (i.value = s.slice(0, ++e))); + }); + } else i.value = s; + return !0; + } + function m(e, n, t) { + const s = null == n ? void 0 : n[0]; + if (!s || 'radio' !== s.type) return !1; + const l = Array.from(n) + .map(e => { + var n, t; + return { + element: e, + value: i( + null !== + (t = + null === (n = null == e ? void 0 : e.parentElement) || void 0 === n + ? void 0 + : n.textContent) && void 0 !== t + ? t + : '' + ) + }; + }) + .filter(e => '' !== e.value), + c = o(t.normalizedResponse, l); + e.logs && c.value && r.bestAnswer(c.value, c.similarity); + const a = c.element; + return ( + e.mouseover + ? a.addEventListener('mouseover', () => (a.checked = !0), { once: !0 }) + : (a.checked = !0), + !0 + ); + } + function p(e, n, t) { + const s = null == n ? void 0 : n[0]; + if (!s || 'checkbox' !== s.type) return !1; + const l = t.normalizedResponse.split('\n'), + c = Array.from(n) + .map(e => { + var n, t; + return { + element: e, + value: i( + null !== + (t = + null === (n = null == e ? void 0 : e.parentElement) || void 0 === n + ? void 0 + : n.textContent) && void 0 !== t + ? t + : '' + ) + }; + }) + .filter(e => '' !== e.value); + for (const n of l) { + const t = o(n, c); + e.logs && t.value && r.bestAnswer(t.value, t.similarity); + const i = t.element; + e.mouseover + ? i.addEventListener('mouseover', () => (i.checked = !0), { once: !0 }) + : (i.checked = !0); + } + return !0; + } + function h(e, n, t) { + if (0 === n.length || 'SELECT' !== n[0].tagName) return !1; + const s = t.normalizedResponse.split('\n'); + e.logs && r.array(s); + for (let t = 0; t < n.length && s[t]; ++t) { + const l = n[t].querySelectorAll('option'), + c = Array.from(l) + .map(e => { + var n; + return { + element: e, + value: i(null !== (n = e.textContent) && void 0 !== n ? n : '') + }; + }) + .filter(e => '' !== e.value), + a = o(s[t], c); + e.logs && a.value && r.bestAnswer(a.value, a.similarity); + const u = a.element, + f = u.closest('select'); + null !== f && + (e.mouseover + ? f.addEventListener('click', () => (u.selected = !0), { once: !0 }) + : (u.selected = !0)); + } + return !0; + } + function g(e, n, t) { + const o = n[0]; + if (1 !== n.length || ('TEXTAREA' !== o.tagName && 'text' !== o.type)) return !1; + if (e.typing) { + let e = 0; + o.addEventListener('keydown', function (n) { + n.preventDefault(), + 'Backspace' === n.key && (e = t.response.length + 1), + e > t.response.length || (o.value = t.response.slice(0, ++e)); + }); + } else o.value = t.response; + return !0; + } + function v(e) { + return n(this, void 0, void 0, function* () { + e.config.cursor && (e.questionElement.style.cursor = 'wait'); + const t = (function (e) { + let n = e.innerText; + const t = e.querySelectorAll('.accesshide'); + for (const e of t) n = n.replace(e.innerText, ''); + const o = e.querySelectorAll('.qtext table'); + for (const e of o) n = n.replace(e.innerText, '\n' + a(e) + '\n'); + return i(n, !1); + })(e.form), + o = e.form.querySelectorAll(e.inputQuery), + l = yield (function (e, t) { + return n(this, void 0, void 0, function* () { + const n = location.hostname + location.pathname; + (e.history && c.url === n) || ((c.url = n), (c.history = [])); + const o = new AbortController(), + r = setTimeout(() => o.abort(), 15e3), + l = { role: s.USER, content: t }, + a = yield fetch('https://api.openai.com/v1/chat/completions', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${e.apiKey}` + }, + signal: e.timeout ? o.signal : null, + body: JSON.stringify({ + model: e.model, + messages: [c.system, ...c.history, l], + temperature: 0.8, + top_p: 1, + presence_penalty: 1, + stop: null + }) + }); + clearTimeout(r); + const u = (yield a.json()).choices[0].message.content; + return ( + e.history && (c.history.push(l), c.history.push({ role: s.ASSISTANT, content: u })), + { question: t, response: u, normalizedResponse: i(u) } + ); + }); + })(e.config, t).catch(e => ({ error: e })), + v = 'object' == typeof l && 'error' in l; + if ( + (e.config.cursor && + (e.questionElement.style.cursor = e.config.infinite || v ? 'pointer' : 'initial'), + v) + ) + console.error(l.error); + else + switch ((e.config.logs && (r.question(t), r.response(l)), e.config.mode)) { + case 'clipboard': + !(function (e) { + e.config.infinite || e.removeListener(), u(e.config, e.gptAnswer); + })({ + config: e.config, + questionElement: e.questionElement, + gptAnswer: l, + removeListener: e.removeListener + }); + break; + case 'question-to-answer': + !(function (e) { + const n = e.questionElement; + e.removeListener(); + const t = n.textContent; + (n.textContent = e.gptAnswer.response), + (n.style.whiteSpace = 'pre-wrap'), + n.addEventListener('click', function () { + (n.style.whiteSpace = ''), (n.textContent = t); + }); + })({ + gptAnswer: l, + questionElement: e.questionElement, + removeListener: e.removeListener + }); + break; + case 'autocomplete': + !(function (e) { + e.config.infinite || e.removeListener(); + const n = [f, g, d, h, m, p]; + for (const t of n) if (t(e.config, e.inputList, e.gptAnswer)) return; + u(e.config, e.gptAnswer); + })({ + config: e.config, + gptAnswer: l, + inputList: o, + questionElement: e.questionElement, + removeListener: e.removeListener + }); + } + }); + } + const y = [], + w = []; + function A(e) { + const n = w.findIndex(n => n.element === e); + if (-1 !== n) { + const e = w.splice(n, 1)[0]; + e.element.removeEventListener('click', e.fn); + } + } + function E(n) { + if (w.length > 0) { + for (const e of w) + n.cursor && (e.element.style.cursor = 'initial'), + e.element.removeEventListener('click', e.fn); + return n.title && e('Removed'), void (w.length = 0); + } + const t = + ['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'); + if (null === o) continue; + n.cursor && (o.style.cursor = 'pointer'); + const r = v.bind(null, { + config: n, + questionElement: o, + form: e, + inputQuery: t, + removeListener: () => A(o) + }); + w.push({ element: o, fn: r }), o.addEventListener('click', r); + } + n.title && e('Injected'); + } + chrome.storage.sync.get(['moodleGPT']).then(function (e) { + const n = e.moodleGPT; + if (!n) throw new Error('Please configure MoodleGPT into the extension'); + n.code + ? (function (e) { + document.body.addEventListener('keydown', function (n) { + y.push(n.key), + y.length > e.code.length && y.shift(), + y.join('') === e.code && ((y.length = 0), E(e)); + }); + })(n) + : E(n); + }); +}); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/manifest.json b/extension/manifest.json index 7053f8a..b0fe3eb 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -1,26 +1,26 @@ -{ - "manifest_version": 3, - "name": "MoodleGPT", - "version": "1.0.4", - "description": "Hidden chat-gpt for your moodle quiz", - "permissions": ["storage"], - "action": { - "default_icon": "icon.png", - "default_popup": "./popup/index.html" - }, - - "icons": { - "16": "icon.png", - "32": "icon.png", - "48": "icon.png", - "128": "icon.png" - }, - - "content_scripts": [ - { - "matches": ["*://*/**/mod/quiz/*", "*://*/mod/quiz/*", "file:///*"], - "js": ["MoodleGPT.js"], - "run_at": "document_end" - } - ] -} +{ + "manifest_version": 3, + "name": "MoodleGPT", + "version": "1.0.4", + "description": "Hidden chat-gpt for your moodle quiz", + "permissions": ["storage"], + "action": { + "default_icon": "icon.png", + "default_popup": "./popup/index.html" + }, + + "icons": { + "16": "icon.png", + "32": "icon.png", + "48": "icon.png", + "128": "icon.png" + }, + + "content_scripts": [ + { + "matches": ["*://*/**/mod/quiz/*", "*://*/mod/quiz/*", "file:///*"], + "js": ["MoodleGPT.js"], + "run_at": "document_end" + } + ] +} diff --git a/extension/popup/index.html b/extension/popup/index.html index 0494b8c..ca94616 100644 --- a/extension/popup/index.html +++ b/extension/popup/index.html @@ -1,154 +1,148 @@ - - - - - - - MoodleGPT - - - - - - - - - - - - - - - -
-
- icon -
-

MoodleGPT

-

-
-
-
- - -
-
- - - -
-
- - -
-
- -

Mode:

-
-
-
    -
  • -
  • - -
  • -
  • - -
  • -
-
-
- -

Settings:

-
-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-

Message

-
- -
- -
- - + + + + + + + MoodleGPT + + + + + + + + + + + + + + + +
+
+ icon +
+

MoodleGPT

+

+
+
+
+ + +
+
+ + + +
+
+ + +
+
+ +

Mode:

+
+
+
    +
  • +
  • + +
  • +
  • + +
  • +
+
+
+ +

Settings:

+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+

Message

+
+ +
+ +
+ + diff --git a/extension/popup/js/gptVersion.js b/extension/popup/js/gptVersion.js index 312df3e..9cb7c0a 100644 --- a/extension/popup/js/gptVersion.js +++ b/extension/popup/js/gptVersion.js @@ -1,49 +1,49 @@ -"use strict"; +'use strict'; /** * Get the last ChatGPT version */ function getLastChatGPTVersion() { - const apiKeySelector = document.querySelector("#apiKey"); - const reloadModel = document.querySelector("#reloadModel"); + const apiKeySelector = document.querySelector('#apiKey'); + const reloadModel = document.querySelector('#reloadModel'); let apiKey = apiKeySelector.value; // If the api key is set we enable the button to get the last chatgpt version function checkFiledApiKey() { if (apiKey) { - reloadModel.removeAttribute("disabled"); - reloadModel.setAttribute("title", "Get last ChatGPT version"); + reloadModel.removeAttribute('disabled'); + reloadModel.setAttribute('title', 'Get last ChatGPT version'); return; } - reloadModel.setAttribute("disabled", true); - reloadModel.setAttribute("title", "Provide an api key first"); + reloadModel.setAttribute('disabled', true); + reloadModel.setAttribute('title', 'Provide an api key first'); } checkFiledApiKey(); // Check if the api key is set - apiKeySelector.addEventListener("input", function () { + apiKeySelector.addEventListener('input', function () { apiKey = apiKeySelector.value.trim(); checkFiledApiKey(); }); // Event listener to handle a click on the relaod icon button - reloadModel.addEventListener("click", async function () { + reloadModel.addEventListener('click', async function () { if (!apiKey) return; try { - const req = await fetch("https://api.openai.com/v1/models", { + const req = await fetch('https://api.openai.com/v1/models', { headers: { - Authorization: `Bearer ${apiKey}`, - }, + Authorization: `Bearer ${apiKey}` + } }); const rep = await req.json(); - const model = rep.data.find((model) => model.id.startsWith("gpt")); - document.querySelector("#model").value = model.id; + const model = rep.data.find(model => model.id.startsWith('gpt')); + document.querySelector('#model').value = model.id; } catch (err) { console.error(err); - showMessage({ msg: "Failed to fetch last ChatGPT version", error: true }); + showMessage({ msg: 'Failed to fetch last ChatGPT version', error: true }); } }); } diff --git a/extension/popup/js/index.js b/extension/popup/js/index.js index 421f95f..caad3df 100644 --- a/extension/popup/js/index.js +++ b/extension/popup/js/index.js @@ -1,38 +1,39 @@ -const saveBtn = document.querySelector(".save"); +const saveBtn = document.querySelector('.save'); /* inputs id */ -const inputsText = ["apiKey", "code", "model"]; +const inputsText = ['apiKey', 'code', 'model']; const inputsCheckbox = [ - "logs", - "title", - "cursor", - "typing", - "mouseover", - "infinite", - "timeout", - "history", + 'logs', + 'title', + 'cursor', + 'typing', + 'mouseover', + 'infinite', + 'timeout', + 'history' ]; /* Save the configuration */ -saveBtn.addEventListener("click", function () { - const [apiKey, code, model] = inputsText.map((selector) => - document.querySelector("#" + selector).value.trim() +saveBtn.addEventListener('click', function () { + const [apiKey, code, model] = inputsText.map(selector => + document.querySelector('#' + selector).value.trim() + ); + const [logs, title, cursor, typing, mouseover, infinite, timeout, history] = inputsCheckbox.map( + selector => { + const element = document.querySelector('#' + selector); + return element.checked && element.parentElement.style.display !== 'none'; + } ); - const [logs, title, cursor, typing, mouseover, infinite, timeout, history] = - inputsCheckbox.map((selector) => { - const element = document.querySelector("#" + selector); - return element.checked && element.parentElement.style.display !== "none"; - }); if (!apiKey || !model) { - showMessage({ msg: "Please complete all the form", error: true }); + showMessage({ msg: 'Please complete all the form', error: true }); return; } if (code.length > 0 && code.length < 3) { showMessage({ - msg: "The code should at least contain 3 characters", - error: true, + msg: 'The code should at least contain 3 characters', + error: true }); return; } @@ -50,15 +51,15 @@ saveBtn.addEventListener("click", function () { infinite, timeout, history, - mode: actualMode, - }, + mode: actualMode + } }); - showMessage({ msg: "Configuration saved" }); + showMessage({ msg: 'Configuration saved' }); }); /* we load back the configuration */ -chrome.storage.sync.get(["moodleGPT"]).then(function (storage) { +chrome.storage.sync.get(['moodleGPT']).then(function (storage) { const config = storage.moodleGPT; if (config) { @@ -66,21 +67,17 @@ chrome.storage.sync.get(["moodleGPT"]).then(function (storage) { actualMode = config.mode; for (const mode of modes) { if (mode.value === config.mode) { - mode.classList.remove("not-selected"); + mode.classList.remove('not-selected'); } else { - mode.classList.add("not-selected"); + mode.classList.add('not-selected'); } } } - inputsText.forEach((key) => - config[key] - ? (document.querySelector("#" + key).value = config[key]) - : null - ); - inputsCheckbox.forEach( - (key) => (document.querySelector("#" + key).checked = config[key] || "") + inputsText.forEach(key => + config[key] ? (document.querySelector('#' + key).value = config[key]) : null ); + inputsCheckbox.forEach(key => (document.querySelector('#' + key).checked = config[key] || '')); } handleModeChange(); diff --git a/extension/popup/js/modeHandler.js b/extension/popup/js/modeHandler.js index 705dd5f..1d77676 100644 --- a/extension/popup/js/modeHandler.js +++ b/extension/popup/js/modeHandler.js @@ -1,15 +1,15 @@ -"use strict"; +'use strict'; -const mode = document.querySelector("#mode"); -const modes = mode.querySelectorAll("button"); +const mode = document.querySelector('#mode'); +const modes = mode.querySelectorAll('button'); -let actualMode = "autocomplete"; +let actualMode = 'autocomplete'; /* inputs id that need to be disabled for a specific mode */ const disabledForThisMode = { autocomplete: [], - clipboard: ["typing", "mouseover"], - "question-to-answer": ["typing", "infinite", "mouseover"], + clipboard: ['typing', 'mouseover'], + 'question-to-answer': ['typing', 'infinite', 'mouseover'] }; /** @@ -17,27 +17,25 @@ const disabledForThisMode = { */ function handleModeChange() { const needDisable = disabledForThisMode[actualMode]; - const dontNeedDisable = inputsCheckbox.filter( - (input) => !needDisable.includes(input) - ); + const dontNeedDisable = inputsCheckbox.filter(input => !needDisable.includes(input)); for (const id of needDisable) { - document.querySelector("#" + id).parentElement.style.display = "none"; + document.querySelector('#' + id).parentElement.style.display = 'none'; } for (const id of dontNeedDisable) { - document.querySelector("#" + id).parentElement.style.display = null; + document.querySelector('#' + id).parentElement.style.display = null; } } /* Mode handler */ for (const button of modes) { - button.addEventListener("click", function () { + button.addEventListener('click', function () { const value = button.value; actualMode = value; for (const mode of modes) { if (mode.value !== value) { - mode.classList.add("not-selected"); + mode.classList.add('not-selected'); } else { - mode.classList.remove("not-selected"); + mode.classList.remove('not-selected'); } } handleModeChange(); diff --git a/extension/popup/js/utils.js b/extension/popup/js/utils.js index 5b69d3a..17a42cb 100644 --- a/extension/popup/js/utils.js +++ b/extension/popup/js/utils.js @@ -1,12 +1,12 @@ -"use strict"; +'use strict'; /** * Show message into the popup */ function showMessage({ msg, error, infinite }) { - const message = document.querySelector("#message"); - message.style.color = error ? "red" : "limegreen"; + const message = document.querySelector('#message'); + message.style.color = error ? 'red' : 'limegreen'; message.textContent = msg; - message.style.display = "block"; - if (!infinite) setTimeout(() => (message.style.display = "none"), 5000); + message.style.display = 'block'; + if (!infinite) setTimeout(() => (message.style.display = 'none'), 5000); } diff --git a/extension/popup/js/version.js b/extension/popup/js/version.js index 3f5ee5b..095e30e 100644 --- a/extension/popup/js/version.js +++ b/extension/popup/js/version.js @@ -1,7 +1,7 @@ -"use strict"; +'use strict'; -const CURRENT_VERSION = "1.0.4"; -const versionDisplay = document.querySelector("#version"); +const CURRENT_VERSION = '1.0.4'; +const versionDisplay = document.querySelector('#version'); /** * Get the last version from the github @@ -9,7 +9,7 @@ const versionDisplay = document.querySelector("#version"); */ async function getLastVersion() { const req = await fetch( - "https://raw.githubusercontent.com/yoannchb-pro/MoodleGPT/main/package.json" + 'https://raw.githubusercontent.com/yoannchb-pro/MoodleGPT/main/package.json' ); const rep = await req.json(); return rep.version; @@ -23,34 +23,31 @@ async function getLastVersion() { */ function setVersion(version, isCurrent = true) { if (isCurrent) { - versionDisplay.textContent = "v" + version; + versionDisplay.textContent = 'v' + version; return; } - const link = document.createElement("a"); - link.href = "https://github.com/yoannchb-pro/MoodleGPT"; - link.rel = "noopener noreferrer"; - link.target = "_blank"; - link.textContent = "v" + version; + const link = document.createElement('a'); + link.href = 'https://github.com/yoannchb-pro/MoodleGPT'; + link.rel = 'noopener noreferrer'; + link.target = '_blank'; + link.textContent = 'v' + version; versionDisplay.appendChild(link); - versionDisplay.appendChild(document.createTextNode(" is now available !")); + versionDisplay.appendChild(document.createTextNode(' is now available !')); } /** * Check if the extension neeed an update or not */ async function notifyUpdate() { - const lastVersion = await getLastVersion().catch((err) => { + const lastVersion = await getLastVersion().catch(err => { console.error(err); return CURRENT_VERSION; }); - const lastVertionSplitted = lastVersion.split("."); - const currentVersionSplitted = CURRENT_VERSION.split("."); - const minVersionLength = Math.min( - lastVertionSplitted.length, - currentVersionSplitted.length - ); + const lastVertionSplitted = lastVersion.split('.'); + const currentVersionSplitted = CURRENT_VERSION.split('.'); + const minVersionLength = Math.min(lastVertionSplitted.length, currentVersionSplitted.length); for (let i = 0; i < minVersionLength; ++i) { if (parseInt(lastVertionSplitted[i]) > parseInt(currentVersionSplitted[i])) diff --git a/extension/popup/style.css b/extension/popup/style.css index 1629eae..fa48bbb 100644 --- a/extension/popup/style.css +++ b/extension/popup/style.css @@ -1,146 +1,146 @@ -@font-face { - font-family: Segeo UI; - src: url(../../fonts/Segoe\ UI.ttf); -} - -:root { - --bg-color: #121212; - --color: #fff; - --btn-color: #7f39fb; -} - -* { - box-sizing: border-box; - padding: 0; - margin: 0; - font-family: "Segeo UI", sans-serif; - color: var(--color); -} - -body { - min-height: 100vh; - background-color: var(--bg-color); - display: flex; - justify-content: center; - align-items: center; -} - -main { - display: flex; - flex-direction: column; - align-items: center; - padding: 0.75rem; - gap: 0.4rem; - text-align: center; - width: 22rem; -} - -img { - width: 5rem; -} - -a { - color: var(--btn-color); - margin: 0; -} - -.line { - display: flex; - flex-direction: row; - width: 100%; - gap: 0.5rem; -} - -.center { - justify-content: center; - align-items: center; -} - -.line .textLabel { - width: 5rem; - text-align: left; - text-transform: uppercase; -} - -.line .textLabel .required { - color: var(--btn-color); - font-weight: bold; -} - -.line input[type="text"], -.line input[type="password"] { - flex: 1 1; - border: thin solid var(--color); - padding: 0.3rem 0.5rem; - border-radius: 0.2rem; - outline-color: transparent; - background-color: transparent; -} - -.line input[type="checkbox"] { - accent-color: var(--btn-color); -} - -.col { - display: flex; - flex-direction: column; - text-align: left; -} - -.save { - border: none; - background-color: var(--btn-color); - padding: 0.5rem 2rem; - margin-top: 1rem; - cursor: pointer; - border-radius: 0.2rem; - font-size: 1.5rem; - margin-bottom: 0.75rem; -} - -.mt { - margin-top: 1rem; -} - -.not-selected { - opacity: 0.4; -} - -#mode li { - list-style: none; - flex-grow: 1; -} - -#mode { - flex-wrap: wrap; -} - -#mode button { - background-color: var(--btn-color); - border: none; - text-align: center; - padding: 0.3rem 0.75rem; - cursor: pointer; - width: 100%; - border-radius: 0.5rem; - text-transform: uppercase; -} - -#version { - font-size: 0.75rem; -} - -#message { - display: none; - margin-top: 0.75rem; - margin-bottom: -0.25rem; -} - -#reloadModel { - cursor: pointer; -} - -#reloadModel[disabled] { - cursor: not-allowed; - opacity: 0.75; -} +@font-face { + font-family: Segeo UI; + src: url(../../fonts/Segoe\ UI.ttf); +} + +:root { + --bg-color: #121212; + --color: #fff; + --btn-color: #7f39fb; +} + +* { + box-sizing: border-box; + padding: 0; + margin: 0; + font-family: 'Segeo UI', sans-serif; + color: var(--color); +} + +body { + min-height: 100vh; + background-color: var(--bg-color); + display: flex; + justify-content: center; + align-items: center; +} + +main { + display: flex; + flex-direction: column; + align-items: center; + padding: 0.75rem; + gap: 0.4rem; + text-align: center; + width: 22rem; +} + +img { + width: 5rem; +} + +a { + color: var(--btn-color); + margin: 0; +} + +.line { + display: flex; + flex-direction: row; + width: 100%; + gap: 0.5rem; +} + +.center { + justify-content: center; + align-items: center; +} + +.line .textLabel { + width: 5rem; + text-align: left; + text-transform: uppercase; +} + +.line .textLabel .required { + color: var(--btn-color); + font-weight: bold; +} + +.line input[type='text'], +.line input[type='password'] { + flex: 1 1; + border: thin solid var(--color); + padding: 0.3rem 0.5rem; + border-radius: 0.2rem; + outline-color: transparent; + background-color: transparent; +} + +.line input[type='checkbox'] { + accent-color: var(--btn-color); +} + +.col { + display: flex; + flex-direction: column; + text-align: left; +} + +.save { + border: none; + background-color: var(--btn-color); + padding: 0.5rem 2rem; + margin-top: 1rem; + cursor: pointer; + border-radius: 0.2rem; + font-size: 1.5rem; + margin-bottom: 0.75rem; +} + +.mt { + margin-top: 1rem; +} + +.not-selected { + opacity: 0.4; +} + +#mode li { + list-style: none; + flex-grow: 1; +} + +#mode { + flex-wrap: wrap; +} + +#mode button { + background-color: var(--btn-color); + border: none; + text-align: center; + padding: 0.3rem 0.75rem; + cursor: pointer; + width: 100%; + border-radius: 0.5rem; + text-transform: uppercase; +} + +#version { + font-size: 0.75rem; +} + +#message { + display: none; + margin-top: 0.75rem; + margin-bottom: -0.25rem; +} + +#reloadModel { + cursor: pointer; +} + +#reloadModel[disabled] { + cursor: not-allowed; + opacity: 0.75; +} diff --git a/rollup.config.js b/rollup.config.js index ea4a70e..d32d7c0 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,16 +1,16 @@ -const ts = require("rollup-plugin-ts"); -const terser = require("@rollup/plugin-terser"); - -const config = require("./tsconfig.json"); - -module.exports = { - input: "./src/index.ts", - output: [ - { - file: "./extension/MoodleGPT.js", - format: "umd", - sourcemap: true, - }, - ], - plugins: [ts(config), terser()], -}; +const ts = require('rollup-plugin-ts'); +const terser = require('@rollup/plugin-terser'); + +const config = require('./tsconfig.json'); + +module.exports = { + input: './src/index.ts', + output: [ + { + file: './extension/MoodleGPT.js', + format: 'umd', + sourcemap: true + } + ], + plugins: [ts(config), terser()] +}; diff --git a/src/core/code-listener.ts b/src/core/code-listener.ts index 76284ba..688a7ac 100644 --- a/src/core/code-listener.ts +++ b/src/core/code-listener.ts @@ -1,87 +1,87 @@ -import type Config from "@typing/config"; -import titleIndications from "@utils/title-indications"; -import reply from "./reply"; - -type Listener = { - element: HTMLElement; - fn: (this: HTMLElement, ev: MouseEvent) => void; -}; - -const pressedKeys: string[] = []; -const listeners: Listener[] = []; - -/** - * Create a listener on the keyboard to inject the code - * @param config - */ -function codeListener(config: 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); - } - }); -} - -/** - * Remove the event listener on a specific question - * @param element - */ -function removeListener(element: HTMLElement) { - const index = listeners.findIndex((listener) => listener.element === element); - if (index !== -1) { - const listener = listeners.splice(index, 1)[0]; - listener.element.removeEventListener("click", listener.fn); - } -} - -/** - * Setup moodleGPT into the page (remove/injection) - * @param config - * @returns - */ -function setUpMoodleGpt(config: Config) { - // Removing events if there are already declared - 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; - } - - // Query to find inputs and forms - const inputTypeQuery = ["checkbox", "radio", "text", "number"] - .map((e) => `input[type="${e}"]`) - .join(","); - const inputQuery = inputTypeQuery + ", textarea, select, [contenteditable]"; - const forms = document.querySelectorAll(".formulation"); - - // For each form we inject a function on the queqtion - for (const form of forms) { - const questionElement: HTMLElement | null = form.querySelector(".qtext"); - - if (questionElement === null) continue; - - if (config.cursor) questionElement.style.cursor = "pointer"; - - const injectionFunction = reply.bind(null, { - config, - questionElement, - form: form as HTMLElement, - inputQuery, - removeListener: () => removeListener(questionElement), - }); - - listeners.push({ element: questionElement, fn: injectionFunction }); - questionElement.addEventListener("click", injectionFunction); - } - - if (config.title) titleIndications("Injected"); -} - -export { codeListener, removeListener, setUpMoodleGpt }; +import type Config from '@typing/config'; +import titleIndications from '@utils/title-indications'; +import reply from './reply'; + +type Listener = { + element: HTMLElement; + fn: (this: HTMLElement, ev: MouseEvent) => void; +}; + +const pressedKeys: string[] = []; +const listeners: Listener[] = []; + +/** + * Create a listener on the keyboard to inject the code + * @param config + */ +function codeListener(config: 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); + } + }); +} + +/** + * Remove the event listener on a specific question + * @param element + */ +function removeListener(element: HTMLElement) { + const index = listeners.findIndex(listener => listener.element === element); + if (index !== -1) { + const listener = listeners.splice(index, 1)[0]; + listener.element.removeEventListener('click', listener.fn); + } +} + +/** + * Setup moodleGPT into the page (remove/injection) + * @param config + * @returns + */ +function setUpMoodleGpt(config: Config) { + // Removing events if there are already declared + 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; + } + + // Query to find inputs and forms + const inputTypeQuery = ['checkbox', 'radio', 'text', 'number'] + .map(e => `input[type="${e}"]`) + .join(','); + const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]'; + const forms = document.querySelectorAll('.formulation'); + + // For each form we inject a function on the queqtion + for (const form of forms) { + const questionElement: HTMLElement | null = form.querySelector('.qtext'); + + if (questionElement === null) continue; + + if (config.cursor) questionElement.style.cursor = 'pointer'; + + const injectionFunction = reply.bind(null, { + config, + questionElement, + form: form as HTMLElement, + inputQuery, + removeListener: () => removeListener(questionElement) + }); + + listeners.push({ element: questionElement, fn: injectionFunction }); + questionElement.addEventListener('click', injectionFunction); + } + + if (config.title) titleIndications('Injected'); +} + +export { codeListener, removeListener, setUpMoodleGpt }; diff --git a/src/core/create-question.ts b/src/core/create-question.ts index fbd68a5..a765410 100644 --- a/src/core/create-question.ts +++ b/src/core/create-question.ts @@ -1,5 +1,5 @@ -import normalizeText from "@utils/normalize-text"; -import htmlTableToString from "@utils/html-table-to-string"; +import normalizeText from '@utils/normalize-text'; +import htmlTableToString from '@utils/html-table-to-string'; /** * Normalize the question as text and add sub informations @@ -12,19 +12,15 @@ function createAndNormalizeQuestion(questionContainer: HTMLElement) { // We remove unnecessary information const accesshideElements: NodeListOf = - questionContainer.querySelectorAll(".accesshide"); + questionContainer.querySelectorAll('.accesshide'); for (const useless of accesshideElements) { - question = question.replace(useless.innerText, ""); + question = question.replace(useless.innerText, ''); } // Make tables more readable for chat-gpt - const tables: NodeListOf = - questionContainer.querySelectorAll(".qtext table"); + const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table'); for (const table of tables) { - question = question.replace( - table.innerText, - "\n" + htmlTableToString(table) + "\n" - ); + question = question.replace(table.innerText, '\n' + htmlTableToString(table) + '\n'); } return normalizeText(question, false); diff --git a/src/core/get-response.ts b/src/core/get-response.ts index 007e154..9a32435 100644 --- a/src/core/get-response.ts +++ b/src/core/get-response.ts @@ -1,98 +1,95 @@ -import type Config from "@typing/config"; -import type GPTAnswer from "@typing/gptAnswer"; -import normalizeText from "@utils/normalize-text"; - -type History = { - url: string | null; - system: { role: ROLE; content: string }; - history: { role: ROLE; content: string }[]; -}; - -enum ROLE { - SYSTEM = "system", - USER = "user", - ASSISTANT = "assistant", -} - -const INSTRUCTION: string = ` -Act as a quiz solver for the best notation with the following rules: -- When asked for the result of an equation, provide only the result without any other information and skip the other rules. -- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. -- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...' -- Always reply in the format: '\n\n...'. -- Retain only the correct answer(s). -- Maintain the same order for the answers as in the text. -- Retain all text from the answer with its description, content or definition. -- Only provide answers that exactly match the given answer in the text. -- The question always has the correct answer(s), so you should always provide an answer. -- Always respond in the same language as the user's question. -`.trim(); - -const history: History = { - url: null, - system: { - role: ROLE.SYSTEM, - content: INSTRUCTION, - }, - history: [], -}; - -/** - * Get the response from chatGPT api - * @param config - * @param question - * @returns - */ -async function getChatGPTResponse( - config: Config, - question: string -): Promise { - const URL = location.hostname + location.pathname; - - // We reset the history when we enter a new moodle quiz or when it's desactivate - if (!config.history || history.url !== URL) { - history.url = URL; - history.history = []; - } - - const controller = new AbortController(); - const timeoutControler = setTimeout(() => controller.abort(), 15 * 1000); - - const message = { role: ROLE.USER, content: question }; - - const req = await 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: [history.system, ...history.history, message], - temperature: 0.8, - top_p: 1.0, - presence_penalty: 1.0, - stop: null, - }), - }); - - clearTimeout(timeoutControler); - - const rep = await req.json(); - const response = rep.choices[0].message.content; - - // Register the conversation - if (config.history) { - history.history.push(message); - history.history.push({ role: ROLE.ASSISTANT, content: response }); - } - - return { - question, - response, - normalizedResponse: normalizeText(response), - }; -} - -export default getChatGPTResponse; +import type Config from '@typing/config'; +import type GPTAnswer from '@typing/gptAnswer'; +import normalizeText from '@utils/normalize-text'; + +type History = { + url: string | null; + system: { role: ROLE; content: string }; + history: { role: ROLE; content: string }[]; +}; + +enum ROLE { + SYSTEM = 'system', + USER = 'user', + ASSISTANT = 'assistant' +} + +const INSTRUCTION: string = ` +Act as a quiz solver for the best notation with the following rules: +- When asked for the result of an equation, provide only the result without any other information and skip the other rules. +- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. +- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...' +- Always reply in the format: '\n\n...'. +- Retain only the correct answer(s). +- Maintain the same order for the answers as in the text. +- Retain all text from the answer with its description, content or definition. +- Only provide answers that exactly match the given answer in the text. +- The question always has the correct answer(s), so you should always provide an answer. +- Always respond in the same language as the user's question. +`.trim(); + +const history: History = { + url: null, + system: { + role: ROLE.SYSTEM, + content: INSTRUCTION + }, + history: [] +}; + +/** + * Get the response from chatGPT api + * @param config + * @param question + * @returns + */ +async function getChatGPTResponse(config: Config, question: string): Promise { + const URL = location.hostname + location.pathname; + + // We reset the history when we enter a new moodle quiz or when it's desactivate + if (!config.history || history.url !== URL) { + history.url = URL; + history.history = []; + } + + const controller = new AbortController(); + const timeoutControler = setTimeout(() => controller.abort(), 15 * 1000); + + const message = { role: ROLE.USER, content: question }; + + const req = await 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: [history.system, ...history.history, message], + temperature: 0.8, + top_p: 1.0, + presence_penalty: 1.0, + stop: null + }) + }); + + clearTimeout(timeoutControler); + + const rep = await req.json(); + const response = rep.choices[0].message.content; + + // Register the conversation + if (config.history) { + history.history.push(message); + history.history.push({ role: ROLE.ASSISTANT, content: response }); + } + + return { + question, + response, + normalizedResponse: normalizeText(response) + }; +} + +export default getChatGPTResponse; diff --git a/src/core/modes/autocomplete.ts b/src/core/modes/autocomplete.ts index d3f384a..63f7f32 100644 --- a/src/core/modes/autocomplete.ts +++ b/src/core/modes/autocomplete.ts @@ -1,12 +1,12 @@ -import type GPTAnswer from "@typing/gptAnswer"; -import type Config from "@typing/config"; -import handleClipboard from "@core/questions/clipboard"; -import handleContentEditable from "@core/questions/contenteditable"; -import handleNumber from "@core/questions/number"; -import handleRadio from "@core/questions/radio"; -import handleCheckbox from "@core/questions/checkbox"; -import handleSelect from "@core/questions/select"; -import handleTextbox from "@core/questions/textbox"; +import type GPTAnswer from '@typing/gptAnswer'; +import type Config from '@typing/config'; +import handleClipboard from '@core/questions/clipboard'; +import handleContentEditable from '@core/questions/contenteditable'; +import handleNumber from '@core/questions/number'; +import handleRadio from '@core/questions/radio'; +import handleCheckbox from '@core/questions/checkbox'; +import handleSelect from '@core/questions/select'; +import handleTextbox from '@core/questions/textbox'; type Props = { config: Config; @@ -31,7 +31,7 @@ function autoCompleteMode(props: Props) { handleNumber, handleSelect, handleRadio, - handleCheckbox, + handleCheckbox ]; for (const handler of handlers) { diff --git a/src/core/modes/clipboard.ts b/src/core/modes/clipboard.ts index 0c37151..782b6d3 100644 --- a/src/core/modes/clipboard.ts +++ b/src/core/modes/clipboard.ts @@ -1,6 +1,6 @@ -import type Config from "@typing/config"; -import type GPTAnswer from "@typing/gptAnswer"; -import handleClipboard from "@core/questions/clipboard"; +import type Config from '@typing/config'; +import type GPTAnswer from '@typing/gptAnswer'; +import handleClipboard from '@core/questions/clipboard'; type Props = { config: Config; diff --git a/src/core/modes/question-to-answer.ts b/src/core/modes/question-to-answer.ts index 1e4a33d..9250010 100644 --- a/src/core/modes/question-to-answer.ts +++ b/src/core/modes/question-to-answer.ts @@ -1,4 +1,4 @@ -import type GPTAnswer from "@typing/gptAnswer"; +import type GPTAnswer from '@typing/gptAnswer'; type Props = { questionElement: HTMLElement; @@ -21,15 +21,13 @@ function questionToAnswerMode(props: Props) { questionElement.textContent = props.gptAnswer.response; // Format the content - questionElement.style.whiteSpace = "pre-wrap"; + questionElement.style.whiteSpace = 'pre-wrap'; // To go back to the question / answer let contentIsResponse = true; - questionElement.addEventListener("click", function () { - questionElement.style.whiteSpace = contentIsResponse ? "" : "pre-warp"; - questionElement.textContent = contentIsResponse - ? questionBackup - : props.gptAnswer.response; + questionElement.addEventListener('click', function () { + questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp'; + questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response; contentIsResponse = !contentIsResponse; }); diff --git a/src/core/questions/checkbox.ts b/src/core/questions/checkbox.ts index 3c3150b..5446e71 100644 --- a/src/core/questions/checkbox.ts +++ b/src/core/questions/checkbox.ts @@ -1,8 +1,8 @@ -import type Config from "@typing/config"; -import type GPTAnswer from "@typing/gptAnswer"; -import Logs from "@utils/logs"; -import normalizeText from "@utils/normalize-text"; -import { pickBestReponse } from "@utils/pick-best-response"; +import type Config from '@typing/config'; +import type GPTAnswer from '@typing/gptAnswer'; +import Logs from '@utils/logs'; +import normalizeText from '@utils/normalize-text'; +import { pickBestReponse } from '@utils/pick-best-response'; /** * Handle input checkbox elements @@ -18,18 +18,18 @@ function handleCheckbox( const firstInput = inputList?.[0] as HTMLInputElement; // Handle the case the input is not a checkbox - if (!firstInput || firstInput.type !== "checkbox") { + if (!firstInput || firstInput.type !== 'checkbox') { return false; } - const corrects = gptAnswer.normalizedResponse.split("\n"); + const corrects = gptAnswer.normalizedResponse.split('\n'); const possibleAnswers = Array.from(inputList) - .map((inp) => ({ + .map(inp => ({ element: inp, - value: normalizeText(inp?.parentElement?.textContent ?? ""), + value: normalizeText(inp?.parentElement?.textContent ?? '') })) - .filter((obj) => obj.value !== ""); + .filter(obj => obj.value !== ''); for (const correct of corrects) { const bestAnswer = pickBestReponse(correct, possibleAnswers); @@ -40,13 +40,9 @@ function handleCheckbox( const correctInput = bestAnswer.element as HTMLInputElement; if (config.mouseover) { - correctInput.addEventListener( - "mouseover", - () => (correctInput.checked = true), - { - once: true, - } - ); + correctInput.addEventListener('mouseover', () => (correctInput.checked = true), { + once: true + }); } else { correctInput.checked = true; } diff --git a/src/core/questions/clipboard.ts b/src/core/questions/clipboard.ts index c661953..f5af75d 100644 --- a/src/core/questions/clipboard.ts +++ b/src/core/questions/clipboard.ts @@ -1,15 +1,15 @@ -import type Config from "@typing/config"; -import type GPTAnswer from "@typing/gptAnswer"; -import titleIndications from "@utils/title-indications"; - -/** - * Copy the response in the clipboard if we can automaticaly fill the question - * @param config - * @param gptAnswer - */ -function handleClipboard(config: Config, gptAnswer: GPTAnswer) { - if (config.title) titleIndications("Copied to clipboard"); - navigator.clipboard.writeText(gptAnswer.response); -} - -export default handleClipboard; +import type Config from '@typing/config'; +import type GPTAnswer from '@typing/gptAnswer'; +import titleIndications from '@utils/title-indications'; + +/** + * Copy the response in the clipboard if we can automaticaly fill the question + * @param config + * @param gptAnswer + */ +function handleClipboard(config: Config, gptAnswer: GPTAnswer) { + if (config.title) titleIndications('Copied to clipboard'); + navigator.clipboard.writeText(gptAnswer.response); +} + +export default handleClipboard; diff --git a/src/core/questions/contenteditable.ts b/src/core/questions/contenteditable.ts index 742d68b..f10c750 100644 --- a/src/core/questions/contenteditable.ts +++ b/src/core/questions/contenteditable.ts @@ -1,5 +1,5 @@ -import type Config from "@typing/config"; -import type GPTAnswer from "@typing/gptAnswer"; +import type Config from '@typing/config'; +import type GPTAnswer from '@typing/gptAnswer'; /** * Hanlde contenteditable elements @@ -17,15 +17,15 @@ function handleContentEditable( if ( inputList.length !== 1 || // for now we don't handle many input for editable textcontent - input.getAttribute("contenteditable") !== "true" + input.getAttribute('contenteditable') !== 'true' ) { return false; } if (config.typing) { let index = 0; - input.addEventListener("keydown", function (event: KeyboardEvent) { - if (event.key === "Backspace") index = gptAnswer.response.length + 1; + input.addEventListener('keydown', function (event: KeyboardEvent) { + if (event.key === 'Backspace') index = gptAnswer.response.length + 1; if (index > gptAnswer.response.length) return; event.preventDefault(); input.textContent = gptAnswer.response.slice(0, ++index); diff --git a/src/core/questions/number.ts b/src/core/questions/number.ts index 2134904..5e52599 100644 --- a/src/core/questions/number.ts +++ b/src/core/questions/number.ts @@ -1,47 +1,45 @@ -import type Config from "@typing/config"; -import type GPTAnswer from "@typing/gptAnswer"; - -/** - * Handle number input - * @param config - * @param inputList - * @param gptAnswer - * @returns - */ -function handleNumber( - config: Config, - inputList: NodeListOf, - gptAnswer: GPTAnswer -): boolean { - const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement; - - if ( - inputList.length !== 1 || // for now we don't handle many input number - input.type !== "number" - ) { - return false; - } - - const number = gptAnswer.normalizedResponse - .match(/\d+([,.]\d+)?/gi)?.[0] - ?.replace(",", "."); - - if (number === undefined) return false; - - if (config.typing) { - let index = 0; - input.addEventListener("keydown", function (event: Event) { - event.preventDefault(); - if ((event).key === "Backspace") index = number.length + 1; - if (index > number.length) return; - if (number.slice(index, index + 1) === ".") ++index; - input.value = number.slice(0, ++index); - }); - } else { - input.value = number; - } - - return true; -} - -export default handleNumber; +import type Config from '@typing/config'; +import type GPTAnswer from '@typing/gptAnswer'; + +/** + * Handle number input + * @param config + * @param inputList + * @param gptAnswer + * @returns + */ +function handleNumber( + config: Config, + inputList: NodeListOf, + gptAnswer: GPTAnswer +): boolean { + const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement; + + if ( + inputList.length !== 1 || // for now we don't handle many input number + input.type !== 'number' + ) { + return false; + } + + const number = gptAnswer.normalizedResponse.match(/\d+([,.]\d+)?/gi)?.[0]?.replace(',', '.'); + + if (number === undefined) return false; + + if (config.typing) { + let index = 0; + input.addEventListener('keydown', function (event: Event) { + event.preventDefault(); + if ((event).key === 'Backspace') index = number.length + 1; + if (index > number.length) return; + if (number.slice(index, index + 1) === '.') ++index; + input.value = number.slice(0, ++index); + }); + } else { + input.value = number; + } + + return true; +} + +export default handleNumber; diff --git a/src/core/questions/radio.ts b/src/core/questions/radio.ts index 67b5d8d..e903dad 100644 --- a/src/core/questions/radio.ts +++ b/src/core/questions/radio.ts @@ -1,8 +1,8 @@ -import type Config from "@typing/config"; -import type GPTAnswer from "@typing/gptAnswer"; -import Logs from "@utils/logs"; -import normalizeText from "@utils/normalize-text"; -import { pickBestReponse } from "@utils/pick-best-response"; +import type Config from '@typing/config'; +import type GPTAnswer from '@typing/gptAnswer'; +import Logs from '@utils/logs'; +import normalizeText from '@utils/normalize-text'; +import { pickBestReponse } from '@utils/pick-best-response'; /** * Handle input radio elements @@ -18,21 +18,18 @@ function handleRadio( const firstInput = inputList?.[0] as HTMLInputElement; // Handle the case the input is not a radio - if (!firstInput || firstInput.type !== "radio") { + if (!firstInput || firstInput.type !== 'radio') { return false; } const possibleAnswers = Array.from(inputList) - .map((inp) => ({ + .map(inp => ({ element: inp, - value: normalizeText(inp?.parentElement?.textContent ?? ""), + value: normalizeText(inp?.parentElement?.textContent ?? '') })) - .filter((obj) => obj.value !== ""); + .filter(obj => obj.value !== ''); - const bestAnswer = pickBestReponse( - gptAnswer.normalizedResponse, - possibleAnswers - ); + const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers); if (config.logs && bestAnswer.value) { Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity); @@ -40,13 +37,9 @@ function handleRadio( const correctInput = bestAnswer.element as HTMLInputElement; if (config.mouseover) { - correctInput.addEventListener( - "mouseover", - () => (correctInput.checked = true), - { - once: true, - } - ); + correctInput.addEventListener('mouseover', () => (correctInput.checked = true), { + once: true + }); } else { correctInput.checked = true; } diff --git a/src/core/questions/select.ts b/src/core/questions/select.ts index f0e3e58..49cf762 100644 --- a/src/core/questions/select.ts +++ b/src/core/questions/select.ts @@ -1,64 +1,60 @@ -import type Config from "@typing/config"; -import type GPTAnswer from "@typing/gptAnswer"; -import Logs from "@utils/logs"; -import normalizeText from "@utils/normalize-text"; -import { pickBestReponse } from "@utils/pick-best-response"; - -/** - * Handle select elements (and put in order select) - * @param config - * @param inputList - * @param gptAnswer - * @returns - */ -function handleSelect( - config: Config, - inputList: NodeListOf, - gptAnswer: GPTAnswer -): boolean { - if (inputList.length === 0 || inputList[0].tagName !== "SELECT") return false; - - const corrects = gptAnswer.normalizedResponse.split("\n"); - - if (config.logs) Logs.array(corrects); - - for (let i = 0; i < inputList.length; ++i) { - if (!corrects[i]) break; - - const options = inputList[i].querySelectorAll("option"); - - const possibleAnswers = Array.from(options) - .map((opt) => ({ - element: opt, - value: normalizeText(opt.textContent ?? ""), - })) - .filter((obj) => obj.value !== ""); - - const bestAnswer = pickBestReponse(corrects[i], possibleAnswers); - - if (config.logs && bestAnswer.value) { - Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity); - } - - const correctOption = bestAnswer.element as HTMLOptionElement; - const currentSelect = correctOption.closest("select"); - - if (currentSelect === null) continue; - - if (config.mouseover) { - currentSelect.addEventListener( - "click", - () => (correctOption.selected = true), - { - once: true, - } - ); - } else { - correctOption.selected = true; - } - } - - return true; -} - -export default handleSelect; +import type Config from '@typing/config'; +import type GPTAnswer from '@typing/gptAnswer'; +import Logs from '@utils/logs'; +import normalizeText from '@utils/normalize-text'; +import { pickBestReponse } from '@utils/pick-best-response'; + +/** + * Handle select elements (and put in order select) + * @param config + * @param inputList + * @param gptAnswer + * @returns + */ +function handleSelect( + config: Config, + inputList: NodeListOf, + gptAnswer: GPTAnswer +): boolean { + if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false; + + const corrects = gptAnswer.normalizedResponse.split('\n'); + + if (config.logs) Logs.array(corrects); + + for (let i = 0; i < inputList.length; ++i) { + if (!corrects[i]) break; + + const options = inputList[i].querySelectorAll('option'); + + const possibleAnswers = Array.from(options) + .map(opt => ({ + element: opt, + value: normalizeText(opt.textContent ?? '') + })) + .filter(obj => obj.value !== ''); + + const bestAnswer = pickBestReponse(corrects[i], possibleAnswers); + + if (config.logs && bestAnswer.value) { + Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity); + } + + const correctOption = bestAnswer.element as HTMLOptionElement; + const currentSelect = correctOption.closest('select'); + + if (currentSelect === null) continue; + + if (config.mouseover) { + currentSelect.addEventListener('click', () => (correctOption.selected = true), { + once: true + }); + } else { + correctOption.selected = true; + } + } + + return true; +} + +export default handleSelect; diff --git a/src/core/questions/textbox.ts b/src/core/questions/textbox.ts index b817fa0..810c883 100644 --- a/src/core/questions/textbox.ts +++ b/src/core/questions/textbox.ts @@ -1,42 +1,42 @@ -import type Config from "@typing/config"; -import type GPTAnswer from "@typing/gptAnswer"; - -/** - * Handle textbox - * @param config - * @param inputList - * @param gptAnswer - * @returns - */ -function handleTextbox( - config: Config, - inputList: NodeListOf, - gptAnswer: GPTAnswer -): boolean { - const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement; - - if ( - inputList.length !== 1 || // for now we don't handle many input text - (input.tagName !== "TEXTAREA" && input.type !== "text") - ) { - return false; - } - - if (config.typing) { - let index = 0; - input.addEventListener("keydown", function (event: Event) { - event.preventDefault(); - if ((event).key === "Backspace") { - index = gptAnswer.response.length + 1; - } - if (index > gptAnswer.response.length) return; - input.value = gptAnswer.response.slice(0, ++index); - }); - } else { - input.value = gptAnswer.response; - } - - return true; -} - -export default handleTextbox; +import type Config from '@typing/config'; +import type GPTAnswer from '@typing/gptAnswer'; + +/** + * Handle textbox + * @param config + * @param inputList + * @param gptAnswer + * @returns + */ +function handleTextbox( + config: Config, + inputList: NodeListOf, + gptAnswer: GPTAnswer +): boolean { + const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement; + + if ( + inputList.length !== 1 || // for now we don't handle many input text + (input.tagName !== 'TEXTAREA' && input.type !== 'text') + ) { + return false; + } + + if (config.typing) { + let index = 0; + input.addEventListener('keydown', function (event: Event) { + event.preventDefault(); + if ((event).key === 'Backspace') { + index = gptAnswer.response.length + 1; + } + if (index > gptAnswer.response.length) return; + input.value = gptAnswer.response.slice(0, ++index); + }); + } else { + input.value = gptAnswer.response; + } + + return true; +} + +export default handleTextbox; diff --git a/src/core/reply.ts b/src/core/reply.ts index f7aba91..84e619e 100644 --- a/src/core/reply.ts +++ b/src/core/reply.ts @@ -1,81 +1,76 @@ -import type Config from "@typing/config"; -import Logs from "@utils/logs"; -import getChatGPTResponse from "./get-response"; -import createAndNormalizeQuestion from "./create-question"; -import clipboardMode from "./modes/clipboard"; -import questionToAnswerMode from "./modes/question-to-answer"; -import autoCompleteMode from "./modes/autocomplete"; - -type Props = { - config: Config; - questionElement: HTMLElement; - form: HTMLElement; - inputQuery: string; - removeListener: () => void; -}; - -/** - * Reply to the question - * @param props - * @returns - */ -async function reply(props: Props): Promise { - if (props.config.cursor) props.questionElement.style.cursor = "wait"; - - const question = createAndNormalizeQuestion(props.form); - const inputList: NodeListOf = props.form.querySelectorAll( - props.inputQuery - ); - - const gptAnswer = await getChatGPTResponse(props.config, question).catch( - (error) => ({ - error, - }) - ); - - const haveError = typeof gptAnswer === "object" && "error" in gptAnswer; - - if (props.config.cursor) { - props.questionElement.style.cursor = - props.config.infinite || haveError ? "pointer" : "initial"; - } - - if (haveError) { - console.error(gptAnswer.error); - return; - } - - if (props.config.logs) { - Logs.question(question); - Logs.response(gptAnswer); - } - - switch (props.config.mode) { - case "clipboard": - clipboardMode({ - config: props.config, - questionElement: props.questionElement, - gptAnswer, - removeListener: props.removeListener, - }); - break; - case "question-to-answer": - questionToAnswerMode({ - gptAnswer, - questionElement: props.questionElement, - removeListener: props.removeListener, - }); - break; - case "autocomplete": - autoCompleteMode({ - config: props.config, - gptAnswer, - inputList, - questionElement: props.questionElement, - removeListener: props.removeListener, - }); - break; - } -} - -export default reply; +import type Config from '@typing/config'; +import Logs from '@utils/logs'; +import getChatGPTResponse from './get-response'; +import createAndNormalizeQuestion from './create-question'; +import clipboardMode from './modes/clipboard'; +import questionToAnswerMode from './modes/question-to-answer'; +import autoCompleteMode from './modes/autocomplete'; + +type Props = { + config: Config; + questionElement: HTMLElement; + form: HTMLElement; + inputQuery: string; + removeListener: () => void; +}; + +/** + * Reply to the question + * @param props + * @returns + */ +async function reply(props: Props): Promise { + if (props.config.cursor) props.questionElement.style.cursor = 'wait'; + + const question = createAndNormalizeQuestion(props.form); + const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery); + + const gptAnswer = await getChatGPTResponse(props.config, question).catch(error => ({ + error + })); + + const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer; + + if (props.config.cursor) { + props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial'; + } + + if (haveError) { + console.error(gptAnswer.error); + return; + } + + if (props.config.logs) { + Logs.question(question); + Logs.response(gptAnswer); + } + + switch (props.config.mode) { + case 'clipboard': + clipboardMode({ + config: props.config, + questionElement: props.questionElement, + gptAnswer, + removeListener: props.removeListener + }); + break; + case 'question-to-answer': + questionToAnswerMode({ + gptAnswer, + questionElement: props.questionElement, + removeListener: props.removeListener + }); + break; + case 'autocomplete': + autoCompleteMode({ + config: props.config, + gptAnswer, + inputList, + questionElement: props.questionElement, + removeListener: props.removeListener + }); + break; + } +} + +export default reply; diff --git a/src/index.ts b/src/index.ts index 804df57..fa5c8ae 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,14 +1,14 @@ -import type Config from "@typing/config"; -import { codeListener, setUpMoodleGpt } from "./core/code-listener"; - -chrome.storage.sync.get(["moodleGPT"]).then(function (storage) { - const config: Config = storage.moodleGPT; - - if (!config) throw new Error("Please configure MoodleGPT into the extension"); - - if (config.code) { - codeListener(config); - } else { - setUpMoodleGpt(config); - } -}); +import type Config from '@typing/config'; +import { codeListener, setUpMoodleGpt } from './core/code-listener'; + +chrome.storage.sync.get(['moodleGPT']).then(function (storage) { + const config: Config = storage.moodleGPT; + + if (!config) throw new Error('Please configure MoodleGPT into the extension'); + + if (config.code) { + codeListener(config); + } else { + setUpMoodleGpt(config); + } +}); diff --git a/src/types/config.ts b/src/types/config.ts index c317e68..ab8205a 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -10,7 +10,7 @@ type Config = { title?: boolean; timeout?: boolean; history?: boolean; - mode?: "autocomplete" | "question-to-answer" | "clipboard"; + mode?: 'autocomplete' | 'question-to-answer' | 'clipboard'; }; export default Config; diff --git a/src/utils/html-table-to-string.ts b/src/utils/html-table-to-string.ts index c06ae6d..507e794 100644 --- a/src/utils/html-table-to-string.ts +++ b/src/utils/html-table-to-string.ts @@ -5,37 +5,32 @@ */ function htmlTableToString(table: HTMLTableElement) { const tab: string[][] = []; - const lines = Array.from(table.querySelectorAll("tr")); + const lines = Array.from(table.querySelectorAll('tr')); const maxColumnsLength: number[] = []; - lines.map((line) => { - const cells = Array.from(line.querySelectorAll("td, th")); + lines.map(line => { + const cells = Array.from(line.querySelectorAll('td, th')); const cellsContent = cells.map((cell, index) => { const content = cell.textContent?.trim(); - maxColumnsLength[index] = Math.max( - maxColumnsLength[index] || 0, - content?.length || 0 - ); - return content ?? ""; + 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 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 mappedTab = tab.map(line => { const mappedLine = line.map((content, index) => content.padEnd( maxColumnsLength[index], - "\u00A0" // For no matching with \s + '\u00A0' // For no matching with \s ) ); - return "| " + mappedLine.join(" | ") + " |"; + return '| ' + mappedLine.join(' | ') + ' |'; }); const head = mappedTab.shift(); - return head + lineSeparation + mappedTab.join("\n"); + return head + lineSeparation + mappedTab.join('\n'); } export default htmlTableToString; diff --git a/src/utils/logs.ts b/src/utils/logs.ts index 0483ddb..eb4a9d1 100644 --- a/src/utils/logs.ts +++ b/src/utils/logs.ts @@ -1,29 +1,29 @@ -import GPTAnswer from "@typing/gptAnswer"; -import { toPourcentage } from "./pick-best-response"; - -class Logs { - static question(text: string) { - const css = "color: cyan"; - console.log("%c[QUESTION]: %s", css, text); - } - - static bestAnswer(answer: string, similarity: number) { - const css = "color: green"; - console.log( - "%c[BEST ANSWER]: %s", - css, - `"${answer}" with a similarity of ${toPourcentage(similarity)}` - ); - } - - static array(arr: unknown[]) { - console.log("[CORRECTS] ", arr); - } - - static response(gptAnswer: GPTAnswer) { - console.log("Original:\n" + gptAnswer.response); - console.log("Normalized:\n" + gptAnswer.normalizedResponse); - } -} - -export default Logs; +import GPTAnswer from '@typing/gptAnswer'; +import { toPourcentage } from './pick-best-response'; + +class Logs { + static question(text: string) { + const css = 'color: cyan'; + console.log('%c[QUESTION]: %s', css, text); + } + + static bestAnswer(answer: string, similarity: number) { + const css = 'color: green'; + console.log( + '%c[BEST ANSWER]: %s', + css, + `"${answer}" with a similarity of ${toPourcentage(similarity)}` + ); + } + + static array(arr: unknown[]) { + console.log('[CORRECTS] ', arr); + } + + static response(gptAnswer: GPTAnswer) { + console.log('Original:\n' + gptAnswer.response); + console.log('Normalized:\n' + gptAnswer.normalizedResponse); + } +} + +export default Logs; diff --git a/src/utils/normalize-text.ts b/src/utils/normalize-text.ts index a5321a4..2945ab3 100644 --- a/src/utils/normalize-text.ts +++ b/src/utils/normalize-text.ts @@ -1,20 +1,20 @@ -/** - * Normlize text - * @param text - */ -function normalizeText(text: string, toLowerCase: boolean = true) { - if (toLowerCase) text = text.toLowerCase(); - - const normalizedText = text - .replace(/\n+/gi, "\n") //remove duplicate new lines - .replace(/(\n\s*\n)+/g, "\n") //remove useless white space from textcontent - .replace(/[ \t]+/gi, " ") //replace multiples space or tabs by a space - .trim() - // We remove the following content because sometimes ChatGPT will reply: "answer d" - .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 - - return normalizedText; -} - -export default normalizeText; +/** + * Normlize text + * @param text + */ +function normalizeText(text: string, toLowerCase: boolean = true) { + if (toLowerCase) text = text.toLowerCase(); + + const normalizedText = text + .replace(/\n+/gi, '\n') //remove duplicate new lines + .replace(/(\n\s*\n)+/g, '\n') //remove useless white space from textcontent + .replace(/[ \t]+/gi, ' ') //replace multiples space or tabs by a space + .trim() + // We remove the following content because sometimes ChatGPT will reply: "answer d" + .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 + + return normalizedText; +} + +export default normalizeText; diff --git a/src/utils/pick-best-response.ts b/src/utils/pick-best-response.ts index 7956419..e523952 100644 --- a/src/utils/pick-best-response.ts +++ b/src/utils/pick-best-response.ts @@ -21,8 +21,8 @@ function levenshteinDistance(str1: string, str2: string) { if (str2.length === 0) return str1.length; const matrix: number[][] = []; - const str1WithoutSpaces = str1.replace(/\s+/, ""); - const str2WithoutSpaces = str2.replace(/\s+/, ""); + const str1WithoutSpaces = str1.replace(/\s+/, ''); + const str2WithoutSpaces = str2.replace(/\s+/, ''); for (let i = 0; i <= str1WithoutSpaces.length; ++i) { matrix.push([i]); @@ -33,8 +33,7 @@ function levenshteinDistance(str1: string, str2: string) { : Math.min( matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, - matrix[i - 1][j - 1] + - (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1) + matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1) ); } } @@ -67,7 +66,7 @@ export function pickBestReponse( let bestResponse: BestResponse = { element: null, similarity: 0, - value: null, + value: null }; for (const obj of arr) { const similarity = sentenceSimilarity(obj.value, answer); @@ -100,7 +99,7 @@ export function pickResponsesWithSimilarityGreaterThan( responses.push({ similarity, value: obj.value, - element: obj.element, + element: obj.element }); } return responses.sort((a, b) => a.similarity - b.similarity); @@ -111,5 +110,5 @@ export function pickResponsesWithSimilarityGreaterThan( * @param similarity */ export function toPourcentage(similarity: number): string { - return Math.round(similarity * 100 * 100) / 100 + "%"; + return Math.round(similarity * 100 * 100) / 100 + '%'; } diff --git a/src/utils/title-indications.ts b/src/utils/title-indications.ts index 65c7506..32b94dd 100644 --- a/src/utils/title-indications.ts +++ b/src/utils/title-indications.ts @@ -1,11 +1,11 @@ -/** - * Show some informations into the document title and remove it after 3000ms - * @param text - */ -function titleIndications(text: string) { - const backTitle = document.title; - document.title = text; - setTimeout(() => (document.title = backTitle), 3000); -} - -export default titleIndications; +/** + * Show some informations into the document title and remove it after 3000ms + * @param text + */ +function titleIndications(text: string) { + const backTitle = document.title; + document.title = text; + setTimeout(() => (document.title = backTitle), 3000); +} + +export default titleIndications; diff --git a/test/fake-moodle/css/style.css b/test/fake-moodle/css/style.css index bc8746f..3fe7434 100644 --- a/test/fake-moodle/css/style.css +++ b/test/fake-moodle/css/style.css @@ -7,7 +7,7 @@ box-sizing: border-box; padding: 0; margin: 0; - font-family: "Segeo UI"; + font-family: 'Segeo UI'; } body { diff --git a/test/fake-moodle/index.html b/test/fake-moodle/index.html index 4b333fe..93abd99 100644 --- a/test/fake-moodle/index.html +++ b/test/fake-moodle/index.html @@ -1,4 +1,4 @@ - + @@ -17,23 +17,20 @@
a. Systems Administrator: Managing and maintaining computer systems and + networks.
b. Software Developer: Designing, coding, testing, and maintaining software + applications.
- +
@@ -276,8 +273,8 @@

- Gives a "reverseWorld" function in javascript which takes as a - parameter a word and flips it in the opposite direction + Gives a "reverseWorld" function in javascript which takes as a parameter a word and flips + it in the opposite direction

diff --git a/test/reset-moodle-inputs/reset.js b/test/reset-moodle-inputs/reset.js index 2ba4d86..9675c46 100644 --- a/test/reset-moodle-inputs/reset.js +++ b/test/reset-moodle-inputs/reset.js @@ -1,21 +1,19 @@ /* Reset real moodle inputs to try in real env */ -for (const option of document.querySelectorAll("option")) { +for (const option of document.querySelectorAll('option')) { option.selected = false; option.disabled = false; - option.closest("select").disabled = false; + option.closest('select').disabled = false; } -for (const input of document.querySelectorAll( - 'input[type="radio"], input[type="checkbox"]' -)) { +for (const input of document.querySelectorAll('input[type="radio"], input[type="checkbox"]')) { input.checked = false; input.disabled = false; } -for (const icon of document.querySelectorAll(".text-danger, .text-success")) { +for (const icon of document.querySelectorAll('.text-danger, .text-success')) { icon.remove(); } -for (const feedback of document.querySelectorAll(".specificfeedback")) { +for (const feedback of document.querySelectorAll('.specificfeedback')) { feedback.remove(); } diff --git a/tsconfig.json b/tsconfig.json index 3be788f..e6bdc50 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,25 +1,25 @@ -{ - "compilerOptions": { - "strict": true, - "baseUrl": "src", - "module": "CommonJS", - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "target": "ES6", - "noImplicitAny": true, - "moduleResolution": "node", - "sourceMap": true, - "outDir": "extension", - "resolveJsonModule": true, - "types": ["node", "chrome"], - "typeRoots": ["node_modules/@types"], - "strictBindCallApply": true, - "paths": { - "@typing/*": ["types/*"], - "@utils/*": ["utils/*"], - "@core/*": ["core/*"], - "@questions/*": ["core/question/*"] - } - }, - "include": ["src/**/*"] -} +{ + "compilerOptions": { + "strict": true, + "baseUrl": "src", + "module": "CommonJS", + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "target": "ES6", + "noImplicitAny": true, + "moduleResolution": "node", + "sourceMap": true, + "outDir": "extension", + "resolveJsonModule": true, + "types": ["node", "chrome"], + "typeRoots": ["node_modules/@types"], + "strictBindCallApply": true, + "paths": { + "@typing/*": ["types/*"], + "@utils/*": ["utils/*"], + "@core/*": ["core/*"], + "@questions/*": ["core/question/*"] + } + }, + "include": ["src/**/*"] +} From b0da1a0967ffcbba736c7d00bcb1d264d7866465 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 20:16:53 -0500 Subject: [PATCH 26/87] updated assets --- assets/logs.png | Bin 21226 -> 36651 bytes assets/settings.png | Bin 10441 -> 8193 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/logs.png b/assets/logs.png index 612d7f7962bdf842c34bbd528b5b010eec6bb74b..918914d25124b062023753e1d4b9c9ec1e1ce6df 100644 GIT binary patch literal 36651 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 Z{|6jCwIS1uqc{Kn002ovPDHLkV1nUuVx|B9 literal 21226 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 -# MoodleGPT +# MoodleGPT 1.1.0 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,13 +12,12 @@ Find the extension on the Chrome Webstore right [here](https://chrome.google.com ## Summary -- [MoodleGPT](#moodlegpt) +- [MoodleGPT 1.1.0](#moodlegpt-110) - [Chrome Webstore](#chrome-webstore) - [Summary](#summary) - [Disclaimer !](#disclaimer-) - [Donate](#donate) - [Update](#update) - - [MoodleGPT don't complete my quiz ?](#moodlegpt-dont-complete-my-quiz-) - [Set up](#set-up) - [Inject the code into the moodle](#inject-the-code-into-the-moodle) - [Remove injection](#remove-injection) @@ -50,11 +49,7 @@ Will be a pleasure if you want to support this project :) ## Update -See [changelog](./CHANGELOG.md) - -## MoodleGPT don't complete my quiz ? - -If MoodleGPT cannot complete one of your moodle quiz please provide the html code of the page. It will help us to add it in the futur version of MoodleGPT ! Check the [TODO](./TODO.md) to see what is comming in the futur version. +See the [changelog](./CHANGELOG.md) to see every updates ! ## Set up @@ -72,7 +67,7 @@ You just need to enter on the keyboard the code you have set into the ext ## Remove injection -Type back the code on the keyboard and the code will be removed from the current page. +Type back the code you entered into the extension configuration on the keyboard and the injection will be removed from the current page. If You didn't provide a code into the extension then there is no way to remove the injection. ## Mode @@ -97,7 +92,7 @@ Type back the code on the keyboard and the code will be removed from the - Cursor indication: show a pointer cursor and a hourglass to know when the request is finished. - Title indication: show some informations into the title to know for example if the code have been injected.
![Injected](./assets/title-injected.png) -- Console logs: show logs into the console. +- Console logs: show logs into the console for the question, chatgpt answer and which response has been chosen.
Logs - 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. @@ -105,8 +100,8 @@ Type back the code on the keyboard and the code will be removed from the - Mouseover effect: you will need to hover (or click for select) the question response to complete it automaticaly.
![Mouseover](./assets/mouseover.gif)
![Mouseover2](./assets/mouseover2.gif) - - Infinite try: click as much as you want on the question (don't forget to reset the question). +- Save history: allows you to create a conversation with ChatGPT by saving the previous question with its answer. However, note that it can consume a significant number of tokens. ## Internal Features From 66f988e9c62f66848c83cafea66daef66eec7be0 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 20:17:32 -0500 Subject: [PATCH 30/87] Update TODO.md --- TODO.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index 0e08c01..9370291 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,7 @@ # TODO - Historic for questions (implemented but need testing) -- Contributing.md / Fixe readme.md 'MoodleGPT don't complete my quiz ?' +- Contributing.md - Better prompt (Fixe put in order question, Fixe calculation question) - Support math equation from image stocked in the `data-mathml` attribute -- Better assets +- Better webstore assets From 7d0d52865faa75fd6d2cbb3ea82eaaf76f1c566e Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 20:17:46 -0500 Subject: [PATCH 31/87] Update TODO.md --- TODO.md | 1 - 1 file changed, 1 deletion(-) diff --git a/TODO.md b/TODO.md index 9370291..036f1b3 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,6 @@ # TODO - Historic for questions (implemented but need testing) -- Contributing.md - Better prompt (Fixe put in order question, Fixe calculation question) - Support math equation from image stocked in the `data-mathml` attribute - Better webstore assets From 65cad4a3138bbea98933580b13683811faece954 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 20:17:55 -0500 Subject: [PATCH 32/87] version update --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 24603de..df86bc2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "moodlegpt", - "version": "1.0.4", + "version": "1.1.0", "description": "This extension allows you to hide CHAT-GPT in a Moodle quiz.", "scripts": { "build": "rollup -c", From ab2d7bb2822455c58dcbd841994cfa75bba0e9e0 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 20:18:04 -0500 Subject: [PATCH 33/87] version update --- extension/popup/js/version.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/popup/js/version.js b/extension/popup/js/version.js index 095e30e..8026744 100644 --- a/extension/popup/js/version.js +++ b/extension/popup/js/version.js @@ -1,6 +1,6 @@ 'use strict'; -const CURRENT_VERSION = '1.0.4'; +const CURRENT_VERSION = '1.1.0'; const versionDisplay = document.querySelector('#version'); /** From 138a39e71e6f40a531316bb6b5a18b61228f9a45 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 20:18:14 -0500 Subject: [PATCH 34/87] build --- extension/MoodleGPT.js | 419 +------------------------------------ extension/MoodleGPT.js.map | 2 +- extension/manifest.json | 2 +- 3 files changed, 3 insertions(+), 420 deletions(-) diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index 1c4959d..3df2e1d 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,419 +1,2 @@ -!(function (e) { - 'function' == typeof define && define.amd ? define(e) : e(); -})(function () { - 'use strict'; - function e(e) { - const n = document.title; - (document.title = e), setTimeout(() => (document.title = n), 3e3); - } - function n(e, n, t, o) { - return new (t || (t = Promise))(function (r, i) { - function s(e) { - try { - c(o.next(e)); - } catch (e) { - i(e); - } - } - function l(e) { - try { - c(o.throw(e)); - } catch (e) { - i(e); - } - } - function c(e) { - var n; - e.done - ? r(e.value) - : ((n = e.value), - n instanceof t - ? n - : new t(function (e) { - e(n); - })).then(s, l); - } - c((o = o.apply(e, n || [])).next()); - }); - } - function t(e, n) { - const t = e.length > n.length ? e.length : n.length; - return 0 === t - ? 1 - : (t - - (function (e, n) { - if (0 === e.length) return n.length; - if (0 === n.length) return e.length; - const t = [], - o = e.replace(/\s+/, ''), - r = n.replace(/\s+/, ''); - for (let e = 0; e <= o.length; ++e) { - t.push([e]); - for (let n = 1; n <= r.length; ++n) - t[e][n] = - 0 === e - ? n - : Math.min( - t[e - 1][n] + 1, - t[e][n - 1] + 1, - t[e - 1][n - 1] + (o[e - 1] === r[n - 1] ? 0 : 1) - ); - } - return t[o.length][r.length]; - })(e, n)) / - t; - } - function o(e, n) { - let o = { element: null, similarity: 0, value: null }; - for (const r of n) { - const n = t(r.value, e); - if (1 === n) return { element: r.element, value: r.value, similarity: n }; - n > o.similarity && (o = { element: r.element, value: r.value, similarity: n }); - } - return o; - } - 'function' == typeof SuppressedError && SuppressedError; - class r { - static question(e) { - console.log('%c[QUESTION]: %s', 'color: cyan', e); - } - static bestAnswer(e, n) { - console.log( - '%c[BEST ANSWER]: %s', - 'color: green', - `"${e}" with a similarity of ${(function (e) { - return Math.round(100 * e * 100) / 100 + '%'; - })(n)}` - ); - } - static array(e) { - console.log('[CORRECTS] ', e); - } - static response(e) { - console.log('Original:\n' + e.response), console.log('Normalized:\n' + e.normalizedResponse); - } - } - function i(e, n = !0) { - return ( - n && (e = e.toLowerCase()), - e - .replace(/\n+/gi, '\n') - .replace(/(\n\s*\n)+/g, '\n') - .replace(/[ \t]+/gi, ' ') - .trim() - .replace(/^[a-z\d]\.\s/gi, '') - .replace(/\n[a-z\d]\.\s/gi, '\n') - ); - } - var s; - !(function (e) { - (e.SYSTEM = 'system'), (e.USER = 'user'), (e.ASSISTANT = 'assistant'); - })(s || (s = {})); - const l = - "\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(), - c = { url: null, system: { role: s.SYSTEM, content: l }, history: [] }; - function a(e) { - const n = [], - t = Array.from(e.querySelectorAll('tr')), - o = []; - t.map(e => { - const t = Array.from(e.querySelectorAll('td, th')).map((e, n) => { - var t; - const r = null === (t = e.textContent) || void 0 === t ? void 0 : t.trim(); - return ( - (o[n] = Math.max(o[n] || 0, (null == r ? void 0 : r.length) || 0)), null != r ? r : '' - ); - }); - n.push(t); - }); - const r = o.reduce((e, n) => e + n) + 3 * n[0].length + 1, - i = '\n' + Array(r).fill('-').join('') + '\n', - s = n.map(e => '| ' + e.map((e, n) => e.padEnd(o[n], ' ')).join(' | ') + ' |'); - return s.shift() + i + s.join('\n'); - } - function u(n, t) { - n.title && e('Copied to clipboard'), navigator.clipboard.writeText(t.response); - } - function f(e, n, t) { - const o = n[0]; - if (1 !== n.length || 'true' !== o.getAttribute('contenteditable')) return !1; - if (e.typing) { - let e = 0; - o.addEventListener('keydown', function (n) { - if (('Backspace' === n.key && (e = t.response.length + 1), e > t.response.length)) return; - n.preventDefault(), (o.textContent = t.response.slice(0, ++e)), o.focus(); - const r = document.createRange(); - r.selectNodeContents(o), r.collapse(!1); - const i = window.getSelection(); - null !== i && (i.removeAllRanges(), i.addRange(r)); - }); - } else o.textContent = t.response; - return !0; - } - function d(e, n, t) { - var o, r; - const i = n[0]; - if (1 !== n.length || 'number' !== i.type) return !1; - const s = - null === - (r = - null === (o = t.normalizedResponse.match(/\d+([,\.]\d+)?/gi)) || void 0 === o - ? void 0 - : o[0]) || void 0 === r - ? void 0 - : r.replace(',', '.'); - if (void 0 === s) return !1; - if (e.typing) { - let e = 0; - i.addEventListener('keydown', function (n) { - n.preventDefault(), - 'Backspace' === n.key && (e = s.length + 1), - e > s.length || ('.' === s.slice(e, e + 1) && ++e, (i.value = s.slice(0, ++e))); - }); - } else i.value = s; - return !0; - } - function m(e, n, t) { - const s = null == n ? void 0 : n[0]; - if (!s || 'radio' !== s.type) return !1; - const l = Array.from(n) - .map(e => { - var n, t; - return { - element: e, - value: i( - null !== - (t = - null === (n = null == e ? void 0 : e.parentElement) || void 0 === n - ? void 0 - : n.textContent) && void 0 !== t - ? t - : '' - ) - }; - }) - .filter(e => '' !== e.value), - c = o(t.normalizedResponse, l); - e.logs && c.value && r.bestAnswer(c.value, c.similarity); - const a = c.element; - return ( - e.mouseover - ? a.addEventListener('mouseover', () => (a.checked = !0), { once: !0 }) - : (a.checked = !0), - !0 - ); - } - function p(e, n, t) { - const s = null == n ? void 0 : n[0]; - if (!s || 'checkbox' !== s.type) return !1; - const l = t.normalizedResponse.split('\n'), - c = Array.from(n) - .map(e => { - var n, t; - return { - element: e, - value: i( - null !== - (t = - null === (n = null == e ? void 0 : e.parentElement) || void 0 === n - ? void 0 - : n.textContent) && void 0 !== t - ? t - : '' - ) - }; - }) - .filter(e => '' !== e.value); - for (const n of l) { - const t = o(n, c); - e.logs && t.value && r.bestAnswer(t.value, t.similarity); - const i = t.element; - e.mouseover - ? i.addEventListener('mouseover', () => (i.checked = !0), { once: !0 }) - : (i.checked = !0); - } - return !0; - } - function h(e, n, t) { - if (0 === n.length || 'SELECT' !== n[0].tagName) return !1; - const s = t.normalizedResponse.split('\n'); - e.logs && r.array(s); - for (let t = 0; t < n.length && s[t]; ++t) { - const l = n[t].querySelectorAll('option'), - c = Array.from(l) - .map(e => { - var n; - return { - element: e, - value: i(null !== (n = e.textContent) && void 0 !== n ? n : '') - }; - }) - .filter(e => '' !== e.value), - a = o(s[t], c); - e.logs && a.value && r.bestAnswer(a.value, a.similarity); - const u = a.element, - f = u.closest('select'); - null !== f && - (e.mouseover - ? f.addEventListener('click', () => (u.selected = !0), { once: !0 }) - : (u.selected = !0)); - } - return !0; - } - function g(e, n, t) { - const o = n[0]; - if (1 !== n.length || ('TEXTAREA' !== o.tagName && 'text' !== o.type)) return !1; - if (e.typing) { - let e = 0; - o.addEventListener('keydown', function (n) { - n.preventDefault(), - 'Backspace' === n.key && (e = t.response.length + 1), - e > t.response.length || (o.value = t.response.slice(0, ++e)); - }); - } else o.value = t.response; - return !0; - } - function v(e) { - return n(this, void 0, void 0, function* () { - e.config.cursor && (e.questionElement.style.cursor = 'wait'); - const t = (function (e) { - let n = e.innerText; - const t = e.querySelectorAll('.accesshide'); - for (const e of t) n = n.replace(e.innerText, ''); - const o = e.querySelectorAll('.qtext table'); - for (const e of o) n = n.replace(e.innerText, '\n' + a(e) + '\n'); - return i(n, !1); - })(e.form), - o = e.form.querySelectorAll(e.inputQuery), - l = yield (function (e, t) { - return n(this, void 0, void 0, function* () { - const n = location.hostname + location.pathname; - (e.history && c.url === n) || ((c.url = n), (c.history = [])); - const o = new AbortController(), - r = setTimeout(() => o.abort(), 15e3), - l = { role: s.USER, content: t }, - a = yield fetch('https://api.openai.com/v1/chat/completions', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${e.apiKey}` - }, - signal: e.timeout ? o.signal : null, - body: JSON.stringify({ - model: e.model, - messages: [c.system, ...c.history, l], - temperature: 0.8, - top_p: 1, - presence_penalty: 1, - stop: null - }) - }); - clearTimeout(r); - const u = (yield a.json()).choices[0].message.content; - return ( - e.history && (c.history.push(l), c.history.push({ role: s.ASSISTANT, content: u })), - { question: t, response: u, normalizedResponse: i(u) } - ); - }); - })(e.config, t).catch(e => ({ error: e })), - v = 'object' == typeof l && 'error' in l; - if ( - (e.config.cursor && - (e.questionElement.style.cursor = e.config.infinite || v ? 'pointer' : 'initial'), - v) - ) - console.error(l.error); - else - switch ((e.config.logs && (r.question(t), r.response(l)), e.config.mode)) { - case 'clipboard': - !(function (e) { - e.config.infinite || e.removeListener(), u(e.config, e.gptAnswer); - })({ - config: e.config, - questionElement: e.questionElement, - gptAnswer: l, - removeListener: e.removeListener - }); - break; - case 'question-to-answer': - !(function (e) { - const n = e.questionElement; - e.removeListener(); - const t = n.textContent; - (n.textContent = e.gptAnswer.response), - (n.style.whiteSpace = 'pre-wrap'), - n.addEventListener('click', function () { - (n.style.whiteSpace = ''), (n.textContent = t); - }); - })({ - gptAnswer: l, - questionElement: e.questionElement, - removeListener: e.removeListener - }); - break; - case 'autocomplete': - !(function (e) { - e.config.infinite || e.removeListener(); - const n = [f, g, d, h, m, p]; - for (const t of n) if (t(e.config, e.inputList, e.gptAnswer)) return; - u(e.config, e.gptAnswer); - })({ - config: e.config, - gptAnswer: l, - inputList: o, - questionElement: e.questionElement, - removeListener: e.removeListener - }); - } - }); - } - const y = [], - w = []; - function A(e) { - const n = w.findIndex(n => n.element === e); - if (-1 !== n) { - const e = w.splice(n, 1)[0]; - e.element.removeEventListener('click', e.fn); - } - } - function E(n) { - if (w.length > 0) { - for (const e of w) - n.cursor && (e.element.style.cursor = 'initial'), - e.element.removeEventListener('click', e.fn); - return n.title && e('Removed'), void (w.length = 0); - } - const t = - ['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'); - if (null === o) continue; - n.cursor && (o.style.cursor = 'pointer'); - const r = v.bind(null, { - config: n, - questionElement: o, - form: e, - inputQuery: t, - removeListener: () => A(o) - }); - w.push({ element: o, fn: r }), o.addEventListener('click', r); - } - n.title && e('Injected'); - } - chrome.storage.sync.get(['moodleGPT']).then(function (e) { - const n = e.moodleGPT; - if (!n) throw new Error('Please configure MoodleGPT into the extension'); - n.code - ? (function (e) { - document.body.addEventListener('keydown', function (n) { - y.push(n.key), - y.length > e.code.length && y.shift(), - y.join('') === e.code && ((y.length = 0), E(e)); - }); - })(n) - : E(n); - }); -}); +!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={}));const l="\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),c={url:null,system:{role:s.SYSTEM,content:l},history:[]};function a(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function u(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function f(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function d(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function p(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function m(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function h(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function g(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function v(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+a(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),l=yield function(e,t){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&c.url===n||(c.url=n,c.history=[]);const o=new AbortController,r=setTimeout((()=>o.abort()),15e3),l={role:s.USER,content:t},a=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?o.signal:null,body:JSON.stringify({model:e.model,messages:[c.system,...c.history,l],temperature:.8,top_p:1,presence_penalty:1,stop:null})});clearTimeout(r);const u=(yield a.json()).choices[0].message.content;return e.history&&(c.history.push(l),c.history.push({role:s.ASSISTANT,content:u})),{question:t,response:u,normalizedResponse:i(u)}}))}(e.config,t).catch((e=>({error:e}))),v="object"==typeof l&&"error"in l;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||v?"pointer":"initial"),v)console.error(l.error);else switch(e.config.logs&&(r.question(t),r.response(l)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),u(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:l,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:l,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[f,g,d,h,p,m];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;u(e.config,e.gptAnswer)}({config:e.config,gptAnswer:l,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const y=[],w=[];function A(e){const n=w.findIndex((n=>n.element===e));if(-1!==n){const e=w.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function E(n){if(w.length>0){for(const e of w)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(w.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=v.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>A(o)});w.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){y.push(n.key),y.length>e.code.length&&y.shift(),y.join("")===e.code&&(y.length=0,E(e))}))}(n):E(n)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index 3d3eac4..cd0322c 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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/core/get-response.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\r\n similarity: number;\r\n value: string | null;\r\n element: HTMLElement | null;\r\n};\r\n\r\ntype ResponsesBySimilarity = {\r\n similarity: number;\r\n value: string;\r\n element: HTMLElement;\r\n};\r\n\r\n/**\r\n * Calculate the levenshtein distance between two sentence\r\n * @param str1\r\n * @param str2\r\n * @returns\r\n */\r\nfunction levenshteinDistance(str1: string, str2: string) {\r\n if (str1.length === 0) return str2.length;\r\n if (str2.length === 0) return str1.length;\r\n\r\n const matrix: number[][] = [];\r\n const str1WithoutSpaces = str1.replace(/\\s+/, \"\");\r\n const str2WithoutSpaces = str2.replace(/\\s+/, \"\");\r\n\r\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\r\n matrix.push([i]);\r\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\r\n matrix[i][j] =\r\n i === 0\r\n ? j\r\n : Math.min(\r\n matrix[i - 1][j] + 1,\r\n matrix[i][j - 1] + 1,\r\n matrix[i - 1][j - 1] +\r\n (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\r\n );\r\n }\r\n }\r\n\r\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\r\n}\r\n\r\n/**\r\n * Calculate the similarity between two sentences from 0 to 1 (best)\r\n * @param str1\r\n * @param str2\r\n * @returns\r\n */\r\nfunction sentenceSimilarity(str1: string, str2: string) {\r\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\r\n if (longerLength === 0) return 1;\r\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\r\n}\r\n\r\n/**\r\n * Pick the best sentence that correspond to the answer\r\n * @param arr\r\n * @param answer\r\n * @returns\r\n */\r\nexport function pickBestReponse(\r\n answer: string,\r\n arr: { element: HTMLElement; value: string }[]\r\n): BestResponse {\r\n let bestResponse: BestResponse = {\r\n element: null,\r\n similarity: 0,\r\n value: null,\r\n };\r\n for (const obj of arr) {\r\n const similarity = sentenceSimilarity(obj.value, answer);\r\n if (similarity === 1) {\r\n return { element: obj.element, value: obj.value, similarity };\r\n }\r\n if (similarity > bestResponse.similarity) {\r\n bestResponse = { element: obj.element, value: obj.value, similarity };\r\n }\r\n }\r\n return bestResponse;\r\n}\r\n\r\n/**\r\n * Return the sentences sorted by score with a score superior or equal to what is asked\r\n * @param answer\r\n * @param arr\r\n * @param score\r\n * @returns\r\n */\r\nexport function pickResponsesWithSimilarityGreaterThan(\r\n answer: string,\r\n arr: { element: HTMLElement; value: string }[],\r\n score: number\r\n): ResponsesBySimilarity[] {\r\n const responses: ResponsesBySimilarity[] = [];\r\n for (const obj of arr) {\r\n const similarity = sentenceSimilarity(obj.value, answer);\r\n if (similarity >= score)\r\n responses.push({\r\n similarity,\r\n value: obj.value,\r\n element: obj.element,\r\n });\r\n }\r\n return responses.sort((a, b) => a.similarity - b.similarity);\r\n}\r\n\r\n/**\r\n * Convert a number to a readable string pourcentage\r\n * @param similarity\r\n */\r\nexport function toPourcentage(similarity: number): string {\r\n return Math.round(similarity * 100 * 100) / 100 + \"%\";\r\n}\r\n","import GPTAnswer from \"@typing/gptAnswer\";\r\nimport { toPourcentage } from \"./pick-best-response\";\r\n\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 bestAnswer(answer: string, similarity: number) {\r\n const css = \"color: green\";\r\n console.log(\r\n \"%c[BEST ANSWER]: %s\",\r\n css,\r\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\r\n );\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 if (toLowerCase) text = text.toLowerCase();\r\n\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 space from textcontent\r\n .replace(/[ \\t]+/gi, \" \") //replace multiples space or tabs by a space\r\n .trim()\r\n // We remove the following content 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 return normalizedText;\r\n}\r\n\r\nexport default normalizeText;\r\n","import type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/gptAnswer\";\r\nimport normalizeText from \"@utils/normalize-text\";\r\n\r\ntype History = {\r\n url: string | null;\r\n system: { role: ROLE; content: string };\r\n history: { role: ROLE; content: string }[];\r\n};\r\n\r\nenum ROLE {\r\n SYSTEM = \"system\",\r\n USER = \"user\",\r\n ASSISTANT = \"assistant\",\r\n}\r\n\r\nconst INSTRUCTION: string = `\r\nAct as a quiz solver for the best notation with the following rules:\r\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\r\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\r\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\r\n- Always reply in the format: '\\n\\n...'.\r\n- Retain only the correct answer(s).\r\n- Maintain the same order for the answers as in the text.\r\n- Retain all text from the answer with its description, content or definition.\r\n- Only provide answers that exactly match the given answer in the text.\r\n- The question always has the correct answer(s), so you should always provide an answer.\r\n- Always respond in the same language as the user's question.\r\n`.trim();\r\n\r\nconst history: History = {\r\n url: null,\r\n system: {\r\n role: ROLE.SYSTEM,\r\n content: INSTRUCTION,\r\n },\r\n history: [],\r\n};\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 URL = location.hostname + location.pathname;\r\n\r\n // We reset the history when we enter a new moodle quiz or when it's desactivate\r\n if (!config.history || history.url !== URL) {\r\n history.url = URL;\r\n history.history = [];\r\n }\r\n\r\n const controller = new AbortController();\r\n const timeoutControler = setTimeout(() => controller.abort(), 15 * 1000);\r\n\r\n const message = { role: ROLE.USER, content: question };\r\n\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: [history.system, ...history.history, message],\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\r\n clearTimeout(timeoutControler);\r\n\r\n const rep = await req.json();\r\n const response = rep.choices[0].message.content;\r\n\r\n // Register the conversation\r\n if (config.history) {\r\n history.history.push(message);\r\n history.history.push({ role: ROLE.ASSISTANT, content: response });\r\n }\r\n\r\n return {\r\n question,\r\n response,\r\n normalizedResponse: normalizeText(response),\r\n };\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((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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 || // for now we don't handle many input for editable textcontent\r\n input.getAttribute(\"contenteditable\") !== \"true\"\r\n ) {\r\n return false;\r\n }\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 if (selection !== null) {\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n }\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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 (\r\n inputList.length !== 1 || // for now we don't handle many input number\r\n input.type !== \"number\"\r\n ) {\r\n return false;\r\n }\r\n\r\n const number = gptAnswer.normalizedResponse\r\n .match(/\\d+([,\\.]\\d+)?/gi)?.[0]\r\n ?.replace(\",\", \".\");\r\n\r\n if (number === undefined) return false;\r\n\r\n if (config.typing) {\r\n let index = 0;\r\n input.addEventListener(\"keydown\", function (event: Event) {\r\n event.preventDefault();\r\n if ((event).key === \"Backspace\") index = number.length + 1;\r\n if (index > number.length) return;\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 type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/gptAnswer\";\r\nimport Logs from \"@utils/logs\";\r\nimport normalizeText from \"@utils/normalize-text\";\r\nimport { pickBestReponse, toPourcentage } from \"@utils/pick-best-response\";\r\n\r\n/**\r\n * Handle input radio elements\r\n * @param config\r\n * @param inputList\r\n * @param gptAnswer\r\n */\r\nfunction handleRadio(\r\n config: Config,\r\n inputList: NodeListOf,\r\n gptAnswer: GPTAnswer\r\n): boolean {\r\n const firstInput = inputList?.[0] as HTMLInputElement;\r\n\r\n // Handle the case the input is not a radio\r\n if (!firstInput || firstInput.type !== \"radio\") {\r\n return false;\r\n }\r\n\r\n const possibleAnswers = Array.from(inputList)\r\n .map((inp) => ({\r\n element: inp,\r\n value: normalizeText(inp?.parentElement?.textContent ?? \"\"),\r\n }))\r\n .filter((obj) => obj.value !== \"\");\r\n\r\n const bestAnswer = pickBestReponse(\r\n gptAnswer.normalizedResponse,\r\n possibleAnswers\r\n );\r\n\r\n if (config.logs && bestAnswer.value) {\r\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\r\n }\r\n\r\n const correctInput = bestAnswer.element as HTMLInputElement;\r\n if (config.mouseover) {\r\n correctInput.addEventListener(\r\n \"mouseover\",\r\n () => (correctInput.checked = true),\r\n {\r\n once: true,\r\n }\r\n );\r\n } else {\r\n correctInput.checked = true;\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleRadio;\r\n","import type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/gptAnswer\";\r\nimport Logs from \"@utils/logs\";\r\nimport normalizeText from \"@utils/normalize-text\";\r\nimport { pickBestReponse, toPourcentage } from \"@utils/pick-best-response\";\r\n\r\n/**\r\n * Handle input checkbox elements\r\n * @param config\r\n * @param inputList\r\n * @param gptAnswer\r\n */\r\nfunction handleCheckbox(\r\n config: Config,\r\n inputList: NodeListOf,\r\n gptAnswer: GPTAnswer\r\n): boolean {\r\n const firstInput = inputList?.[0] as HTMLInputElement;\r\n\r\n // Handle the case the input is not a checkbox\r\n if (!firstInput || firstInput.type !== \"checkbox\") {\r\n return false;\r\n }\r\n\r\n const corrects = gptAnswer.normalizedResponse.split(\"\\n\");\r\n\r\n const possibleAnswers = Array.from(inputList)\r\n .map((inp) => ({\r\n element: inp,\r\n value: normalizeText(inp?.parentElement?.textContent ?? \"\"),\r\n }))\r\n .filter((obj) => obj.value !== \"\");\r\n\r\n for (const correct of corrects) {\r\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\r\n\r\n if (config.logs && bestAnswer.value) {\r\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\r\n }\r\n\r\n const correctInput = bestAnswer.element as HTMLInputElement;\r\n if (config.mouseover) {\r\n correctInput.addEventListener(\r\n \"mouseover\",\r\n () => (correctInput.checked = true),\r\n {\r\n once: true,\r\n }\r\n );\r\n } else {\r\n correctInput.checked = true;\r\n }\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleCheckbox;\r\n","import type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/gptAnswer\";\r\nimport Logs from \"@utils/logs\";\r\nimport normalizeText from \"@utils/normalize-text\";\r\nimport { pickBestReponse, toPourcentage } from \"@utils/pick-best-response\";\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 const corrects = gptAnswer.normalizedResponse.split(\"\\n\");\r\n\r\n if (config.logs) Logs.array(corrects);\r\n\r\n for (let i = 0; i < inputList.length; ++i) {\r\n if (!corrects[i]) break;\r\n\r\n const options = inputList[i].querySelectorAll(\"option\");\r\n\r\n const possibleAnswers = Array.from(options)\r\n .map((opt) => ({\r\n element: opt,\r\n value: normalizeText(opt.textContent ?? \"\"),\r\n }))\r\n .filter((obj) => obj.value !== \"\");\r\n\r\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\r\n\r\n if (config.logs && bestAnswer.value) {\r\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\r\n }\r\n\r\n const correctOption = bestAnswer.element as HTMLOptionElement;\r\n const currentSelect = correctOption.closest(\"select\");\r\n\r\n if (currentSelect === null) continue;\r\n\r\n if (config.mouseover) {\r\n currentSelect.addEventListener(\r\n \"click\",\r\n () => (correctOption.selected = true),\r\n {\r\n once: true,\r\n }\r\n );\r\n } else {\r\n correctOption.selected = true;\r\n }\r\n }\r\n\r\n return true;\r\n}\r\n\r\nexport default handleSelect;\r\n","import type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/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 || // for now we don't handle many input text\r\n (input.tagName !== \"TEXTAREA\" && input.type !== \"text\")\r\n ) {\r\n return false;\r\n }\r\n\r\n if (config.typing) {\r\n let index = 0;\r\n input.addEventListener(\"keydown\", function (event: Event) {\r\n event.preventDefault();\r\n if ((event).key === \"Backspace\") {\r\n index = gptAnswer.response.length + 1;\r\n }\r\n if (index > gptAnswer.response.length) return;\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 type Config from \"@typing/config\";\r\nimport Logs from \"@utils/logs\";\r\nimport getChatGPTResponse from \"./get-response\";\r\nimport createAndNormalizeQuestion from \"./create-question\";\r\nimport clipboardMode from \"./modes/clipboard\";\r\nimport questionToAnswerMode from \"./modes/question-to-answer\";\r\nimport autoCompleteMode from \"./modes/autocomplete\";\r\n\r\ntype Props = {\r\n config: Config;\r\n questionElement: HTMLElement;\r\n form: HTMLElement;\r\n inputQuery: string;\r\n removeListener: () => void;\r\n};\r\n\r\n/**\r\n * Reply to the question\r\n * @param props\r\n * @returns\r\n */\r\nasync function reply(props: Props): Promise {\r\n if (props.config.cursor) props.questionElement.style.cursor = \"wait\";\r\n\r\n const question = createAndNormalizeQuestion(props.form);\r\n const inputList: NodeListOf = props.form.querySelectorAll(\r\n props.inputQuery\r\n );\r\n\r\n const gptAnswer = await getChatGPTResponse(props.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 (props.config.cursor) {\r\n props.questionElement.style.cursor =\r\n props.config.infinite || haveError ? \"pointer\" : \"initial\";\r\n }\r\n\r\n if (haveError) {\r\n console.error(gptAnswer.error);\r\n return;\r\n }\r\n\r\n if (props.config.logs) {\r\n Logs.question(question);\r\n Logs.response(gptAnswer);\r\n }\r\n\r\n switch (props.config.mode) {\r\n case \"clipboard\":\r\n clipboardMode({\r\n config: props.config,\r\n questionElement: props.questionElement,\r\n gptAnswer,\r\n removeListener: props.removeListener,\r\n });\r\n break;\r\n case \"question-to-answer\":\r\n questionToAnswerMode({\r\n gptAnswer,\r\n questionElement: props.questionElement,\r\n removeListener: props.removeListener,\r\n });\r\n break;\r\n case \"autocomplete\":\r\n autoCompleteMode({\r\n config: props.config,\r\n gptAnswer,\r\n inputList,\r\n questionElement: props.questionElement,\r\n removeListener: props.removeListener,\r\n });\r\n break;\r\n }\r\n}\r\n\r\nexport default reply;\r\n","import normalizeText from \"@utils/normalize-text\";\r\nimport htmlTableToString from \"@utils/html-table-to-string\";\r\n\r\n/**\r\n * Normalize the question as text and add sub informations\r\n * @param langage\r\n * @param question\r\n * @returns\r\n */\r\nfunction createAndNormalizeQuestion(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 createAndNormalizeQuestion;\r\n","import type Config from \"@typing/config\";\r\nimport type GPTAnswer from \"@typing/gptAnswer\";\r\nimport handleClipboard from \"@core/questions/clipboard\";\r\n\r\ntype Props = {\r\n config: Config;\r\n questionElement: HTMLElement;\r\n gptAnswer: GPTAnswer;\r\n removeListener: () => void;\r\n};\r\n\r\n/**\r\n * Clipboard mode:\r\n * Simply copy the answer into the clipboard\r\n * @param props\r\n */\r\nfunction clipboardMode(props: Props) {\r\n if (!props.config.infinite) props.removeListener();\r\n handleClipboard(props.config, props.gptAnswer);\r\n}\r\n\r\nexport default clipboardMode;\r\n","import type GPTAnswer from \"@typing/gptAnswer\";\r\n\r\ntype Props = {\r\n questionElement: HTMLElement;\r\n gptAnswer: GPTAnswer;\r\n removeListener: () => void;\r\n};\r\n\r\n/**\r\n * Question to answer mode:\r\n * Simply turn the question into the answer by clicking on it\r\n * @param props\r\n */\r\nfunction questionToAnswerMode(props: Props) {\r\n const questionElement = props.questionElement;\r\n\r\n props.removeListener();\r\n\r\n const questionBackup = questionElement.textContent;\r\n\r\n questionElement.textContent = props.gptAnswer.response;\r\n\r\n // Format the content\r\n questionElement.style.whiteSpace = \"pre-wrap\";\r\n\r\n // To go back to the question / answer\r\n let contentIsResponse = true;\r\n questionElement.addEventListener(\"click\", function () {\r\n questionElement.style.whiteSpace = contentIsResponse ? \"\" : \"pre-warp\";\r\n questionElement.textContent = contentIsResponse\r\n ? questionBackup\r\n : props.gptAnswer.response;\r\n });\r\n}\r\n\r\nexport default questionToAnswerMode;\r\n","import type GPTAnswer from \"@typing/gptAnswer\";\r\nimport type Config from \"@typing/config\";\r\nimport handleClipboard from \"@core/questions/clipboard\";\r\nimport handleContentEditable from \"@core/questions/contenteditable\";\r\nimport handleNumber from \"@core/questions/number\";\r\nimport handleRadio from \"@core/questions/radio\";\r\nimport handleCheckbox from \"@core/questions/checkbox\";\r\nimport handleSelect from \"@core/questions/select\";\r\nimport handleTextbox from \"@core/questions/textbox\";\r\n\r\ntype Props = {\r\n config: Config;\r\n questionElement: HTMLElement;\r\n inputList: NodeListOf;\r\n gptAnswer: GPTAnswer;\r\n removeListener: () => void;\r\n};\r\n\r\n/**\r\n * Autocomplete mode:\r\n * Autocomplete the question by checking the good answer\r\n * @param props\r\n * @returns\r\n */\r\nfunction autoCompleteMode(props: Props) {\r\n if (!props.config.infinite) props.removeListener();\r\n\r\n const handlers = [\r\n handleContentEditable,\r\n handleTextbox,\r\n handleNumber,\r\n handleSelect,\r\n handleRadio,\r\n handleCheckbox,\r\n ];\r\n\r\n for (const handler of handlers) {\r\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\r\n }\r\n\r\n // In the case we can't auto complete the question\r\n handleClipboard(props.config, props.gptAnswer);\r\n}\r\n\r\nexport default autoCompleteMode;\r\n","import type Config from \"@typing/config\";\r\nimport titleIndications from \"@utils/title-indications\";\r\nimport reply from \"./reply\";\r\n\r\ntype Listener = {\r\n element: HTMLElement;\r\n fn: (this: HTMLElement, ev: MouseEvent) => any;\r\n};\r\n\r\nconst pressedKeys: string[] = [];\r\nconst listeners: Listener[] = [];\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 * 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\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 if there are already declared\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 // Query to find inputs and forms\r\n const inputTypeQuery = [\"checkbox\", \"radio\", \"text\", \"number\"]\r\n .map((e) => `input[type=\"${e}\"]`)\r\n .join(\",\");\r\n const inputQuery = inputTypeQuery + \", textarea, select, [contenteditable]\";\r\n const forms = document.querySelectorAll(\".formulation\");\r\n\r\n // For each form we inject a function on the queqtion\r\n for (const form of forms) {\r\n const questionElement: HTMLElement | null = form.querySelector(\".qtext\");\r\n\r\n if (questionElement === null) continue;\r\n\r\n if (config.cursor) questionElement.style.cursor = \"pointer\";\r\n\r\n const injectionFunction = reply.bind(null, {\r\n config,\r\n questionElement,\r\n form: form as HTMLElement,\r\n inputQuery,\r\n removeListener: () => removeListener(questionElement),\r\n });\r\n\r\n listeners.push({ element: questionElement, fn: injectionFunction });\r\n questionElement.addEventListener(\"click\", injectionFunction);\r\n }\r\n\r\n if (config.title) titleIndications(\"Injected\");\r\n}\r\n\r\nexport { codeListener, removeListener, setUpMoodleGpt };\r\n","import type Config from \"@typing/config\";\r\nimport { codeListener, setUpMoodleGpt } from \"./core/code-listener\";\r\n\r\nchrome.storage.sync.get([\"moodleGPT\"]).then(function (storage) {\r\n const config: Config = storage.moodleGPT;\r\n\r\n if (!config) throw new Error(\"Please configure MoodleGPT into the extension\");\r\n\r\n if (config.code) {\r\n codeListener(config);\r\n } else {\r\n setUpMoodleGpt(config);\r\n }\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","INSTRUCTION","history","url","system","role","SYSTEM","content","htmlTableToString","table","tab","lines","Array","from","querySelectorAll","maxColumnsLength","map","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","config","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","type","number","_b","match","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","filter","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","questionElement","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","model","messages","temperature","top_p","presence_penalty","stop","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","error","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"2FAIA,SAASA,EAAiBC,GACxB,MAAMC,EAAYC,SAASC,MAC3BD,SAASC,MAAQH,EACjBI,YAAW,IAAOF,SAASC,MAAQF,GAAY,IACjD,CC0GO,SAASI,EAAUC,EAASC,EAAYC,EAAGC,GAE9C,OAAO,IAAKD,IAAMA,EAAIE,WAAU,SAAUC,EAASC,GAC/C,SAASC,EAAUC,GAAS,IAAMC,EAAKN,EAAUO,KAAKF,GAAQ,CAAG,MAAOG,GAAKL,EAAOK,GAAO,CAC3F,SAASC,EAASJ,GAAS,IAAMC,EAAKN,EAAiB,MAAEK,GAAU,CAAC,MAAOG,GAAKL,EAAOK,GAAO,CAC9F,SAASF,EAAKI,GAJlB,IAAeL,EAIaK,EAAOC,KAAOT,EAAQQ,EAAOL,QAJ1CA,EAIyDK,EAAOL,MAJhDA,aAAiBN,EAAIM,EAAQ,IAAIN,GAAE,SAAUG,GAAWA,EAAQG,EAAO,KAIhBO,KAAKR,EAAWK,EAAY,CAC9GH,GAAMN,EAAYA,EAAUa,MAAMhB,EAASC,GAAc,KAAKS,OACtE,GACA,CCxEA,SAASO,EAAmBC,EAAcC,GACxC,MAAMC,EAAeF,EAAKG,OAASF,EAAKE,OAASH,EAAKG,OAASF,EAAKE,OACpE,OAAqB,IAAjBD,EAA2B,GACvBA,EAnCV,SAA6BF,EAAcC,GACzC,GAAoB,IAAhBD,EAAKG,OAAc,OAAOF,EAAKE,OACnC,GAAoB,IAAhBF,EAAKE,OAAc,OAAOH,EAAKG,OAEnC,MAAMC,EAAqB,GACrBC,EAAoBL,EAAKM,QAAQ,MAAO,IACxCC,EAAoBN,EAAKK,QAAQ,MAAO,IAE9C,IAAK,IAAIE,EAAI,EAAGA,GAAKH,EAAkBF,SAAUK,EAAG,CAClDJ,EAAOK,KAAK,CAACD,IACb,IAAK,IAAIE,EAAI,EAAGA,GAAKH,EAAkBJ,SAAUO,EAC/CN,EAAOI,GAAGE,GACF,IAANF,EACIE,EACAC,KAAKC,IACHR,EAAOI,EAAI,GAAGE,GAAK,EACnBN,EAAOI,GAAGE,EAAI,GAAK,EACnBN,EAAOI,EAAI,GAAGE,EAAI,IACfL,EAAkBG,EAAI,KAAOD,EAAkBG,EAAI,GAAK,EAAI,GAG1E,CAED,OAAON,EAAOC,EAAkBF,QAAQI,EAAkBJ,OAC5D,CAWyBU,CAAoBb,EAAMC,IAASC,CAC5D,CAQgB,SAAAY,EACdC,EACAC,GAEA,IAAIC,EAA6B,CAC/BC,QAAS,KACTC,WAAY,EACZ7B,MAAO,MAET,IAAK,MAAM8B,KAAOJ,EAAK,CACrB,MAAMG,EAAapB,EAAmBqB,EAAI9B,MAAOyB,GACjD,GAAmB,IAAfI,EACF,MAAO,CAAED,QAASE,EAAIF,QAAS5B,MAAO8B,EAAI9B,MAAO6B,cAE/CA,EAAaF,EAAaE,aAC5BF,EAAe,CAAEC,QAASE,EAAIF,QAAS5B,MAAO8B,EAAI9B,MAAO6B,cAE5D,CACD,OAAOF,CACT,CD0OkD,mBAApBI,iBAAiCA,gBExT/D,MAAMC,EACJ,eAAOC,CAAS/C,GAEdgD,QAAQC,IAAI,mBADA,cACyBjD,EACtC,CAED,iBAAOkD,CAAWX,EAAgBI,GAEhCK,QAAQC,IACN,sBAFU,eAIV,IAAIV,2BDkGJ,SAAwBI,GAC5B,OAAOR,KAAKgB,MAAmB,IAAbR,EAAmB,KAAO,IAAM,GACpD,CCpG0CS,CAAcT,KAErD,CAED,YAAOU,CAAMb,GACXQ,QAAQC,IAAI,cAAeT,EAC5B,CAED,eAAOc,CAASC,GACdP,QAAQC,IAAI,cAAgBM,EAAUD,UACtCN,QAAQC,IAAI,gBAAkBM,EAAUC,mBACzC,ECrBH,SAASC,EAAczD,EAAc0D,GAAuB,GAY1D,OAXIA,IAAa1D,EAAOA,EAAK0D,eAER1D,EAClB8B,QAAQ,QAAS,MACjBA,QAAQ,cAAe,MACvBA,QAAQ,WAAY,KACpB6B,OAEA7B,QAAQ,iBAAkB,IAC1BA,QAAQ,kBAAmB,KAGhC,CCPA,IAAK8B,GAAL,SAAKA,GACHA,EAAA,OAAA,SACAA,EAAA,KAAA,OACAA,EAAA,UAAA,WACD,CAJD,CAAKA,IAAAA,EAIJ,CAAA,IAED,MAAMC,EAAsB,y/BAY1BF,OAEIG,EAAmB,CACvBC,IAAK,KACLC,OAAQ,CACNC,KAAML,EAAKM,OACXC,QAASN,GAEXC,QAAS,IC/BX,SAASM,EAAkBC,GACzB,MAAMC,EAAkB,GAClBC,EAAQC,MAAMC,KAAKJ,EAAMK,iBAAiB,OAC1CC,EAA6B,GACnCJ,EAAMK,KAAKC,IACT,MACMC,EADQN,MAAMC,KAAKI,EAAKH,iBAAiB,WACpBE,KAAI,CAACG,EAAMC,WACpC,MAAMb,EAA0B,QAAhBc,EAAAF,EAAKG,mBAAW,IAAAD,OAAA,EAAAA,EAAEtB,OAKlC,OAJAgB,EAAiBK,GAAS7C,KAAKgD,IAC7BR,EAAiBK,IAAU,GAC3Bb,aAAO,EAAPA,EAASxC,SAAU,GAEdwC,QAAAA,EAAW,EAAE,IAEtBG,EAAIrC,KAAK6C,EAAa,IAGxB,MAAMM,EACJT,EAAiBU,QAAO,CAACC,EAAGC,IAAMD,EAAIC,IAAqB,EAAhBjB,EAAI,GAAG3C,OAAa,EAC3D6D,EACJ,KAAOhB,MAAMY,GAAoBK,KAAK,KAAKC,KAAK,IAAM,KAElDC,EAAYrB,EAAIM,KAAKC,GAOlB,KANYA,EAAKD,KAAI,CAACT,EAASa,IACpCb,EAAQyB,OACNjB,EAAiBK,GACjB,OAGqBU,KAAK,OAAS,OAGzC,OADaC,EAAUE,QACTL,EAAiBG,EAAUD,KAAK,KAChD,CC7BA,SAASI,EAAgBC,EAAgBxC,GACnCwC,EAAO5F,OAAOJ,EAAiB,uBACnCiG,UAAUC,UAAUC,UAAU3C,EAAUD,SAC1C,CCFA,SAAS6C,EACPJ,EACAK,EACA7C,GAEA,MAAM8C,EAAQD,EAAU,GAExB,GACuB,IAArBA,EAAUzE,QACgC,SAA1C0E,EAAMC,aAAa,mBAEnB,OAAO,EAGT,GAAIP,EAAOQ,OAAQ,CACjB,IAAIvB,EAAQ,EACZqB,EAAMG,iBAAiB,WAAW,SAAUC,GAE1C,GADkB,cAAdA,EAAMC,MAAqB1B,EAAQzB,EAAUD,SAAS3B,OAAS,GAC/DqD,EAAQzB,EAAUD,SAAS3B,OAAQ,OACvC8E,EAAME,iBACNN,EAAMnB,YAAc3B,EAAUD,SAASsD,MAAM,IAAK5B,GAGlDqB,EAAMQ,QACN,MAAMC,EAAQ5G,SAAS6G,cACvBD,EAAME,mBAAmBX,GACzBS,EAAMG,UAAS,GACf,MAAMC,EAAYC,OAAOC,eACP,OAAdF,IACFA,EAAUG,kBACVH,EAAUI,SAASR,GAEvB,GACD,MACCT,EAAMnB,YAAc3B,EAAUD,SAGhC,OAAO,CACT,CCtCA,SAASiE,EACPxB,EACAK,EACA7C,WAEA,MAAM8C,EAAQD,EAAU,GAExB,GACuB,IAArBA,EAAUzE,QACK,WAAf0E,EAAMmB,KAEN,OAAO,EAGT,MAAMC,EAEF,QAFWC,EACa,QADbzC,EAAA1B,EAAUC,mBACtBmE,MAAM,2BAAmB,IAAA1C,OAAA,EAAAA,EAAG,UAC3B,IAAAyC,OAAA,EAAAA,EAAA5F,QAAQ,IAAK,KAEjB,QAAe8F,IAAXH,EAAsB,OAAO,EAEjC,GAAI1B,EAAOQ,OAAQ,CACjB,IAAIvB,EAAQ,EACZqB,EAAMG,iBAAiB,WAAW,SAAUC,GAC1CA,EAAME,iBAC6B,cAAfF,EAAOC,MAAqB1B,EAAQyC,EAAO9F,OAAS,GACpEqD,EAAQyC,EAAO9F,SACoB,MAAnC8F,EAAOb,MAAM5B,EAAOA,EAAQ,MAAcA,EAC9CqB,EAAMvF,MAAQ2G,EAAOb,MAAM,IAAK5B,GAClC,GACD,MACCqB,EAAMvF,MAAQ2G,EAGhB,OAAO,CACT,CChCA,SAASI,EACP9B,EACAK,EACA7C,GAEA,MAAMuE,EAAa1B,eAAAA,EAAY,GAG/B,IAAK0B,GAAkC,UAApBA,EAAWN,KAC5B,OAAO,EAGT,MAAMO,EAAkBvD,MAAMC,KAAK2B,GAChCxB,KAAKoD,YAAQ,MAAC,CACbtF,QAASsF,EACTlH,MAAO2C,EAA6C,QAA/BiE,EAAkB,QAAlBzC,EAAA+C,aAAA,EAAAA,EAAKC,qBAAa,IAAAhD,OAAA,EAAAA,EAAEC,mBAAW,IAAAwC,EAAAA,EAAI,IACxD,IACDQ,QAAQtF,GAAsB,KAAdA,EAAI9B,QAEjBoC,EAAaZ,EACjBiB,EAAUC,mBACVuE,GAGEhC,EAAOoC,MAAQjF,EAAWpC,OAC5BgC,EAAKI,WAAWA,EAAWpC,MAAOoC,EAAWP,YAG/C,MAAMyF,EAAelF,EAAWR,QAahC,OAZIqD,EAAOsC,UACTD,EAAa5B,iBACX,aACA,IAAO4B,EAAaE,SAAU,GAC9B,CACEC,MAAM,IAIVH,EAAaE,SAAU,GAGlB,CACT,CC1CA,SAASE,EACPzC,EACAK,EACA7C,GAEA,MAAMuE,EAAa1B,eAAAA,EAAY,GAG/B,IAAK0B,GAAkC,aAApBA,EAAWN,KAC5B,OAAO,EAGT,MAAMiB,EAAWlF,EAAUC,mBAAmBkF,MAAM,MAE9CX,EAAkBvD,MAAMC,KAAK2B,GAChCxB,KAAKoD,YAAQ,MAAC,CACbtF,QAASsF,EACTlH,MAAO2C,EAA6C,QAA/BiE,EAAkB,QAAlBzC,EAAA+C,aAAA,EAAAA,EAAKC,qBAAa,IAAAhD,OAAA,EAAAA,EAAEC,mBAAW,IAAAwC,EAAAA,EAAI,IACxD,IACDQ,QAAQtF,GAAsB,KAAdA,EAAI9B,QAEvB,IAAK,MAAM6H,KAAWF,EAAU,CAC9B,MAAMvF,EAAaZ,EAAgBqG,EAASZ,GAExChC,EAAOoC,MAAQjF,EAAWpC,OAC5BgC,EAAKI,WAAWA,EAAWpC,MAAOoC,EAAWP,YAG/C,MAAMyF,EAAelF,EAAWR,QAC5BqD,EAAOsC,UACTD,EAAa5B,iBACX,aACA,IAAO4B,EAAaE,SAAU,GAC9B,CACEC,MAAM,IAIVH,EAAaE,SAAU,CAE1B,CAED,OAAO,CACT,CC1CA,SAASM,EACP7C,EACAK,EACA7C,GAEA,GAAyB,IAArB6C,EAAUzE,QAAyC,WAAzByE,EAAU,GAAGyC,QAAsB,OAAO,EAExE,MAAMJ,EAAWlF,EAAUC,mBAAmBkF,MAAM,MAEhD3C,EAAOoC,MAAMrF,EAAKO,MAAMoF,GAE5B,IAAK,IAAIzG,EAAI,EAAGA,EAAIoE,EAAUzE,QACvB8G,EAASzG,KADwBA,EAAG,CAGzC,MAAM8G,EAAU1C,EAAUpE,GAAG0C,iBAAiB,UAExCqD,EAAkBvD,MAAMC,KAAKqE,GAChClE,KAAKmE,UAAQ,MAAC,CACbrG,QAASqG,EACTjI,MAAO2C,EAAiC,QAAnBwB,EAAA8D,EAAI7D,mBAAe,IAAAD,EAAAA,EAAA,IACxC,IACDiD,QAAQtF,GAAsB,KAAdA,EAAI9B,QAEjBoC,EAAaZ,EAAgBmG,EAASzG,GAAI+F,GAE5ChC,EAAOoC,MAAQjF,EAAWpC,OAC5BgC,EAAKI,WAAWA,EAAWpC,MAAOoC,EAAWP,YAG/C,MAAMqG,EAAgB9F,EAAWR,QAC3BuG,EAAgBD,EAAcE,QAAQ,UAEtB,OAAlBD,IAEAlD,EAAOsC,UACTY,EAAczC,iBACZ,SACA,IAAOwC,EAAcG,UAAW,GAChC,CACEZ,MAAM,IAIVS,EAAcG,UAAW,EAE5B,CAED,OAAO,CACT,CCnDA,SAASC,EACPrD,EACAK,EACA7C,GAEA,MAAM8C,EAAQD,EAAU,GAExB,GACuB,IAArBA,EAAUzE,QACS,aAAlB0E,EAAMwC,SAAyC,SAAfxC,EAAMmB,KAEvC,OAAO,EAGT,GAAIzB,EAAOQ,OAAQ,CACjB,IAAIvB,EAAQ,EACZqB,EAAMG,iBAAiB,WAAW,SAAUC,GAC1CA,EAAME,iBAC6B,cAAfF,EAAOC,MACzB1B,EAAQzB,EAAUD,SAAS3B,OAAS,GAElCqD,EAAQzB,EAAUD,SAAS3B,SAC/B0E,EAAMvF,MAAQyC,EAAUD,SAASsD,MAAM,IAAK5B,GAC9C,GACD,MACCqB,EAAMvF,MAAQyC,EAAUD,SAG1B,OAAO,CACT,CClBA,SAAe+F,EAAMC,4CACfA,EAAMvD,OAAOwD,SAAQD,EAAME,gBAAgBC,MAAMF,OAAS,QAE9D,MAAMxG,ECfR,SAAoC2G,GAClC,IAAI3G,EAAW2G,EAAkBC,UAGjC,MAAMC,EACJF,EAAkBhF,iBAAiB,eACrC,IAAK,MAAMmF,KAAWD,EACpB7G,EAAWA,EAASjB,QAAQ+H,EAAQF,UAAW,IAIjD,MAAMG,EACJJ,EAAkBhF,iBAAiB,gBACrC,IAAK,MAAML,KAASyF,EAClB/G,EAAWA,EAASjB,QAClBuC,EAAMsF,UACN,KAAOvF,EAAkBC,GAAS,MAItC,OAAOZ,EAAcV,GAAU,EACjC,CDNmBgH,CAA2BT,EAAMU,MAC5C5D,EAAqCkD,EAAMU,KAAKtF,iBACpD4E,EAAMW,YAGF1G,QTgBR,SACEwC,EACAhD,4CAEA,MAAMmH,EAAMC,SAASC,SAAWD,SAASE,SAGpCtE,EAAOjC,SAAWA,EAAQC,MAAQmG,IACrCpG,EAAQC,IAAMmG,EACdpG,EAAQA,QAAU,IAGpB,MAAMwG,EAAa,IAAIC,gBACjBC,EAAmBpK,YAAW,IAAMkK,EAAWG,SAAS,MAExDC,EAAU,CAAEzG,KAAML,EAAK+G,KAAMxG,QAASpB,GAEtC6H,QAAYC,MAAM,6CAA8C,CACpEC,OAAQ,OACRC,QAAS,CACP,eAAgB,mBAChBC,cAAe,UAAUjF,EAAOkF,UAElCC,OAAQnF,EAAOoF,QAAUb,EAAWY,OAAS,KAC7CE,KAAMC,KAAKC,UAAU,CACnBC,MAAOxF,EAAOwF,MACdC,SAAU,CAAC1H,EAAQE,UAAWF,EAAQA,QAAS4G,GAC/Ce,YAAa,GACbC,MAAO,EACPC,iBAAkB,EAClBC,KAAM,SAIVC,aAAarB,GAEb,MACMlH,SADYsH,EAAIkB,QACDC,QAAQ,GAAGrB,QAAQvG,QAQxC,OALI4B,EAAOjC,UACTA,EAAQA,QAAQ7B,KAAKyI,GACrB5G,EAAQA,QAAQ7B,KAAK,CAAEgC,KAAML,EAAKoI,UAAW7H,QAASb,KAGjD,CACLP,WACAO,WACAE,mBAAoBC,EAAcH,MAErC,CSlEyB2I,CAAmB3C,EAAMvD,OAAQhD,GAAUmJ,OAChEC,IAAW,CACVA,YAIEC,EAAiC,iBAAd7I,GAA0B,UAAWA,EAO9D,GALI+F,EAAMvD,OAAOwD,SACfD,EAAME,gBAAgBC,MAAMF,OAC1BD,EAAMvD,OAAOsG,UAAYD,EAAY,UAAY,WAGjDA,EACFpJ,QAAQmJ,MAAM5I,EAAU4I,YAS1B,OALI7C,EAAMvD,OAAOoC,OACfrF,EAAKC,SAASA,GACdD,EAAKQ,SAASC,IAGR+F,EAAMvD,OAAOuG,MACnB,IAAK,aErCT,SAAuBhD,GAChBA,EAAMvD,OAAOsG,UAAU/C,EAAMiD,iBAClCzG,EAAgBwD,EAAMvD,OAAQuD,EAAM/F,UACtC,CFmCMiJ,CAAc,CACZzG,OAAQuD,EAAMvD,OACdyD,gBAAiBF,EAAME,gBACvBjG,YACAgJ,eAAgBjD,EAAMiD,iBAExB,MACF,IAAK,sBGhDT,SAA8BjD,GAC5B,MAAME,EAAkBF,EAAME,gBAE9BF,EAAMiD,iBAEN,MAAME,EAAiBjD,EAAgBtE,YAEvCsE,EAAgBtE,YAAcoE,EAAM/F,UAAUD,SAG9CkG,EAAgBC,MAAMiD,WAAa,WAInClD,EAAgBhD,iBAAiB,SAAS,WACxCgD,EAAgBC,MAAMiD,WAAiC,GACvDlD,EAAgBtE,YACZuH,CAEN,GACF,CH6BME,CAAqB,CACnBpJ,YACAiG,gBAAiBF,EAAME,gBACvB+C,eAAgBjD,EAAMiD,iBAExB,MACF,IAAK,gBI5CT,SAA0BjD,GACnBA,EAAMvD,OAAOsG,UAAU/C,EAAMiD,iBAElC,MAAMK,EAAW,CACfzG,EACAiD,EACA7B,EACAqB,EACAf,EACAW,GAGF,IAAK,MAAMqE,KAAWD,EACpB,GAAIC,EAAQvD,EAAMvD,OAAQuD,EAAMlD,UAAWkD,EAAM/F,WAAY,OAI/DuC,EAAgBwD,EAAMvD,OAAQuD,EAAM/F,UACtC,CJ2BMuJ,CAAiB,CACf/G,OAAQuD,EAAMvD,OACdxC,YACA6C,YACAoD,gBAAiBF,EAAME,gBACvB+C,eAAgBjD,EAAMiD,oBAI7B,CKrED,MAAMQ,EAAwB,GACxBC,EAAwB,GAqB9B,SAAST,EAAe7J,GACtB,MAAMsC,EAAQgI,EAAUC,WAAWC,GAAaA,EAASxK,UAAYA,IACrE,IAAe,IAAXsC,EAAc,CAChB,MAAMkI,EAAWF,EAAUG,OAAOnI,EAAO,GAAG,GAC5CkI,EAASxK,QAAQ0K,oBAAoB,QAASF,EAASG,GACxD,CACH,CAOA,SAASC,EAAevH,GAEtB,GAAIiH,EAAUrL,OAAS,EAAG,CACxB,IAAK,MAAMuL,KAAYF,EACjBjH,EAAOwD,SAAQ2D,EAASxK,QAAQ+G,MAAMF,OAAS,WACnD2D,EAASxK,QAAQ0K,oBAAoB,QAASF,EAASG,IAIzD,OAFItH,EAAO5F,OAAOJ,EAAiB,gBACnCiN,EAAUrL,OAAS,EAEpB,CAGD,MAGMsI,EAHiB,CAAC,WAAY,QAAS,OAAQ,UAClDrF,KAAK3D,GAAM,eAAeA,QAC1ByE,KAAK,KAC4B,wCAC9B6H,EAAQrN,SAASwE,iBAAiB,gBAGxC,IAAK,MAAMsF,KAAQuD,EAAO,CACxB,MAAM/D,EAAsCQ,EAAKwD,cAAc,UAE/D,GAAwB,OAApBhE,EAA0B,SAE1BzD,EAAOwD,SAAQC,EAAgBC,MAAMF,OAAS,WAElD,MAAMkE,EAAoBpE,EAAMqE,KAAK,KAAM,CACzC3H,SACAyD,kBACAQ,KAAMA,EACNC,aACAsC,eAAgB,IAAMA,EAAe/C,KAGvCwD,EAAU/K,KAAK,CAAES,QAAS8G,EAAiB6D,GAAII,IAC/CjE,EAAgBhD,iBAAiB,QAASiH,EAC3C,CAEG1H,EAAO5F,OAAOJ,EAAiB,WACrC,CCjFA4N,OAAOC,QAAQC,KAAKC,IAAI,CAAC,cAAczM,MAAK,SAAUuM,GACpD,MAAM7H,EAAiB6H,EAAQG,UAE/B,IAAKhI,EAAQ,MAAM,IAAIiI,MAAM,iDAEzBjI,EAAOkI,KDQb,SAAsBlI,GACpB7F,SAASkL,KAAK5E,iBAAiB,WAAW,SAAUC,GAClDsG,EAAY9K,KAAKwE,EAAMC,KACnBqG,EAAYpL,OAASoE,EAAOkI,KAAMtM,QAAQoL,EAAYlH,QACtDkH,EAAYrH,KAAK,MAAQK,EAAOkI,OAClClB,EAAYpL,OAAS,EACrB2L,EAAevH,GAEnB,GACF,CChBImI,CAAanI,GAEbuH,EAAevH,EAEnB","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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/core/get-response.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport normalizeText from '@utils/normalize-text';\n\ntype History = {\n url: string | null;\n system: { role: ROLE; content: string };\n history: { role: ROLE; content: string }[];\n};\n\nenum ROLE {\n SYSTEM = 'system',\n USER = 'user',\n ASSISTANT = 'assistant'\n}\n\nconst INSTRUCTION: string = `\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\n- Always reply in the format: '\\n\\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n`.trim();\n\nconst history: History = {\n url: null,\n system: {\n role: ROLE.SYSTEM,\n content: INSTRUCTION\n },\n history: []\n};\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(config: Config, question: string): Promise {\n const URL = location.hostname + location.pathname;\n\n // We reset the history when we enter a new moodle quiz or when it's desactivate\n if (!config.history || history.url !== URL) {\n history.url = URL;\n history.history = [];\n }\n\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 15 * 1000);\n\n const message = { role: ROLE.USER, content: question };\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: [history.system, ...history.history, message],\n temperature: 0.8,\n top_p: 1.0,\n presence_penalty: 1.0,\n stop: null\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Register the conversation\n if (config.history) {\n history.history.push(message);\n history.history.push({ role: ROLE.ASSISTANT, content: response });\n }\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, question).catch(error => ({\n error\n }));\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","INSTRUCTION","history","url","system","role","SYSTEM","content","htmlTableToString","table","tab","lines","Array","from","querySelectorAll","maxColumnsLength","map","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","config","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","type","number","_b","match","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","filter","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","questionElement","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","model","messages","temperature","top_p","presence_penalty","stop","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","error","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file diff --git a/extension/manifest.json b/extension/manifest.json index b0fe3eb..5617c6d 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "MoodleGPT", - "version": "1.0.4", + "version": "1.1.0", "description": "Hidden chat-gpt for your moodle quiz", "permissions": ["storage"], "action": { From cb23ae7b21e28bfb45b7cf9b9f017fd04b5ecf99 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 20:24:29 -0500 Subject: [PATCH 35/87] asset update --- README.md | 2 +- assets/setup.png | Bin 14362 -> 8424 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 200235d..d682dd2 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ See the [changelog](./CHANGELOG.md) to see every updates ! Popup

-Go to "Manage my extensions" on your browser, then click on "Load unpacked extension" and select the "extension" folder. Afterwards, click on the extension icon and enter the apiKey obtained from [openai](https://platform.openai.com/) and enter a code that will activate the extension on your moodle page. Finally, click on the reload button next to model (it should give you the last ChatGPT version, otherwise enter it by your self) and click on the save button (The extension need to be configured before entering the moodle quiz). +Go to "Manage my extensions" on your browser, then click on "Load unpacked extension" and select the "extension" folder. Afterwards, click on the extension icon and enter the ApiKey obtained from [openai api](https://platform.openai.com/api-keys). Finally, click on the reload button next to model (it should give you the last ChatGPT version, otherwise enter it by your self) and click on the save button (The extension need to be configured before entering the moodle quiz). ## Inject the code into the moodle diff --git a/assets/setup.png b/assets/setup.png index d326e0e83733084c8c1bb1b46a42ade16c43de64..a60034085f68efdc0583976a57dc19e2621e6914 100644 GIT binary patch literal 8424 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 F`X7>-L)`!X literal 14362 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 Y6e_GhD|0`*ujhl32FgoRe$fy3PiAMu3IG5A From 73dd76625fd81e73deaf9441c263e8c96a1e45c0 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 20:28:07 -0500 Subject: [PATCH 36/87] updating dependencies --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index df86bc2..19151f2 100644 --- a/package.json +++ b/package.json @@ -25,15 +25,15 @@ }, "homepage": "https://github.com/yoannchb-pro/MoodleGPT#readme", "devDependencies": { - "@rollup/plugin-terser": "^0.4.3", - "@types/chrome": "^0.0.246", + "@rollup/plugin-terser": "^0.4.4", + "@types/chrome": "^0.0.262", "@typescript-eslint/eslint-plugin": "^7.1.0", "@typescript-eslint/parser": "^7.1.0", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "prettier": "^3.2.5", - "rollup": "^3.20.0", + "rollup": "^4.12.0", "rollup-plugin-ts": "^3.2.0", - "typescript": "^5.0.2" + "typescript": "^5.3.3" } } From 3dab8a459512c4c9fcdda0473bd79808fb5d08be Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 20:40:19 -0500 Subject: [PATCH 37/87] version checking fixe for dev mode --- extension/popup/js/version.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extension/popup/js/version.js b/extension/popup/js/version.js index 8026744..dc9991d 100644 --- a/extension/popup/js/version.js +++ b/extension/popup/js/version.js @@ -50,8 +50,11 @@ async function notifyUpdate() { const minVersionLength = Math.min(lastVertionSplitted.length, currentVersionSplitted.length); for (let i = 0; i < minVersionLength; ++i) { - if (parseInt(lastVertionSplitted[i]) > parseInt(currentVersionSplitted[i])) + if (parseInt(lastVertionSplitted[i]) > parseInt(currentVersionSplitted[i])) { return setVersion(lastVersion, false); + } else if (parseInt(currentVersionSplitted[i]) > parseInt(lastVertionSplitted[i])) { + return setVersion(CURRENT_VERSION); + } } setVersion(CURRENT_VERSION); From f4727e08fb4e55af43c0a155a651073d9ecd4fe1 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 21:04:54 -0500 Subject: [PATCH 38/87] assets update --- assets/popup.png | Bin 52676 -> 37601 bytes webstore-assets/{ => v1}/banner1.jpg | Bin webstore-assets/{ => v1}/banner2.png | Bin webstore-assets/{ => v1}/banner3.jpg | Bin webstore-assets/{ => v1}/banner4.png | Bin webstore-assets/{ => v1}/icon-128x128.jpg | Bin webstore-assets/v2/banner1.jpg | Bin 0 -> 207038 bytes webstore-assets/v2/banner2.png | Bin 0 -> 259412 bytes webstore-assets/v2/icon-128x128-black.jpg | Bin 0 -> 16993 bytes 9 files changed, 0 insertions(+), 0 deletions(-) rename webstore-assets/{ => v1}/banner1.jpg (100%) rename webstore-assets/{ => v1}/banner2.png (100%) rename webstore-assets/{ => v1}/banner3.jpg (100%) rename webstore-assets/{ => v1}/banner4.png (100%) rename webstore-assets/{ => v1}/icon-128x128.jpg (100%) create mode 100644 webstore-assets/v2/banner1.jpg create mode 100644 webstore-assets/v2/banner2.png create mode 100644 webstore-assets/v2/icon-128x128-black.jpg diff --git a/assets/popup.png b/assets/popup.png index 673dcab7b09294c0de73b09f24258faf490b5102..601e817afd2731c5daf0b7763cd34233255f0c0b 100644 GIT binary patch literal 37601 zcmd42Wl&wg_brIKdvJHVIKiC&!TsV+xVXD}u%HR9!JUgkaCdiyAc2cJJbv%}UroK4 zshRg_YCfFPwY$1coztgfueH~XR#lcmMtCsjvV2RB#h&p=;lFY3>ntkm8gcYoIZZgKPQ|KHlY zyxjlQ;(xUNk8S8*KP3i%g8G5{MOs4B%jjP=x`C$F+q)PnBjqsV-@LrM3?hfbww`Y+ z5loiR$JGxI7H$5rmrrR2QdUK$m>S$;+OY<#Ab=aMGa+saoDS~$j>0Ky%6(L2<13bG@Arg*eA+5I;0RzSXwZg1eR4$e;OrHFIwU<4xB^=G!8I?5{X;f?4y?{ z!v6=I@|;{;%CWEeMfxX4VLI*G#VzgN6V44GL9+<2?Vd7@LM#Gx!q3%dwP5vH7KHWk z>Ym$CW;`9uo!z*#VYc>gZaV$Ddp`D5on5m>`}Gz>Hn0+wv~N)V9l6;^n5#60(92X1 zxmS@j|FTD2BHY3c!rDMTbqF|;XX*|2+E075g3bJW+0XJTI&%irR%LllAWF5l@1oXS zGbw8E^4YGvtv*~sqp@;;&1}t{!(Mq7%X2!Atq?l|}RLO;Fu9_@hP)O^a^pYX~MRvYp4Xq2V)eV3QC(+`%= zadXhpo=(9*>*xB*QA8yT?pn@92Gp8o&&B!~*8VXivUAmTOt;@sciLuew{q%s!}l>p zh8a4f25~dr^uN7$kV~UGT><&CNZDCnT ze4b$LHGUG<)yG22%Lw>cDx8~DM7P*3ysn+=2G)W*cjnf>ce)S3magpMZXV%K@C zlN7KY^BP?qw1(v{q3q)PM|jHUulZc@;*SF}-_LwhDKk4KpmCbpw6J zNzcP(ayAZN_uiMCjTk$_ZzE$M3o6AH2RQwPLH*#k+Pd05)b#cFuURL0^}m3rQRD2= zF^9hz4SaV-Bru}e z*mF3~Vex?kceQJyZS<2;Eef;4UT6a`Eq>~Td+u3wZxzHkg7NZjuXE>QI3N@rS2vb8 ztG!?Vb&X>?U9q|U$H!^3qJQlx;bhUd@Y;1U8v-g_eIF3+UEx2q9m3N$L?EU4E4=lmNfno=L7*{0jCMa;+3Qj$f!)gU7AJ?GR(a;#O= z1+@pzO)1!}v=8-4T2;&6K|%gk>z)KT#DNJK;J06j zmWKgLtr9T&{q;)t&LXuyw$bzH_HRgrUT1z|ak(UxXGn2X)jt$~N(K~#J7i=#00M4E z`rIoJovv`1Zj4gA1QLRc3}BKo9%A>Z_0+K~lEm~yeYp7-Q&j2Vwr!0pv92Kx0*Vuc z!^CcAdA0oxWo-m0FtPWA%)w{N+6ek(*%- zar-_32paCn^rkX3{QhP~c$6_a_!%3qD)_x*;GMO%W}x?doSfAahK$p@r7DXasX!)i z`Ir1fwRXnQs>YFEVua_!8&i$cvrT4bLW4gaJ;fv4m4K_HoqdUm!5!&u#c)5Zna$qar1W*q_3N88|j@TW62w%R{Ugq1}> zh~hI<3NNp_smjN{c@Zw2pKnx|P!ubQcrX`QZhoHEHc*|WQ7VOh^y$@9{_99%G+HGscP+6qB#wIM>8J}a)->z z19fZ=~IBuxo)`A%VHw@e15smVe}^&J3qNs5!Xwih&px^*$;F#LY_n`QX-4_(*P40eP3;6ttVC-ynV!69#_jtGt zRfc%r)WBb3eBQ(`4J_*V%(qZ`Q?{G=@G@lPXRI1u;Bx)&Lr&Brj_lg!PkAgU8R%|H zA<6HDB;dsS-+5%T%2VIQBr(3_w<0V}|$_9rUFX+rk1dhL{QXC7Yk6ZJZrnKG(6 z-rkb{e+Z&=F)i4-2|we>mEA#eYlD!eO;2xoBGQnvX9N1qkgeyto$dSQx+-l>=e=KJ zhDgFHDVK$9Mtb2Q-6>}FK1nzB4eim{O)$~1Svv>cn47bmMwUU6}qkM0ObjRhHV$?`^;-W2X)}tVbY)}HCK^B>*hFVB3HTu=OT#^R_ z3-_hXU#}g}WEW1Xg`a3ZN3B|7=5cOVI1Ra}#KC)E+C&Kr5;D8*sn48vFGYPvK56L+ z7hMJIWvFmV&M0%cYewjK%&eWw(Z`DP~wc zuxUJ&I80yNfGa}A>6}M{AXwKf?I@`1t;PGpbriDjQ{6AH%fJV^uxh8>K(I+D2lI?R znk}&J%+t}3m(409o3NMfUym=YCbd*(3O+aBsPMa$%$#|z{)_({Dx@iSuDEOr@L0@f z0hVgwty$LZvwJ~B3IyQc$^ih4I4kHght&UKZ*{xql|NhG#t%^H?~{M;J4vm;4upaD zvJnWS!`BWKm)Rse9+SR2PDt;^WIca!j>UQUUVEWU@;l8=OVZgk6NQbC#bE$}GwIc8 zUA+HglPp<;v{;y|Im6{3Ma$&e^9VaDBeeU~>l0!1mgHs=FzU1SCzaQ0!jAfPVHXAF zB1`vWKwZx625jBb%~10cx^z%`Htn`wu08zLT6N*-s_X8dMKHF};5j6Mr=vj&f|-L9 zsFTEl(C`hG9)1CZjY{>A>ZVU*8J8q_`VW0rn)x1dw<)>mFFy?XZR`gaKEF2XokE`& z;ew{bWnzjY(JV5)j!BhV~#Jc(8A7>v?)-Z)Ja!zJNPt_L8>^ zE#74IBN4!Qe-`IJJ9A(=aBY!3Ox@}QH|RiangzYC|H`~L9Y=iW(&-wXiRG{TD=wPz zc0~w!KW3gxUvSsH^ha|6_jGKPIhov1cHCy5lDpI;i9x&&oy?zrorf30J%-a0ZK-RG zm%X?>q+fmsW&r%T1{27TFR+vAgv+WgYpzIO6HoyeVy*~4 zS$?*jp<|h*gsJ*ULoai%(W9$tt)K7nP1zQzJcwkvJr*A%lZemm{%Pp~1lLO=(nhs2 z1HJs#{^k`B#C>*a0H4Lu%nW!JBjmIV#CW^#qPnVX?$UWTIA&vgu7>InnlyXs5;kaM z>NcwA+g!!rc)XQ-X~>b!;>Ak1>1^QtGds0jemi${Vc2$O(-~AD`?X(MESsWPbTogD z^Y+V@ECy0v>9!CPX%fYtncOUN5yh9G;4rc%Bf_3vE9C0GvrP3{b4Ce!YNXBj7U5_q zl;xh@;LeuuqRVnh^q8Xvl_qSg z%9};q%P~5xT834S-vP?Y$6FL@FT$M5o5XxRY5No9-~5285jycXa^hE?{F03$PMa&x z+femUwg#JkTFVveeZy>GG%u&Ze!gHdeXu_npAw`~i*NaMUHrxMQ2gZ)+q(1&cy7kn zqK{rhWNf#g1)XX>R*?+WT$WLwfD=2O0xd^yV*7oghFO=Xk6x@jNm8x+`h{?b=vnF%RC^y)4o7k$Wg?MD*C)TZk8Vuv4FVsrPhP>bd* znW#V4c1`qsw!i@IcpX_AT)CNX*Fu9PWwr)|d0O2x@r+^xHmv6P3VQt9nK9hOmq&Of z@)^s~x7DPyo_!ij8&WxvtEn3E8zX0cMavk|^>$XSW{#@PYzB+A|Yp_L2E3{@RWhe0dkc#mR?T2#uuD*;`Rq1uE;CdCw+r<|h zzxyi_Ry4OH=_O6VzJvO2nwq1)Jp|u(Bep7K{n9z^M3!tb60f-27-y+dmXuqlK>FT* z-tsxhy{Of^O?}@;lbvU~%U&dr(-!sES+mz-y*b}ipqHaFQin8yTE!9x-goaY0&1_s z94K2wHT~05P(EiX0wribp#u`NdBMRE4hBEfnP+?oZq7L>gcjcB9VcY}Tyb}VM_YeA zyXfWh*rQ0uVhjxF-Bl;t@=-Vpn_{by()?M>iJXf^vPn z4`ZXCtdQ%OSo30N#|jki!$4KRled+EEV)E}UfcENuztCn>00Iki{UVM?QSI_m}=w+ zz1`$-OLk^si7b*KmS9NEQXrc7LZCoIYlIE{S%CS0#lLnPgrg373q{u%4+DDAZ_m{1 z^^Kx_{k;{?%(U+pu**DE9I`hTi)Tm?6$c9~B~`wE&h&cGYu59O7D^(`(sqJC6 zn8tC?xA|_!D*4UHCEa^<%OqBftxa0e8H77K0p2py^FCxs6NS=$8pAUP83VkX>30cK zBAS~S)+6GENQ_U&IhoLt-HSZu=>MaXQ!aCf4ty1zrT8s=)+7chL)M4dhn}eHYL1v(j{q0tQ-*4wMI4@^o zXTG?aX)@BBjHNX=Dwo~NU{%jA$rs<7--5zghd!zrYzT3}1PULV1o8VD)NHAjqa@Hy?cH=M%Q!7f%b6~nKewVPy&67;~PdOhEFUQUU5?G6!k*4f1{q}AWd zVb4LC$x8HNi>63fU`o-Ut12D#bzc|60WNCR{;C; zZ*4!9WbK_e&;7chtl2Z^O8quC07IDSnm3h63ZZ6|(S<2o?X4T1&3TTNZWjQ))xc!z zCnTVebgbEmsPPYaZ-Di*boQ-LOyg9#`9d0xx3stf!mijOTA8;x6)2Rl zsg%(&xvOQ(i*oxBNt!)YTsoA=Wd+r%S8>W`ap#6pGELT8t{0kAD1dZ?BAjMeBkSj= zL6JkOoIXiA(>edgfwOI<#gNg>S!a(z;Y%WXY(R*wgqU94->W`8H7@5DfXr<7ZF_kD zN8?#=cW>)%;B5$Tr$Sr>M6y6Z^72d#O5~0Z@=Rt0nnUaljl07`PQM0{g~XmXKD+hB z_WA7Y{obgf>Brp)6AhAT=!7&|Kbb~2V&2p?rR*}D33%gkyt82X2671tSifNTqB#zt zd@kgFsc0gzIB{HwtHi~3B>wc>BpaB&&FJBuY+3uM;>wQ*vmMoxaY}l3 za(Z)%LVZ=kDLnmUy!=L6{U6l%16bgMU$4-M%ObXtWHZ7kM`-GjV zb|=s}7*?ns@Aa-<{~jJ>u)XsQQRZK?$!Q(4o&WE>gepx4I+~oTr4weiPq+0Mj<9R4pml!b>qc{YZH6kuT_Cz$_;g$xG5k(It?Z94 zmjU_aFlsisWiz*4D*YrwKlnR?h`R^<>-azvhqAe57O^84>z}TMVn*ifxcZoKA9ffr z|5QV4(R#vwQ|+x^hl*)i-vU52q5}u+YZsH!dERI|)nl&CJkA_kVOwf~e$*ih;U*`H zJAJGZl4i41due8!MlSTRU)xtsZT|Tz*7Gv;NjHsJL(E!!I5&w4I3GAZ>{m|?IZ*NGU0Kn~F<9Rw6M$6&7mb`_@5X;ju%M=# z2Th*EGT9W)x)<6Du8{Z4&_wfYvmTX4`BqK(R*di1$*!NS16zWQFy3RL-zR(aw%$U# z<=9P@T5<5W)a=;^YqkdCHFPe!x3Y%JfeT(f&m0-#xuM=)j~nF*R4Wc(A!Cl z{!R9A=N?8G%#}`~R@oT7d(Tqy=#{De!9f->4(n3qcT-62BJ}0{9!FuRO?%O_gj_sJ zM(%)MK;bd&bECTWq{pIw;@o$H0OXJVd1Bgh zFIcj1>3c{Wkr&GfQQBZ~#*`f1pYb7!mG=E0>*BVxPgY3qAM`aMy!9R-V*Qolx$L`J z>DBr2z^$payA*^GcuN8A+Y%lw2{Et)u!n8+#je@807Cy`GG#aW;^dyz*uwI8GR0JF z7hd?Khv~)9j~quObvJ$NGd_U3_^13vGE5UEj=fueR2A{FZUBvOIeGEpw^H}cOAjL? zVj*I3bia(n^EV{od|$d2yx)PEdns-1r`Z!DGCAj7S%`gsy03&7MFJQq^(BGk=zQ|F z=eAjkG9r7Y2%;cWfz(YUO@`q@UIjf|F?KC}1&Qb&F}D5=CZn5K389D&C)N*C6~EZ! zKe_|m#l6smg zmL4oMj&(Dt(7`*WLtsF^+QT7d)&n=UC!m=%BCg+d&d8C=+k zum1{fY3dvU(&n=gaF%92+8DgW0M6Wl{`+=fo$;$!zi z8z&yqTs*h-FD(#|X|JoSHGwbX-zMFnitD7l-!yf)oSRac4Sa;rxzeUf*z_k=h6%u( zHP5A|jMnK+$PV=W{z2{SEcRH~Y@c+6Ha%ga#}Jjwy-=$O$3{kf3W;U78T$LZIqEmSQ^n{{jn8omv54o3oFCS z@KlSOlusYnl|)rx@r7z`yREYO(e-a_P8v@sp;j$P`g29uJA%!in^6nl$Ro(p_C$t;V{BGyfji`Cu{oE%pgH{#vy&1XTCwtQO>=L5;aF z54up%iSpY)#20NvHk<*NFC=SXN*sr|GnFkW~R|VBm*vuycJ-v^IQtTie;n zN5|9xcqx9Xo7X+P!r|2>`@fp8*K>Cd-6PKBcd5g(0IhG%^n2pp@#4vz$!#OK5*hq! zTTupnW10-*z%rJ)NUI>)X>N9f1DDwMuEM#89}X{~3_7qb{EHWbD7X&be+odRh+fRM zm~2MNRlQ@$hN=`&2(o(0_KxMB4~?VrUWtv2$iw08Ak0`Kwe{|yKui{}0Y-g8{O%tr zE9?ey5V8Ux;f)1X?pU?l;S3L{=y-J`Bh87F@i&`4K!42#4GxAciR|lLaSSTioqJfZ z!JTJykIk?99&l^bI_h8p6RSx!zfx^b-&<eaKA$-c)qYw8Q zje;(n{5UM2a~Waf3h=&Ywjzd>5Kb5MOy)wvvt7BVh~hV1HCv8flefumQ`->KiLT@L z$vt4Kk~*X%m-53CVaEk-c(y-etmXJPreNP5FKoap8d}s_p2(SKmJFnRCS%NQ0h!GJr@JKoUA@xstH z1>@&~^$vK0`PgJ}ENTCbwXSMp827$e`iwWZ7k_6Z_Qjw(%f1qlSI8@SUpKTK>9acr zI2ZWr&-un}&dHbHK4h?!L-fxo0Wll24YH%Fn$z}rIlx;_e?_}*o+7#+H5c;hZ9exe ze$OiFckf*O2!GB;%F+;R-;e)#1?9C@`hb4uli*596`LL9g_V2v7kdC*<)11}hC&>KzOx%MP zaeom~Lm*UVZvJdK_Z_`hz^(k&nGC6*;Uh2rCHh9W;7jQP^b8I`HdrsN&~@)BRYQ`} zuw?`Xz62g|PH*Zz^`66GoYhF_w5)lC<747X4ydvYF?0ob=e#b7gGkthOamPoU?*7G z!yD-E1$>)ex@(WmQc=#3$(HHO#`x>LwZU4&fm0)*3|Xtf-hn#B%3L9oAMo8SY~l53 z8*@_OOaB8QNy%GQEQwFe6*w%ytb!w}Ns{TX_)C$ustkEi1hA%c$#JhecBy!G=xL=d z8@cf-A*$6QGi}l$AuyY!Y13oC4;WSTK}j2Pcnre&v(nYQUJZZkAn-Lz!GSYH`acNx zFSRXyCq!MzqgGr)khC(qNE&O%{2 zmK4W|U#~;voCf8kVG&<{k2W^J_}(sNcM?tat>W}OxtaH_p-XA<%@Pu8dT9ThnZQX~ zhp~D-O1qj16k};6&{xp8Bk3|)M&0yh`x&HD*wTSRlWr){%G47m#3V6>Q+uZp;H0)H z-Z}Eg9IX>dj2#B~<@%7B4ipd{a=m;|AWnfFvh=Ti@YtxH<5Y>%$ln7QClj?_$_+^# zlxd=liC9Ut&5TT&YxH&i^JX~Pc6gP{z5(b;faR**{FAinVqjXJuSVC7bgr$+>9Bo; zDdm!MVQLpHxA6}G)BzS{bw)VOSH(VZZY~kzh6{cnU?W_61S(>`=Pr7Zdm#A1hUT-1 zqNEROQ3(&N)h=V8i`SYn#g`N8whOjG_-Mfmo|M*rTE8>2e*6cjD-)QIhPUrKHAPYI zQSoSw1~{_I#vWuxw?D zQ{i;}4IZ4`5dy!p->h#V*bv~zaTv5druA^QFM`77;9$^~l$ad%7nypZa(ejnQQoLr z@~}s`$dVWL%c(Rm&SUc*=~*nQV9Y{lksM?;6-$%H0A67~m?D!M>7fsL7rB}npwywx zpj4RRL9|rZF24~7hxsoeNW$IR?mabspy}BXWG{htXQgX?bAu%);zkuhKHl5KYfo4` zz4SG_x5F#RENe1!Z~(SY=EvXVk0V>^`yooe!lGXD*wel2#WMuoh+mFHTDiR8%#|ng z0a(66NdB1x0Mv8cbfj)se-h;nV?KF_a`f%UZ(AL`wjh)KwVB^`9Y~I(0zPRjd zayV^WWQik|lI|nfq%QD!-B;M%CumjBFp)<#LL>bo3xhbv%dZgApsYp|;IO5zOHdCG zondGN6Z?SKXM#UMO2M#nOG#Dt2rIchLZ*@`h)E|eN}n7Oe$t!3>KXsXOKa7tV!qxZtI`T>fcMS)YFLR&AbQH1dp3cRi1a0{Yqv0uqxL zy8O%d9%f?!mnhtEdP&p6%9WfurFxjpiEof}xlpKjmgH)iExC{>YG0Hst`Ury}b3{bA z63wpQcSFK2pzFS_abjZ^J!RFxov$?-V2gm6EAV^~-r`f}`c#bEYoLm_LY8-87S0iQ zCr6RV-jq;f@Q+P6kPGv1HJ(?Yr>~6V4f`{cgGlAFV^X2FA#24S?m(f00y{jsEXs4d zde8;b#6N|OhdFP9Y2Uu_LZD7R`n`B`iYjxpN5J zJqg6zn&4m3`su?K2gmkF+_M`io5VW&hfo8F1QnI_>MVRZK)GqpsnyHYL5rHJ9gFGL zV&KK81Luwe;)`V#i{{3G%DdCI<*jaOgWlEG4({)Mjc_w*ALB-4sGI5cBNp}$FjIBA z$2D`X`@aZ1CR$>?PA{kj19CPlf14^3@%}Lq<$OyZvzAz~2MHL21zOEQ*h5-K5|=mO zeSp9nnyoIPg2rHcToZrA``=t_ixz}CL+Vv{c6ScBeqC!0hOC^832bR`$DxS6EA!;2 zVw~hAM=6K&hi8+0GW0DUdJ8gn&;`!=sDDSg2mywAes?yhiiGvC3+8zZzXR2)iy+Qq z`u1-ew$-+oNue%3EpP@`5u)r}L$WN1JVnI*5LNua`U24FqFwSBXkjsd)4vhkf5&d_ zXc=7lHktAF5Xv+Augd^#FR-t~^#Ff4@RB&*s4F=3gVCu6t3Uk+E!#w3uM`1QPR}i( z__qN~EsTZW(4E8s8BTq6N8hj9jE>pP9$Vou6O0C%P_8CEq(YQ+ytoE#L#@l^BZ-?% z;6rmgy%H?R4IQV}Gh4fI=UCoGddCmKr;8Yc1+(;VAiCFSv)wd}&Tiry+J{6~#AI06T4~9#&oDzM4~lt;+syRwL)n#b_Ujq~ZUrNaE$*U}fVhPbVY)pQ@=$ zBJ@058LIDXk8NCcxfzZ&Rg3IHJAtibW82>02hGk8FYaektr3mur;NYVK2$;~ly#kv zPOxrpxSQ{vrePCq&JciBsV=7}fi4|6Q3}^*VgN@aP(_B!c-2;>7VmJ2*M}^iEyRt! zaX+3e$`>=*Ua05)K~k2T8H9SuMqj$bQc*OO?>feNzsi=yR3`3l%x3eUu-d&{v*^K* z77G0z;y6eIqXZV5b2`=ke}r@Yi$pJ|cVwhYb{zLUqgXNBY_U@B??OfTFcnfkr_1py zUH{;q*~Bki>fg2>ixAns#^2xnauMjbv)<}T{jrVRjRrx(*81Fjv#_%IMcYCP{uh=T z`1VOfG6%@)@OMvwdDd_J30>=z&l& zK;8ZTMJ-crOYNK|KvFj+jS~>Ho}2LUnuO$puZIw|Zv6eMii&zcy#os@NGA9=Fw6OK zcW-7JxVx4z+qS3YEM9b40?Sf_&J&E1pScWnRbM{}5%o=X* zb@;z5S*{`!Rjhb#d&>yQZ{dwrM_?FD-7JoXMUd6Z8~*e;>iYS#Ht+sp^ya?MxcSlJ z)Q~1X$^98ntQ`4o9NX1X`3MI%zAC&-UuiV35ib|3$RV*l0_d{W;~Ia$m|{p*JZkzEHN@&zSChbXYDn_fX0hAA z)K}Daf77Y7PF-7lM>RP^>0I6M@}Q!K4LMYh=D8GiwekqyqnLh9o$V3T`NwD*(^eX&6k7mXUs_6X`bSNd(BmD!ctCu)t*c^N<7 zD<1DSgj2CE{S$RNQKZZq`T9JVJ^04E?{9p>0qlx^#V_!YDe;sKp7Eg7T%S9T4U zt^}h9N>TD!W1frOB#}P8ls*a~RVkikb8PydTi@#NQvFIj=FM&8UE@Ht1>{oylOz0| zL%@piORl?&jY5%iksR-NQc>=v!3W)M(@!}{Rub&TcAX$i!^2s?J~63b6U(ZK4`YNH zE~bv%Y-qtNy}J3;rbeDAlrf#264>&~NGlE0n!BNAhX?epiPs>h{VLzH!=XE3H zGN$G6xS1o3J|mb}TIo(ojoI$)^(=CGDQ*q(+v3@9Q(Z)%JbyGk?y4irPM0f}UC!UI zMWiodSg!rB`HHP@VJ3zdi0Vt-@oxW6&bn_xYxxu|#|}K5m7ZZ?7Rkgt)M;UgUN9yL zQoY7F2*)BX4`=0H9vz>hgE83t7B-Gbih!y(JvaC3H3o@nY^%-cf_ zUSy^!PldZq!YoN@==b4I?wcUegi=>gBp_Ivov4n0Wb01uT!^OFYW=&2LdVOFf)y;6 zvx{19NgiCNdq~=pKD#0?pfC)y5+i@NM&}8=Hl)F_s}|Pdq@$Hrpw3#8TIj4wz}!Xz$iOz}ZstMw9}+UL0fq zcheUz5@%?ftG7HB;JqJ-u0QoT^h^WSt$>abdh4-TEWYcF$jUyQ&7Ho<%gp8z#=kFk z$3nj?&4f}!7AQs~cOySN2=Kz5@AZ-BARylr`SL>+FA%54ESfl)l2^8)g*3s)1BDSb zanoqxYF1~;rt9Ypf`gI_6z1i>R0npYuy~kNZK;jCe^bzMbGiC8td^E8wsP?V7(|!@hx1x~T7H{;(31lYl8JU^R@GI7P7l6y^!wz`-|IBK!d9=s+Jm@N|N9otj<(vE{rUYH#@jgb_|ooJ;H>jWXZ|i{wb7tey zXO4&a_bT%i?rSF}h^{8dAKN@hXj9xl)ose+BSCveHo`F}xH1Qjjvp)jS&(pFkozWCDn4a?&2j znv@(q^mgSDRQZBph2)pfXSP)%-(ZbR}ebFQjngV%(KN(v!7eOetTfs z)H@~lo_lQHfulWWx_F(NZ_%rNR(TspN6jp#;zH*XsAaUuH`gD69DBEY)#m>td7UN8 zMH{wi79KNJ#0gc$UBU2K(v9d}=o?B{T2K}fps272X{d*n$6@n^)?(1xz9oCVFz zV@o`IzYQ%$rXLh&w;7~R#v~jaiL~U5O>YK!Qfc~x8vO*j6=P_)vWM}`|`RAUp3gYy>(?xIS( z@|wXgbkrj=MY2>g^l+KCaTrV9MECO8yT8Yl@~b%YKw65wsq?aUNp4vB#=TNRaK48R z{tBb-`&AsMA0i#e3ECi795ja)!k+8JI_#?mBaT!CDE6-=@m8NO8Un}^@9t$E7A>Uz zx*L5u7{=*%N+LF@0ae+*Svm-Xb(mg53iv$O$iUEG6CjapY;E)ZCBloq62o^<`Q-Zd(X9M@(|XJyYZukMGt$4T2)lz9%w2X| zH~*5QKsI3BnK!Z=i+4;~f%PO8DDZKX`N-*}j(m@2#EUnKwU`ks_lXwKMdhkpDh+IP z&tL?1=?X}k|ExG7kdNurSurAdHNX|i#(ecj(j&(Nj5WP9y0HlZraKCV}{brGvw+3eId!tUe#B!S%a3)E9}DSqpK$HaM~OO~p4fG}vshD$yZ;4C z#af$*ta$&ETT z_$cWrJOD>%GnTi#^AFC5s&&Ba!qhCi340V%1W>pcH}?rLuu6ltoxA@Xz#>B+u}<{? zW!XsL#NB*4(k7*xEKznphfcd}T{m>8&m{u&pf5n;He!py^Kq6mNZgWUib(r_}E5)O#b|H^z)3CT@ru-HHi?t7UiMkO1K2pVZ=Jpzp%SKSxTe=xyKS^SIoKO_5I zHhuO+yG0&+Auz^&W$ih@{l6sd@et>eNl0}g?Viuf=Ih&|e~=`>s8uyJ9GgC;Y*|8{ z%KJEQGunTRB!|bxI~YO~&DNA39*=S_=QUK4razLT!cfooxBNm8Dg0FTGcZ417baYn z7U|ll=A8G0lIDLSr*H^A%;_q9udrV%FpDDTT z&KOd=!-*SUPu*s9{*Dg>!LPXVm>_eIVdhx3X5kN z{+l2$F?y;5EqQ9}1CaaC)K*tfeEfp}&lP3qsXKU=-OE8F>lSaH-nlvS&0t4LKtiet za&S$Y?lRm5$}vLn=9l36?Yf+jp77G)1|niej{r@`ItO%VrcI63cgIQB+94Hi_g_7} zFma?G?bA|98db&PBWBPg{wMBI75UAUs{wpdMf`!dVpA(4{Wj_>>PYmaik8I4%d&W( zaWb6d^(fcXnbVfiOU$Ek3dY1#jqzCDqPqAJ{sfDx__#X+W*>YU-`*}Uzp8}^=|d+CX-vcpQeu)3ioJq zpohgMY$_qwN)lE5GUPkr8Ab#YG{$^d@*ov;}yM$6&BLWZNT;8IrruxiRs0hm+QVi*1~D<2kO-PEE6I>*8MG=Z*zulwo<-TG$#GsP1uh(Ua(!p zLnNj4oES|ky_o28YtPG#8JV^If z5a`Xsd~CiI+N(i~xaTbLxvO`y-ds<4t`vrlavoEDgMh*194Y{m8M5MiFC!qtzH%`A zkWbLsO@tVBz$U`_A2^Qv=6jmfa2F@*6aVsj)vzMv8^&nD1G*Z+^i#7zqVOzr;i^-l z4Q8~+sSBQsTS}x}0g^X;~a)jxQ5@u1S5P1d0;s(MA8+WZ2rd`#fKBdb^;YdtR zmd>uTt0d7OuRAPX0UrM92Pb}vm=b-%k-jwmsA5|rAGeygf?~R_-Xo5mpor-4Xd3yCHD1RLk68dn;wgH?!(W``Wk?fAeUUV z{WQ*W&p;+Bd8X{dkZ1*#^c$NxK_{5jmyp1lO;+@>p;LA?!iU=b2mLns=MDoK3`~K5c z8MtOjtM2eJ52goDvNroZqrC}>6)+yXazH~-b}PS6gK8bi5MDx)9!1`DW>*WHVo(W{-c_*0cP64UphGHXIc6jDY#MQObY2sCFN zjX)SKU}#0`_gE=17SmUvsc3+~Pc=(R)~6K-qf@EPziu#$Ga#{(Z_;sT_#3Zy_f9d& zl0sl7Z%WROqo5lrtFr#ni({oGqFx4*!)nYiH=&fr?tA9!z8>u=Zad}e9(vXo4p(A@UwK|ThKVds*z;&UEfp# zThXEmiXc6nSFNbSNG(kJyIA!22AB%B6PlCct@EX}TS z)l>q$zf9@>`Q-U9Ahf={VMQ;I_G0a#_I62%ZakpvU%l=35i=4vLI!{x^OR3dVF#X! zUk;FlnGo*Uo9yXeJyp%uU^8RjB#6EnZ&jiTDV^XjthXW;!TV>&p%s-*Us&7Dgw^OH zClsMWK_OP?Law!B1xoL#$PChTnO$nBUoTd6Qi9nn#vU6zY{q%RMk5N~2&UHN9tN&4 zX_jARJhELChiD{++4ceSRca)@x16mNNjED9-pmOwWOs*AnW-Aml6oqm?B6jcNB!7m zg6HrWls$?e->X)-5qh~O1g+j+G%%^6Ya*4~!cpRYnk;94hSE34)TR2{-uzBTE>6

iSZm88*l4j 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 literal 52676 zcmdpdQ*@+V)MlJ?oOEn;Y;&0b2&2@DL~`M(eNrYW&I7}$iCw3x7}yZ(6=l8~y}=2v$I zTp&r{zd$1q6{Chfiy`H2K^D@jbVcpEW4|gc%SQ0h@J(%%`4~-2icG`>5|{f_{5aMJ z`evt@9W;n76tj4g-R`zQ%40k{W#uLR+f~oZ z>MF^ZB%aL0#hoE|!ci-{f8};!@;=`!#k(kdBXB}m|J0;z1jV&hIy&^jahg3N^tR1y z;DU?vNQ8A~i?k4&2Wz7h=p<@oLl@53y~H+n{N z(3lq?7mFpP4gpkg(wlOkO^QSfA~_BeklMoCD;b)9`SzhZi3!50kjDR^G``8(XADcT zNYDB`pjT2VskOl2?NBs?Pw6^+kT3u#ur}nUf9E5L`w; zBb%{c;4?afW?|D`q$rXAWF)CA>;?K6^b6k7DQT^du!3yko`~M`XGBImzeEeq&P*;O zvrj5)hu$kkWJGNXj_(o&$Bv^OKkXU5L!tf_vbwep(owLu8tH7KOZ4Pnj%eNv?H-5oL z5M+@2NResLJJcBDzyBfl^3M~Zc%bwclCpd5pnkETqotSOQzc=O>pS8E^;X2ZvRHHTk^ejID<8Cqk8t@*)t2ogu|EvGYeH868cVv7rxr{OXK?G z8^fobW1|*3ZV12=0*ej5Z*2u_?2;fVJaB_q2`&_4c!nPDbqmS7?;ELMy9}+vwFn2} zH-w5??ZDqI4>0h6&elld8+7$mCYjsy#MtFb; zPRPkO&2eimM;d`L$Ds)SUYz6o<`K^DN9+IRrf=>>; zeQz*;bDJuAmnKdmp?L9>AnS>xqwA!$zk0EVKxcfcdI7`%1E|*aZ8sn+nH-0Zrts?{ zO<<~WO>kQo)(Upn^+2nPclCnw*#l-khh9+OVGOJ!Vh?qah=45*_$z{LrComtRfE)L z6M@H(C09WXAe9klv?%G|QZqE3E5qlILG`YiC0D`n>eEz&{B<>MLeQca-FM2PdzNpb zq|is3@7fqnzJA@`nT>O~v+hk4a-!gSK>7SSzQWLtQaPiLGWl*XTW)ZY!k1~-(Kglfn>M)h$*o|p& z$VLnzP%}C(GIEUeh0`f8*KtE}2E_`(n|VQprcn@A>|FcTcLlx5fio(O=dC$xWm0+^ zowDHRS{1+gPC@nE`vdJ~FK$r_oM^H4BkFnEahnf^BSWhF&uTuq_?_)yRZ#F!#-A;eG!* zIX7AL&8;lc{>mO3Lt{R-VHdACp9OJ_MsxfXtUwC|(Ro1D&7HhQ9yyVue~S(Y>3MAA zZke|KTx4T{?Qe+slE2-QzIc4iEYY=FU_HhZR^Jv;O_Rq*`I_(F&+&3g z+d^Jw%x-`$JVZ&L_v#85JBJae8i3`~y?N9F?yOAZa^nQ74k7E7iJXr(QCGFTFeJzT z3P0|gIYK<{1Fw2~?NQSe)YHrRkYnG+F$FWr#YaqtqCrbF0a)6F<7}ff+Q=5S@C71# zU)iGAkD6d|?)z#b=PX}izDZ8mAgY_>I=?EDxwAZ<9-)0` z8S$q_8O$nPjN@;dA`Z~S2*wHP)vZqEVUuX;rHt7nu5P7rnYsuvrTqF( zFACK=tv zt&SsN=vNN#kp4Eay)6;9qVDoWs=n+BBj#{%j1baopc-rksE3v7Z-YYcZ_V*4a^WgQ z_dYL@OpAF0+*hST;=8GB=V;~J2`MGPdO?bm-H56I#9#OIz$;>V(PZjTbdw?-?7~o+1)2^@h+jeV-M~u9}u)r5Q3NYuKmO!CwHvY*(`|pp#$eU zEGFAvK^}$i%x8B^LxqM%U!BRS62h`Q7-n8Rgyv!bgmr#a}n7M>w-HoBKm%zcu0$SoEWY0BkKZ z$34?fIkEXloD+`jy_NODnV8f@o#f13-rYF_1YOm#=kBCxAfDdNB$WW53nh4<0y}qd zrW@}#=8r@XaAnoX{pcJT2Ny?fV1Yo4`YfrQgb?yD8T79JS}kg9`=Rj^KQ~s#b@93*+zuL&psppo|5<@T7;=qviNiP>)z<&;ZJ1|_Cl?s* z#DEEbcWOC`W9AV9`foI%$+DDdd;6X*#HWyqXW0;3XdiE1=}0CfgZM7BMeJj$MB3#s zXeUWeqnQo;RD5PsLHzxIc0SBhc5kptwTB_4CEpSY^S&Q?qB&?gqv@3EhbR7CANN~= z`SHTT98U>#wK7Za|9)>dZe6BAc zn|ETL+;{Xzjo@Eb>!bR5i3Fc6V~Yn7CHjEC+DBpHDD~E1Svz`{2l?l7^Jt7ZJO7IM zFoPPGMXQ!q()T21f>%c37mpV%PkTBeBBc=oH8{QWs0yH@1G}W$TQiw!Sx!e3pbF)^ z@I=2yE7iyg;>y1{A^$hW^zgHRhU!k~FS7%JC1OYHwr{m~`8yPQgt@?UiCG9uI_ zuxSP=Qez3U!vVVLNEVm!j<-!Kwi1z|1qu_W(Qcm|>C^GRet4t~)S4@rk?d5e?kAr) zEmKs1hk0Ak{hUk`mr02X3U)$m&Zvq(ZCm<^=%)%Kbuq4H5?QTxx*4akoS*e($|b;! zsG$MCb#j9F0y{v9^sVG#H7@X&(=|}@CPYH={)%r~I_C;v4&}!U97eU{YHolyMtjmL z=Z@X&<0F{j4mbx|njeUx>-UD~;zeJ_%k+3}C@6W+pyYJl5zXGpH;vwd(VKSm1VZY@ zGaI#FWD1c@n=b_kmP9%flu6|5@a$4Rjr#c~{0{%HY-z9Qd5y%@{7ZYXjA$hBGp4AB z$Rov)LLPx=ojCA~w<#=(FCJ|1=g-}>JB^!xQW*k((|IkdiMzKlArw0#7+%oHQ2G)3DTlY6z;G^+3CWuH-`ve~xl3vC7<9*5cfA}UdZJH4OE0GKREU4F~X0;vDBP77Gi)o^8bVIsi^5vA-V<{e2rnpzIhoX zs*pyD8BM;FFI~URu=3rm&~$jn1&SV(D{C$JN36oU*Eir1 zyJB%k{n>){*s<$wB`oc}5e-xH`%Zc#e;Uj!ZDR&=j1lNf_)q0=-k1S?3U>#NqiJzf zlmlyy2qCx(;gYI|yuVZP78zYbl5DxfHFr+PhaNwT_gC%91{6g>0jaScvLgb=w6?O} zye0c|VuW;l@MJ)SHpdN3$FnNV`>6{xoqB%QZMwX6!hm_)y?3wT(IG-zHh5@&05zE`*by=$p6#`i8_g7drg%kmz z5zTt=#+>l^&ZQVXMA$#$;&zI^eMjXmAs7_ogLJ~C2ac*agn9jhzcW+lEr=6(hFuSB ztu_&=yb$6mbBb@f7lwj?CS#r^26p(^Z;clV&gDnO zJC958k2%$RqU_1tg`IST9+B@bH>W(n(3|qZVXlz}rQ$v@@H(i4%06`7Y5iW^GDpD{ z+t>+izQhlS7VJjqCfGMs7Mfhr1;)&!+z4(Z@1ksB?Abx5Pyo*84>%s4&z@4Q-}J=Y zx!(w874)$dwa;iP5&{WDKGv^&TbMRq9_-&8&Pk$(c8!cmA1MyhqMu{q%aspoV|hc5 z+ePo;VtiAXIS6|7Z@qP>1JQUsSfFY`Ylj?&aQ_sm(+4^53nz4f)8*&{Hh{dgJTmU( z&}cmCiSH*dJuA|_d5Sh^qO|*`qR|_)1jGRwp7GVg+28iRCqAH9jcVql9LK|(5jKLt z(O6=Ati?i}vctspwwL7d2@Qh>h19u zu`hE@yC3krn}}8Ye#htg^`f}!E*AKgu2PWxl%%S6%I9_O#DTVh(}ru)%bIHt>58e9 z(hL1!fzsQrXaHIUyZ~GP+5U3L=}kF0C&YsEA~d~RqzItyRMLjoQijUPhIeE4!{{t# zW0=PsLlVUd@Dx)iqSz9`yDUCsQ7P*2PYQf5P{NA z1}#fql0qtvO!z!Ec^uyu3Tg90%4@?zP}NBl$Ieh4%sd{)N%U>4T zk6JdTWEhy1ov?bcBSuoQ!yBj6mr&SZ2V9UmqOkox;&%xc^4~@{WQX74Wk*C7o7}~s zER6T6z~THzaoeA)2k@sDMEdWUgEonyz`nqsqP~eQ-%HVZ0`fJx@WW+++e?GoB}8Eo zyJlL;ZHzFHrcKu5&!0*`g1E8!8*8Y9y9`H{@RQdW=z;rFU1GOo=3=uBF=#_vD(B>? znP&kw9XB@$)?WOx^YD*^krs0zGb-}aBu-;qQg2P6dM;S2BVr3k+BZ@7d-R)ET{CNc zSwaUYV3n6wWNl1gXixF&i!%0@RsIOhF5o(aAoU-5`P^^h&dAb?)u5OVCv`qIA;@0sVfFGnQi*VC%;RO%T+Lex5yoFF*DZKA&Z- z-E0~2p)oJFuH~tF*Mg^%>jbU(g+XE{Y^;?q3V!cPwHdTC;_6#fqBGh4E%#kLxYu=> zXiUhply45kH^KONQW77HhJNYMhA4QLF6b~{Oe{mkchpd<>u;D_HiD#(qzEm2UYJ_= z^I2J#dY+uf<7E2<9A&N&X;1UnV%pZcCPmlx$m>TkenK@kA4i7IHd{dbztZ<1qjR`? z7kCsBW4kI$M&RW(c;W1_dPVS~QCb{V5mTShVj!ZUvw!gn+{8btOe5}w?fD-19D_Kj$*DESbs~n>{DV+_#Zx|3vTTOf;biOMg~uI2Dv|x(j12Qx zZ#nZv7T+=@vyp}P*^%WxvBnnn%bZ}gSnPUltkzz}pN|Rk2=nE94vsBmxq?yTk&&Cn zUKX#eeWh0e7b8411)HpYcy~7GknApDLTb4I*WxXjmlEM78;_w?BWs|Ww2wy>*P?>* z3(irtT9N%9tJL~kI71S~@u+>BkW*GrVl5UZZtg1tvk^q?hjfwYnLaOeW3E@9$3FS~ zMEv%&9`Z$W7~TU8&!xj`z__qrd=btnM#MO{M#Z#kfL*RUBP}~#nFA>j+6K_NHY|{P z1ZEFi_8SarY51K4YJ82sj>JCily7Z@C(`(8x^5ZrF^|imcTC#17J7Rbsl~wnUoi8u8GTm;CsSANR zV_NJ9+mX@4B^h^u5SsrG5sDqwfPXkz>W>PbsSI1KX|El#aW(;A3mH6Hk%DkyF0gi? z1eJj3kA(zQ+M_*09#KX>tE>juWnofSIya$mwMkP{gNQKachN$|ACuWK0Ak$f9dAHw z%hs(m8^!sJ)TcXLlWje7`2GG;aB5Rkc*7sA!?ap=vpH=s9KzK%czUu$ioGBY zdFD>@rKs!Z(noKIAxXQ%*kv`D1}lhp{GPx>bWZ?QD8;tOOk33`QW2vzZ@Az$2@qL~ zT~=}bc4S$VJ6WL@qkeW}9xDtl`P{}0XedS?>NY0PCq4^g@^yjj`naIBPCJe)6b`%@ zBdxl2bqJbW5!Mc+EKGn5X?XX`*V*r=cdQ@MP`|U^4(segCHjC|?^!wDN3ISaweC4F7{Rsg-2C}<(0sbu3dW<6W zGvIUzre|!S#d7+mMo^qy1#9QzCqHVoLHVTE;Ae85EXysLnB32%prArFZirZRSSs`Q zW=T!ai=J&=w9a@U(E()a zUg+1Sp=s2tXV5A-nb8Gq32_z}CRJ@-^nd{jP zKlhyWhPx(rdGP=V(UTe(fvOICxRky4cm&I7A=U8vT7OP24WUX@uOATppcOaLo_m z&LC*s2-NmsC|*aVd@&s}2kRk&^-W^CDZGd!Gk0VEJf~Q5>DE%A%}w$xPVyxK7{?4~ zk>J{$Sd!&!B8)zEn~?ak+Iu*Gk6XCOX5%Qjk3dxGd6)vaVTngKn}x^7IJal82%ULE zU-FNCcmh!1>_oYlw5>m%j<$c}la(=W1)LK{VYR*Wx~0~*CHlfWa>Acd3x=N))Yrn9 zSjsxZmp6T$9m^OvbOEEqgojs`1uJY!_9?GkvBw~&_r0tsSc`nEGYx7pNv7) zdVgRHlGP$Se0nd)D@scRE;Sue;J@%$39e!ZV>qwwddp@+(VUv$o$QFiZUXgKD*U}hyPUFdG)%0)aP6ctx9)Ub-Sppe-w&RKdS5Rlu3h&UcP;Y)vFSuR zZZVc=SX)n{<> zz0&PevZ9mPpv?~)tudO9aZuCJTh(3@WU+{;ny;T|s!E7BmBNXe*bvKAPQKQP^LNNi zVUL0ZY1U;^hQiAlOo~z`UfWv*TpCr*c+dnLy8{c8g4F`G9nJ>^it=rodt=x|VdeEH z(X+$**wj(DCUouoOV#(bQFa}Dj`}O|AZP9z9sAkb5C=8BTwp)Zj~Og$;KvDy`nzDS z`gM#$c1CzRuK$f9J%!!xd}L|2Qbp$)BG!eNE9t}M3l>%me9^T;2@>)}P7^}AE6IHq zP$O5Bo4OQ?tfXS(K%tO3n{LC3qWR_p2#+tH)i?vnltyuiz-;{#yG%`NHWiEumzk1L*y#9hYAM#fj z&0n%8GGK`c3NS}(;V@%y7gu`+HcyE7xLa}0j9c2-q`u^9)4h6*Z!;;f9-QjYGIA%@ ziOg|<98Ur7RhwfG*%26!r(wbCC7BhLWZ(?(ln8Ay>Xol*O+i!0I#BFA=9>C-3Yzhm8&0j?64x`;7Qw zoJa$gAI>fm`i>AgCH|4hUxSNqH|TE`MO`r3c+c8=mXsnV(|<76p_R)jtC&|ptGHlS zU}ntiR+Eq(UbGWSopQS6i(lBiv?a52?fx69GV55Am(mS<tIPxOm1a+2^B%a@C;gE@ek*B^?<_G-<&0y3=aqYD| zi&1RS?#6fQn-fLMVaD>m5@4km0W&Y;miRmvr__~Q1;9VMwANocb?g-jIl(m(ieKM$ zh`+*0rXsFy9P()!q49#2{rtLMtm-FsICT_uV%Mg&bxoFD5A@18`Pu4wW^MDtFZCmu ztXM)51sG=F=cRcr{%L1h5!=i-WYXKL#Oziv2MJCu3Jv*6XL zV&S)TslxeK;|(^Uc~%i{W97Qxi)$p7#_Ko}wG@Q34NFn08l(NRO;m0$MHux*4Vs3f zsT9+3M5l^&%|%UCb8i<7q(NimCddt8L_MGiPI3hkmsrfQ9Gwf(TYogC9IyNqsYM)= zhry)x9ZNk4Im4HBXgqT+^~SHbw)C1z0Upqt49Y0Q`+1?AS!|U*=LF|@!MVo7S4}1FZK%-*k zNsKf(JX+8wVc_zQ((}MtRbc1(dxPo7i*o}MvJoa?t&fcEyMRQk<-)7ij_wjB%*^S# zO_RuS4OY8Tdz5xS)Gk3W6PYJYSB{AlyYE|s?x?q;#$wb9t1-=;6ZTQkj34OJoy8)3 zLbXvGR1Ur#7(=u8IUB~x3^A7Dg`TTd6G9EoI>e|=%B)b+ql z`HY*Kkim&rN=aOgvHMZ%7WZt5NOox_+MA|>46?0)#R`(kr4ZQ(?GowJ-)an-0xsb7 zpI1~J_c=}~C0&&cMZ0+Fz8+X?DhfLn)=2Z%!@G&tuHUJEOZ6sg+!3kJ=D%YV9s1=O zoS_Y*^Ie?#fYiT&$aw`hPNNv^>B9!i*P|=12FVWQk#6@yb=cJdn#Y@#x{Krq5L;;pTwFj|YL49hb5{SDL9(8;lgpoENm z@*^h$x$}TH=9z)F_93t_%m6dCG2`z8F%a=0&s?=UK8v(}ZaAxyfPC`ltB~A7uYya1 zN8tl(q}|PC0RK*8ySSiMFp7FYqOUBacBO?Wn`r504Q5#ByU+Ss5Ey*cvjF8v_$ zShFQqHGW*MKP>vMk1&%Ko|eaUbFHpIC*z0yv#!HBny$~0j=DOjq9t1b@UzB#qA`0b z^rv4n`>SVUf>LD11}>M9p_6fnh!(sovSg^1e5*bl$UnQgHVXoq9+!`n zGk-Ve1;m&fl8G@z59Y1xz}>K{N?=p3ehDo48BugVMQ3*l!L1-TXTE~}4P0AMwDHB; z{d`9Jnd)|obyNWlFaB)p(BT&$aUTE|q(~{8h&^_EI0~&vktitR~GaLFt z8f=~gOZv@O=_xPV8A&MH!Md9Kd-<-NPX5dXq-HLdn-}RcM#{_9CVyzP!p?$O(NW)h znxahAbVC1KTk*`VZaWe(C`O~5KQYylZkC7I41E7ZZS+PwuyYU-Qa-y+R$Ok(9&wg@ zv&vc_cM=6nS23VxF|6J^sii|Q2>=y-ZfdlSQLBV&;^(|(LooDSo}HMvuTc!U+q=7U zGM^L92?jJ9JEHNhb;7RqmPlRYOFyj#6JyrMYwH>A?)9TY&Bi8^l!RGoptjLznYA&Qc;e%rQ>0r4=*i3#-7R%naqy8 z8FZ3GdukS~jLA<+XWcio9Vmu{&#j!ztJ6iWk!Ls!#?&qD4ExmzTPW~rOucHzmQ(_( z+S`WPclnLG&eyS@e43Kgn!7}mg|ho^P8GqGKcZAJO8QzzHo;g6E)UZSi@7l|FCyO}x&u($po3dnXItNocz<7Dday5QEmJPjZSy;$VqpHD##kGl z`oR8d{6d{iStjVvU-t0yd=$ZaT>K5RCw?CVcCKv7x4M6;PSP~6yMo*LRB-pYXI|eE zhK`j&onu!{&FYwqPN~Iiv8sVEm~5}t8ow0_@3_BXdp>boBdhlc7rZ1orN8BjI9m=o z;GNu?%h%X1w5j)O!p9Pzs0!5#Et+yXy&mc>zf}QErd^j&76UPs(y(U#CJpLhhj^q5 zjEZAhSIfr(Qma5nnLv!R;AszTp1$a{2~R>d>~?ja24-@tS17>tM@zwlu$kM#m2IHh6x%#dADtbN-F|cgy=ffhP(1*2rL<~p`O8We)6o(VFemCocgDmPLncbh zL>(l_w~$bRcJV)Hrrs}d-!dBu&O3YO9(&L%d&n*h5~i(*Z?t$6@84OlF9^SPuLsIU zrh$fFqO0L<$J@B7E#bC%Cwn z9u@B19Lcs$==tbG#UEW<4;j#*du=7?#`nU;M2|jKZR;jEO@fVxF;+!Y%AInfz6i~d zv{&hqa-D>e~1%)I@Q9M*mx7JW>(#^)hBz|I`xAZt~-ZhM8@ruiK_E^E8Xfl+u@Uh}d7BgQsjW>4noHg;*)mRb@$*QjBA1*cpW+pVGP+ZCi~sIq3*`yvG`2QS z@A|IyV`uMlo}StDcgCDuzDIzt5;dOannDGh8D z+2fbqMeWQpZb&T>$T0rE!nTkB`t1RP;kdNd;-qh|E-W#s593_X$^GYEmB{dtUWl#^ ziMk;a`iFhw@-|_(jdw};ye)0m`X>E%oR ztjtBGQBy#hm{y*Artl;=CrqbcAuqpvy0WUh@>+Z2Q`i!NPKt#|SMV*52G~-lCbIC4 z@069dXl~7#idKODs!x}0n^!mXy;+c%g~DOH-}$7~cf;Wc1=J1tZvB!CEeC1DytTqo z&+Egu?XlS0Fn5=}p3zv|rpO*bWrvxTTuzO18te-Dz{xu?;BH;xe|d#cQMIOLo(0oI zbGiQwuJD2)u^!Q;xZ;lJ`)gNo3C`V$q&l}(%i9fgaBx7)G%|Fl(H9J*O=+Zubt@|- zFsh>-CQ35{7oWl+=LT{U=wtFMzfQyVTH5U+TgGQCKY;WDShUgGeKq-U0{(-~_A6JabtX#4hLx|03SkB- zt>!SPmGDZY2@zCF<+YhT9!jjWO#`@vTrN3y`2Hvts-5P2!j5_&ecO=cJj9%;)F7ei zo76g5{7IA{@|z824;r8|iYwbAIuSCmRQH*yJMTk+uE+0hKdcycF8)TgQ2M&Ta!Pu2 zcupzt@yu@wUzml`J&3e8FBP0*qSml+EGg;gQOTQ?RqxP>o8Oas3^*WaJSKD@o)SaC;NOK zr9Hd3rc1GJO(#CO{D+4NhEb9$%vU#Rmg_D}a%h)=osQOYLfs?~7x*HqJRGN@8n%@Z z8{Ec$^V20Tah8asT?VyWDqsod076GO6E=-|hDU_Jc)PZ$WJ3~&hkyFdB7Gj_h+RTp zFn(ReV#m1_L1?AZS~JoQ-CoID?|)(LDSlx=_q!ckpFWvL(NasAo?vFqFFv-!p*2h- z95gM*t9RCDfIc1Q_Rq*yxKud8{xibO7Q&6yiu1qblTA^0hKrtqohCX$XG z_SMh&DScREvYX|=`m$w*5{zl%`>-V!`meNPJM;K4|CpgNh1dsC-$)DuN*5>vSLz{@pm;HsmNR;WSNYb;I0wNL&^ z7pank2jdQ^jO=vSuk>(lMZ%^8Y9d5xF{vy}hcPi}?AFaly*6_{0oj_7V8lDv7KK5e zQon;g07#vX>Ne*>v>f7voroB{sI0tu{__tkxU`Dq3DrnZG~M*@d4^f*sek3cCPx6; z>>M_1r-6p^1TrZ8cKodZu_oM)Vdljiqs6g()rD<*Ko;(u6_eZh=$u}*G0#}k+d4DH zGW)vU7E0rDH?fzkSbPRClE8Wn)jU1oOkHH{v0=J$yM~$aUI!M=uH7mR)_EBi?U)k% zR7Re}ixENTlBfeEN_`C_QtQ2=7v&_nw5_bm>o>)r0%pIrK4}4%y4`9P?d>yNp4;>8hE3 zA5o;phQr%GtefJiq{^2H6-`)v;zEzPUu`f3gpd*p-iYAPu-CQE8{7eC?d7P!yhapD zhO14G)ac18yjK!r%T!>1aurnWBDge~*T?2Cl$gBhYl$FPrqi2f_EpmCkZ ziUAQA6u%gh!UM!P{uYW(h4U_N=rl}?bl9B>s*3s{7#bD_Ls@1><1`w_ZppeBwTKLjaG8AB~O4ct}x(LB~GFtjuEqu^F;D|Sdr8%k5g4& zhRdtP5bj_DGq^;}>rW|ue3BcS&Jj&~r%b^`UNBj63TL7W%JG~2*+00j{#Cuu0WP3|djeCrjp>mpFvK~5b&FRX*3|`Qt1Fy{HNAaJCf;osV@TfwFFZ4sbEn#V!obWL zs}p9WUx);F0JEi_zDSqnIjR)W}Y2_r;@2{?+ zFq_M{Nc!Oft9`?=SfyUqqFT(?VpWaL;%Pto5rE8;HK}@LW%&5DpHVQdwAy_SCzL_R z&Op}g-s357Qv2`8%cC{D?%T+7Gb&vIxj-ue)qictNl^ftUj(|ky6Pj{X=h@3zY_Kx zJM4t~5M3P;VRj3r`lB3w^?=~-Uu7+;7rkLNnCNw!MJVFW{E*v1TQuL7LaM~{OOfdW zI^iZTV}NG=8-p7*`YMrG*%`784i5?f#4`c#mqMiGK#Y$#gTjQ{b=o*^*Y@J?>K~qA zsH|@BBouOT&hiQ=OMr(e*9_O2^a(EV^cTUc=>YiN~;wd4WatWXyAAtjbsK#HtnNem!I72$&fx-y_=( zflMD>Rmj)yJ4&=UCSE=LNNiWjYd>)g`rjaMJ{+j=v}0|<4`02wqo83{5)>vK7O=6> zOSH$Q$5N96>5D$r$SKX6-d)U=EWnJTya!|K-)9(qI&l7W$Kh@g3j>Q#U1tTVGZcDl z2L+&#j=Caz!#bVdDBW9oWAg3`MTk_K_fFEaDY6-dQcRL&-8!t%@TlEiH)P%&I^fAW zGN)s^g2{8pTd}%7Z{R=c-UuQX4U8i}dQt!tF0c+x4MR@ks-S~~){I9Xc>N=if8O=} zvH5ZXA>+JcJ?NNQ1=~#Xw$u7;^Lar}hHLc51kSV6#=QS=FQvxS0Jm!XcDomZ%ZCLW za{vTLW(%dg>9@(gc5<;~yhnnt|G)SGWfDf-p($*XFYP-wEc!S_&Xxiw!27ua?E-I| z7@Hx+{I-~2ka?bg(k)s(P5?_isd-7ci5v1@f3Gdh@i`bQUdyx`1zu21R>?d- zL;44@e#v0rs;8>H6{@<@)w(G*X~X5@<28sI)V~HxqN{0?4?|;UhtXk#YQWPZ%YigZ zThaFld8DkqaQk2r0!Y2=F)}sgf;WM~Jq|EHaTyZbgk;v-p^k(ph54{a`;Ys=6vWV- zhgDo==}^>$d{niVUvY?6rF)jnv46P_W~U+fjClMX_ho(OBq|5VwO21NbB7XY@g2uJ zPjpVz0NB+>H;kIR9M7ilW{pn_WN!KfV%vyR4WU&jxH}(%$q^rd+okwYLKvZ<0qyYC zpB=MmW=}yppDyr&J|j9z2&b+hB1|$poh525yN9~rIIHP_83j!}fp@pcheNx0 z0^$Nfg3vkD;lh77#OKKzGm(D&d@>=AT2EH_8(&_-yB-T|9zM zUVj%k+So$V7uil!h*7$)53L`T%oAV4dVtJVoL0i|Sy}MJFen8oCQ%sj=yt4v>G_ab zo<6*|AJc&9e~SM@&J&HH0Fe$tYC(AU|5$t(p#va?390q?|4%&UoGp-6qQ-Ef1#uQ#j-7dao0tGL+FZDN-&-;*`RPrg7UJT3ZU(U3Uk*}gecoJE z)zn60K}xCsPD~)xn@tU#E|lM#8GN;k1q>PuYRX$$(sq5mT3N5ui7S9~ctV7LMc*Te z!XGp|EX6&*1JYLCEUzu=yNwo_etNPW1|7ODQkk?=IOLrr zyD)e~b?Ez7;gT&V4D(y;K-MwNso7{GG?d^^=&*u|aRrI48-W5E;*ol_unqECpOi5B zkBAAV$URz`m1xZqE*z_wEvGvO%`T=NWIlN^3hnwOsGl-CF=Y?X{PI6wImzVcXCGVgPPw?%#UFZB49pNFMK&Qv}q3^kY>#tBA5`nQ4^+~Z;4`1zyU;dg+N`mA+)w z7V2#$cVGY8r;rj2K6??6uC{Xrkw);>u4bA$LG)f3=B{H;qh-cl^ABV zZn!E>rewx`RUJaHmLss50+X$h;-t5wnqon(BTkjyaset8v25axROBm*q*x{^0Y6CmCMc%)u^^AxXO#C<+ta22yyp}fg z_gUd~PW)C0%+%FWqxh6te9E~4n>s^ovY~mhw?=NwWU|Gzc>j`>D{@Iblltt_!oG3g zPpfY^QXO}4)U*O)sCFw4Mx!?<)D2-a(u!k z3{C#Mb-#Q+)Cj{iI599PZ=s^SnsImYrr59cfP~6wCNp-I5E3*n7oSK)i%B{s=JN9T zZ?1`;-FLJ#=4lHf1G_#oEmw(Xtbgo^*k2nrLThRSVO7|v3^54@q8oNUNFmRY50^$Z z#PDhswvw9J2`!}sJH2P9M%R&e!&5!Y(g^V{3U;2Dt9W8beN9uecEjn77y$#C$KwEb zLqZbLNf$km(2A?Fvepk;+Pt_mZR)04D)nW#qW*JQVUKJFB#l4U8m{D9+p{!$LH$D$ zi+I>Jj_<*t3G%uEEO%6*Nng177Y=A@r1y&9!=r4DdWSz`F`L4|^KPYz;IUK+{x81}(NtaW+zqos`=|YSc7^zF$0ay79XXpUyMtnV(X-JI14Z@vj9OCg#f2 zW-Rb1v_VNe=KLS4Ra(<(l1RS`4@EY4!X5_+VNMH7tR&gYwRIxq?sSoq1BVD|mLptn z-COgueO?!LUi-17GU->tI4alNbV#9iAB;8eUX$WU3$MLmNJkBRFqz%w5CR%W@dJmo z&bYVH%`gtMWBpd(;qnld(mx?3%`=E`f(61&`yr2#=CN;Cy*_wNl^IcY8Er~;TU|ss z2j$Ej0D1_0P3K506NH<|WKFrMss8fF5u{o~=`D*~rP0V}Tx_N)2dH;O6T^e6-M9_h z+LT4K*#@g0MfB2`E(T=ZEMPg5*1tzkMI)fScqm^fn7h)nhW77fNse9butX3_MWFixTLy4>(Bi7Jk2_gEC27e#C7|la-u*m+i;AzD-8Rgro3#gdzKwBH#Pr zs3i{YsbWg5PNmQGb4r9;`$QIr+)P*n=IP6bu3RVI@zvO}99B(+?9(Ud%1T@+)yat; zP#8bJH(Znu2WZ)aie_}k`4JUwpuJ|Io?e8fsy*a3Oqt|h0QuQr!mr?I1X_q9#kDQF zG&uy-uKKj=HcR5vNnIu2FkWDD=VwX); zHO||?FzGYfEOGXxE3lEGYNEyX9DxOHnK*PS@`z_=O&e-FW@z$*#(m}sZa13*8}QRo zQo``!ZRVCoefN9R^^fqpfP=`qZo5Gk?p91PgZ*|9c1iQNc#2U`?iI32!19Yab;Ksx zQ^0xxugTLs*4SgFs+Kn+)Z`F4^Hq2OzNv>xkbGpC<<0LPYRC8w@QpTI@61YDJ^wT` zX7Tj~Dp93&K_uc)i!5PGyqN7%>jGaP4nNrv)Gq0-KB)w023Bmk=HGdbpHk zNfSRC>cvO_u&tyjXq;v+$ro`c_}AfLw~{k(RpUK%lF@5qYoZu&Mp^z4H-9JC;L@@i zY+(N>LyyR<9+(g}C_|5FP_-q)T*(ur z`XVNUby?NsZ%SrEp{^>Veiw7VIfjLgYsama)f!P9O>GcdGXJ(fQG_0h0}T>Xq1v*F zD=xxavV5eg{A{CrcAInz+=f56(4@bL)>r#e%0Pv{G*HRpsm^1kNE&_>fl$PZ2Z6d* zYoh{gfK(3U#b$@3I{xg{&7m7rN)(wzNS`9#`x*i&{pM8u)t3E6=;$m7`jS0Z(eQW~ zZecgw>-jDMc5o%H{+L83&N;e?F+T&n+4h8eba>7@|cUCIt8!t-8t4 zy*Tpm0yPnV?#`r-ur@7D!a*`?BsKhSG9_!&^JEkfYI+T382qN~hIP`8xcGY~wNQ>m zxpGIvi@KC{rfNmK?gKO;@|*YNmZs91r!@+zPEmWg3Br|p?xZsIv}`Vn$fU3|E(83R z{H|#7+aUR&clphOvBPoqRIi6Z0(&kp>pN({=c&#t)ytNQlK}=cLE_7x?!wcY&MJp) zwVz&XY*w0&pyJR{Q;xybB1ahzu|noUJ4I+v5yG7Rc7+O1=x&>PW}sTYh0W5hl40Rs zh<9lx(3}i+f_b>CMuft=zPMk-GexEeZaL0(?#%)(#psAvG+TYB#YtgHD1@$n`r^?o zrm^vbQm06$QSC$kn7V%&0Oc&A{gadG2V}#>>pfMwtX;WH+U)Ghk&LY+*O71_iL#jj z8|vW(hjcgi=9JA=ZmpTif$k}D<&HTW!6)<)wLCA7l|b@M7OtR5`IU(_Q#Z$4w3LXc zF_9(QEKNFbny`P9O8C4a%`tqvrbmdT*y%Aa&u%{EBq9x3OoYrx$jf6#lqbO8z zGhlAC+#qD{1eU-;J1HaGh{RD5**tMhhXb?-ed&H? zXyK@rczm?3jG&KxA@Q$-Quhfd(yK7x2Mn-q-UwzySnroEFT0{K9+Yn$reZoF(W25y zFA~=T^WjOw=YIsb^XP=Ok)s~fM8u(9vb^A1=X@$g!~RMr1HCsK4plr9=YpU{?O`Ya zu)<4}b<3zVE|8&{?M9|Z*Edf%O?y9l?x^5`GV`HHJoRV*Tz6w>(|L_HHRw7{9lev) zsys)_P-|0Y)@4-YGkONfR`OiFb`=$xO=fG2_+q*sRw4DJatlpx6QSX-JC(Lo_th zU?3ehq)00;!|*jaI@1aU9Ztj24)iyBoTEyFrsXm#ZWkqnDf1`0-VcW_h|E@)3^`BY zkHac)_vw?O58fXWE*3lN?;zGXvx>e+YZlU1H9@u8^U7uMap!o^P24irYfjta!qpd+ zFo3#?KIH^oC0%o{_5tk4XdylcgT*4$QX8A2MtS=0rsSV*IY?V*ASNsx(8D7$mBn<^ z32XCokksO`{w1zb459uC-Dp%sP#hVJ;E-N_cBz?`l(pz0iL*VV#Y2Dz=`qx}gk^MT z5;o+z{vx`cu}I&{5!@FoJ(KKe;Q|+j3aU?Ah7l?z21da70SUQHwi$2fG$kql{ zI8hU-fh{mAfNYX-3goULhXfk&pM=|Np0&7lw-(qZX7`B>(cmD$zX-TqP!D1*Lk%W2 zbAfQSKlM9zgd8QjrnX2#`4z3#u5+}9og&ESQmOKG;;sHYXlL@KR63qQrjO?CU%C{o z$C06ET1eg4X6yGkloT!U1zp1G@R!;i*s}A_4U^jsyZteXBaQ5m&swc$<( z=o)x&6<^9Qxrz?hD}Zrz5UfJ*0wftn*LW_KcZN_dC|nu#uAXL{qKX=urAYEw+>tM> zW6d)(=)OO99#8D37;w|*l(f-vAX7~(fWX2Kco3eK1|DR*l&h{^mF-{pg~zkkt&+5?(8^z7p@?AeD+dh1fI>F}H4nOI)w8*QTb9x1WPM4<~} z3woAv`_4K$TB4!5P|~oKS4E1eWA|0@F(WE?o}Z6?a#U!kPBIM4>MJpp*$Hxd5b5*hBULjm)AV6jvP3DKq>ll z)3N{TE7ANxnz(>7LhSq4+tQU-z;QtJhnQAfZ1$8(SZ_b6bCpqSHxbPEo^)Zj>y8JY zLz}&MfxA8!TcRQoSw`@61r*+H&Q%fsOaP?AJd%?+Xl$|qH%$ys{)|z(G)gBtJn}i{ z*}y~5zQwAn*1A*%Iz&wfE&iCyM3Ld*TOjdMRnD@F)`SAV+ zYEJ0Q?^9}u#9v6*LwAEJyEiYqKNK7b+z+sz7D~DyeuQp3{Yb`sv{ROi{MV;lx1h9h z5LUmr@_8o%CO`xS%~#*)4b!bKWhJe`j}^74Eh8ce_uuq61+kxqraAnMRc?j94*F94hfNT(zPknTKOZNGU0BdsjKbV5fimCP+)j?_`k{xrAn@8tV^P|A|CbKp)rJS@^v(N*sK4v3*8TS3e7kN7 zOEx?3DLUEJbU(pp*Nf%HJ%0AKq;+Ht{&)yZoL#y0Q`1lwiLg!0kWtN?2R0(EcEDuI zvElR?+ZBsDZ}u8YlPAX3OC_-YcF?HWiRK8AdWL^1DK3r_yy5Zb=_<*$X{xM%DtTCw z%nowICMTo34-@3R+Qz71+jXu7DfFw9Um$_PSVz&HxYTZ0*KxGN2XTXr?o4-}L}3lk{@lf42X(*pVS?Z?Q~CTvAd{L<9^9 z3QAs0jhy};4-8j7N<>Ut=kaJMEGAY^S=l8g*a$1e%%o%Za5AS}X9z|nlMWj6kcIN^ zT!hO+8ph{KRRg#CBZta>tjm89m$rbG{!a+Z{~UZ}HtY;}#WKYpE!Ue>oQC}qaur?A z%RfcW2Xno}PE185sWTA3j&hlEP-CUU1vk7s*7$Ck2pBOMRg$r?qU!m6vNl_<5|seV z#++lopwV{nLh#~;EiRz`@w$nLiTaDB3f6G|vehUy$mQ-p0tTB+TDA@j4#=P~cx_aD z6u{p~luDn)l0xWWj?rT#S0roy@@c)yqGgH*2ym_Io1kkTTq!je@DaG-7UL^Ff zDbUKuMzO7Y_@tz7hleJlquV*5sbN%{A(Q2mM>Z^W6%6a#BjA|Zv1 zK4l3#A!r}c$BWkGI4M_Hx2N-lVqOmt-HHij0lkfL$U2ka7J6Kp&_JAJcb+zx3oadB@L zbFKBJTJNBG;q`XZii0B>=2SHWWsU(&li^Z?&nw43j`IU|Bjr$O#AiDRhDJ|ak;KL<6LBtO z5_)vO$2&F>I>;Yz)p5yURqN|#Zop*GU~p9M|Ln^$y5zG8i%H z-n)e(XLM;i-FOwH4vmrf<6d-_`kNqA85!X?9n0}h4PCrL)W5qzp)%nmf=4aYp$JVA z5XcYXZo>wbys;5ATYo;wZURLar;!?3%Pz{$>Km8Ein}I8%f~}ZObt~5LViIP9k3W%}f@hMOjYa zLBvNlI7}(BLeShKD$6XQ92>sRX!$+mZHIXzYG|`+I5}mOCKDxkkg921Z6!4d+F)kz zrv@<5O$J5I>I0_u*-|oM$FR&rw4yRMRw3A-RI%A6hip68`N_b@(W+)+mEXV${%*&I z4EiOt?KB(Psjmrnu! z+eU4V&q?|S6OTz8UB@7gF2;w(EWtWIWwP{>N2e5o3IMRjfRG`Je8UVPmsTj^J_bUx zaYIxkzj;Fx^;VLmKh~d>UZXxbpOH}9KfjYlT5875_L}MgKsrUO3GhiHB_+khiF>gF z?@92VRKrlpBXq%7OF+l zlJu+NC#Knhjq&La zG6)Y#&g96$kYIB$`JViktGKTLN_0(j1ZRcxrL&{h{4btHD`KLqX#J_qp%r^+T|n|N zXRjEU+2(f?0-9OlGvN=)mS*`U%V0$=st3eD8Vld&kAz~hqg%tAakq)PF;Qd~VXqHj?C9PQQ(hnigcp6a%#wdZ&G?GaS zc6@Ac4t$IdlU2M>^{mhr#y1s+M+0I9Z)Y4fuk*;+pa~NPlYayB9?Z{La!5A{YM1er z!4Z%xv&}{r90?R6t*n=8nUJs{Y@67K>lkp38!%-X>r4(7nVIEUcDrK=

xzb{!B~4psX^{Awlcbhk*VUHjN;Q=oP)~y6v=}xl7dUI5$yEg1tgKYe@*iiM69>Gw%?(Tx7J8^CPyi*YhWm;IJkP>L85H`D?#lg& z5yQjY>wriB3sNdSRzQOmfq@Qq?)pk}ciJ3=^Mfkex6B)RKUoZ|eoVz83yrB<8Gu1R zE7hZ{aeCiKf3{T3B?@-ycyF_K`!*^Y`_=?d8K;Lm7HTs6_yI*5jnAUYNdx)}3gZv% zT$;q2OPl>OVfrQzs-Sc8aNhu=39Ijna;if7(FsXj% zFI9{zxQxKht#>CBB)Ic?adGe5NT?nU+{PmJQEA zSe3=oZi1f?Flj3{+DOrr7$8Dx*l&>{DAQ=y(V^v=Y@wI4+gFWKU~ks)JP3(t&^01)fB0H9K60vwGw@^hku z?E`ADin_xP#W(O_hjv-Ky48Gnb|X@V?|jS-x<9F1%_( zAmkAdhYrl<%BWokw9;c@9|QS{gzji%dvPI)Dl__raQAqYqK$KNT>1h;@!vSnK=gHt z3b(U3QvKn4gM%FynZj%X_71Mvdw;PuKyP<*+D_0hrtt~**2#Cm@|0^Q< zUy<6;^%}sa(Mdi{&_qhj!QR0^gY;k2>TtG5NkU4Rm!A&|1_oAIQIU`WIH@|ghH+e6 zoO+iBYkon2g6h)NGR1nZ7?45x;K^J;o#7CabUF(p)F*~AAc#>FsurmqU8>Rw*&m6S zC|mk(gWiq*wEutT+q*Fnd5W}Qk#1n?<54bj|LFHGIz_6d?|uQM@A+VAw%d*_FQ;;c z1PJJnSr$>E(!_;iKHrvmt``2kvgSvorhR|F+)naB3K>z}ss5kA+9WNohB>)h_F%2S zz(Ha+IJh6+Qf!O?(kQ2M{%cP?J8ZN6VXhp|b=A;6_WKdoIAQVxs5pxN_4`Jtys{tN zj)~V1DaRPY!#9v3li(Vo^pqocI$CwV*HsIzXT;nkc0 zU>TV+tsNl8Cx#-Vlq3kFuR=vqGetb|U?&O>UspaQIY_*7vLe0qO~{mZ z8$0dS1v&Fr`-lM9vxFu|*;oacNP+xTOwzq0@plSpfv+#&L1~sMn?^3vxEcm}=rCWX zzxb}qh~m@i6V$~Yi4dQLr|J#8LuuK5X?t%qmhat|$R9777t_>nR|U>G&@n`tHyi4M zcU>nRk7|SuV@>MsnY&{qsamOV&~csQxOL0{d5S<>RcIn$BD1RJKtWJ_%tmqDX4LWD z&8UodKQK^n2x`oKvFlEH5j~P~*P-Qfv7jgX>D*zpg*xhvg=(U}NOWWiGlIOio2S=% zYPp9{j}Nt>hbGIEqMaH{PxHq(x{i4t-URpEHo*8E z#4=6}H{msaz+d>B6S1vL1tWg4vqHQ|^*2E-(KnG~b38qOa*Rzw3Tb0b=`(boOD_3x zhl}q<)pFy=&(d@OH(!)r4kq}}fG)oLBOd6UoL8xsodO}Y2OW1q2Y3NG+}9bXRU^m} zX1y!b-R(N4-&b+>>*DVroPtZq8orbuJ z7+cWVr=w6C%H~3Glp-d7-^WQ3nWAE4k`&!OA^+a3&KDilg#|7ahE8J=4O-#M>+O?1 z7^6h`@3?a>mYBRLw=eiPNToDAa+K6j5!;;C9W@7)0)eIMI+}m8p%mfmP8EkXQOBh| zVx^H*{CbOc*>ZH=7>8+sdaV0GHX4uECnju(en!r=;BJ30CEw!Iv|4c z^_qVjB9{7Kb5%RP$8PI`y*hBH6IWY!&1fH0`Bz_|=Q5Onx+gE`OnuI)-zRE(*wlJ1 zwHOk+F+Q2@Pv@%b7SFCU6%1hCQOQZ+P@AZoloo^Yoc^8o3_p{Dde2>@lj5F$AlEU>NP9T-=)@sOewC>M_y(+)q{cc>!K%R!sj!%-e!z;l8|?V7#wTmQFxf8t=OXMxg__wTJk71 zH}VMd(O-)$wTr)4%pcKHf1+p1rM9SBxrtxO%O%Q};Dlq8l8WESZ5JydP&SpH!Z7yPG zS!<_D){n9ggxGIPq)Fk4`P+2G|HR^(O`?-Wz{=@s5ZZN|M719dgu;M~sF`Ty)@BM) z2xdtvirDKDJTEhTe?5JABTf@-DrY0hzs?yuJ=BI>;7H=4T zju00c;lgFa%Cr^?>_Bl%(WpsS5)6``f-Jn_qEn*~gT9H8;t@6#qOqP{c8ra%qPF7$ zOI+k2JDKe8%v;hzN6{n>T?fX#@CS5Rfu%A;-ga0>XmTSJ?@jW*+94PfgM-{|;RS2& z27mjgD+9ZXF53;`lnEm6*tL!JF)XLKj7v>T!>Yd?Cy4^$le9LXs@>r5wC47o_V#GM z=g{CPwJPbwRn4G5{=x)Um3<&I)5-6SW;ihzDJ{$C#{9I3f6Bl6vZo<`PI5aWChz!< z-kdLu2)CvJY3t6*>R)^gI7u$&l+e%s+iF4&$2XP0R;LJmZm{qmAc&1vQm<^?_1Fi)bI5T1qUg=R#IREyz zEw!Eq8B2u&jjkJSnhQXMYjM}*asH7`7*F~M8L~J_`N5D*^($e7h@Z0hp4SQ8jc%`g zNU0d6cV)~GY2blNc^{?KGXSRXybl(&VRFOpq*IjGxjd6#_Q2#EI$p7A*RheHBe^*8 z{!hxacj|k3P)awowO-839mvg!(k_H9DkapEwbz@bRa|29@^6$sQPInRWqlZjU!R&4&+`H4X9lG!2h*?Ohn1~uGKc8rotg^|J zB6PjgyNfBY5gt!CtO=yNcJE|6+*osrcicD`2K8*SlGd6dpO+I4coT6f>4JZiMR8_ke>+cxD*7rjI!Ur+$PJNNfF7Xpow*Hv-{jD>AGR4Z2BvQH5Pa zi_?+f1iSN!iHmsbaNOa2wdiCd#Ypm0iX)+C%-h_D74VYgQ0}LCZ_KI&5+0?VK)gze zklXH25xm~q-7NP&`@sio%k8?nH&Zb=`h3x}ilntxxDibS?e znz%L$Xs-nIS{-(BR)tf=z6#j8U=Y?xsZN!@B8`q&-=^p*#!)-L_~HZ3NiP3Q0yd)E z68N&;qM54}`FbJu&Tx2Isa5qqAmW)H=fi=?$SlNPB~zXYNVGvB)Eqqu-LIAO<3S6I zinH>1@(IbZmK?gZ08pB_L0H*f&rTVjs=^LC|5}mQKmvuP2G=h(jc7Yt@Isdfl(U8} zrgh*hUpCLrvEGLQ;}a!(Cwk5P4R}4KK)i&%_vPe>O(Lw!0K;ncRdoY9*nI!~E=>5v zTXJVGjt#7QHQg>7#^7P^sU&V<$1i~mNFv}c zcT$QC!~*p7)xDJ`a$;TU3@TWFN6zh3xjYBHRR4sXB(<|2*73wp7fe{b0v93ek9c{V~?Dmjpx(c)5R zJb9CN6(+TkCS}s~Y>Sda8+bs&BAHAJ;83XUR|rEe$h+jFNwEoWHQG-gl;;Z9_T0bu z$f<%&w2b<;X&rXj7`d2SN zB&G8Rqk47XW6-y;rvAOvg22FxS0`mgxVVigsRri!S5q0ybbrBhnV>o(TLz7J*s}dz zz6Bwy>MTmIGr8{@(vbjbkS09j)-aVn`yeQy}+lm{N8D^jn z!2F;7-g`zNqBg18h(`85ab38blFE}uE8gvrZ4v^I){Owpdg1)ws64MQuaGylH%WN# zn+*f?eMx`#!2~C` z%)ZNBd+PztTbEv0Ni&)4t>l#hC@qlXzvk|G_QnK9M@PTE-e!{S$mIGBB_SbET3X64 zAn@bt?CgLP@O$Z45j0H9u)h^*#9UlhCMGt%Q@5f6bCJ?17{5GNR4di}B@)O4444Xe z0FV*-K$9fG`oC4#Yk&%g{~tMp|6K+3|2$jqfAY_#28>FC92ERtQvm$VupEMi+7L>+ zOBQVk9Ai8=^-208RiVK5M z$~XElGeI8+ClcB{>v}cup<{6d0WvrS9`SVH8XQY_(u4W@K|I@x=~)U8+OcFa|LNnI zIac=lNe#D2C_-XoK#rF7`)WeC@Swm;uajp4(5w|;9b{$zwaVH`HMbYr7z{yjoKn#F zfv^-Em!L^_JSKnR3T4Q2A! z^tYX6d0s)JCB5q;d(G=l1YcZ4I9LZj<1 zq^DxTRo$jc!P2-kF4Qzit4Lr0(Ci-=zc`WXD#Jn~WzT5NyqXTmwJBy=5F!tigyhR8 z1Aa%#{rf-DJ}Aa}zXq_Tn|B+cW}nzdp&0N9N?``HtBvqM8}2#=aapF}5qRW-oGg(R zJ`m37ywt}(X)v-;!$$s=Ud?LMAVD#_^3HE=NMPD|Gktmbg%HeD~FP=Q>-$X1ds8!0Iol*n-PzlaUH9gx01Uz>{yu zlpg~KjGVd0l|^r?FAw^(g2i;`imUzo?gsYXY#`?qhoG2$ojT&WsZiQ`Y6c4l=p%F9 zsF-lch`)%1I?|yS@yUqRo=KMIQv-W*B|;}M{7Q;3B1|}tT6+8;Mrvvu4GDnBtA)u# z908hiUlgp)10itv^_Y5p46w8ZJ{y1x^JmYx5ooUhx0TZcQ|69key50-lu5jl6=~7v<%x22j~`>wQMdsZ&XchHP>k<5t0Odl z>IWr;00XZTdv%D#FV?+hrb1NcTk$k%A3Of&v>{=0N2Z{l1uz%Vodu&Sh>Q|DPG}!C z9KsZ)xOS0rRzoIHc<}H$Bx#W=b+|<=Kt3W!ht-|MO98ZLtQ}Ci+ER&#$ON#VfiS## zuobuPAWa_g4b%xvIwCyZFt~wDhe#|R_ljF@0%(qXVMIO!{3?uHXwb=Z zDxVR8L6vDS>zo*VdU{a0E6d|k?LqHMSRMxGI$lI|JUpPsD^TN6DJ}cDm2R^?84V)n zr7aa5A5z6U*j9n+3HmM46R|e|otgjc`mXcTR4H!^)T>zurK-@V{PSvj_@ope#CL4} ztyAo+YISFCDzQBD`7He`&69&P1hBFu%3;LsyYQgDY@j|3hbBn75OC&kt&RBMx%YR$ z&msmASFG9fq|2m$>seqwNl(Sq3Nzc93>K{jYGzilfJ0L4+F)Haq-Kh()r#_SAT0g$ zLb;@lk|a&?@e6%A!6@$0gXE8QU=ar$683gP;B}pHCHeARw46h(deBWzA+f0>5Cano zBli;F#=>aQ+t~5w+)sjdV3FZ49^O6(Upmaw>v5e1Gx9z2T|#S?#@&A}681nkaKD32 zHW2@>ubb;h6c#WCZcp3P-HjHe*aD^fh2{8z#HEAk?0_~qe1FF$0BBFzpPg=UE98Py z=!p=DP9z3VklKsQgB86P36b|iI+2dT#$K+XFK9 zjeTEqhpw3V3xYRXt^DsJobP7^%oPH zQLZDMXe%#pk|E3nPDt-B^S6jjShV)Ol*8%X!D{zNRn@0pt9v(JVPxdNkUH2eZIE+hG#*Ta;A;?n&Pk?L^}$`nPFPs=~{! z0fw#+)@zKQZRW`-Vb^SniowXYf5~@G_4{ZAKBnNdw3BIO8^EC<=71Rs-fD~S3}FgD z7;m~4S0ORutp*r)paV7nKD4d=*OC93zVrsm5&4s&sSrb4hA3P2R@BkTk`K}+}hv%&NF>8^2^EmkvL)8J>Dkj9oETkjg zBG-Pt19AC*v(rYlb8pUmB{N*r^TpHMidv$mI?}7seiA4LH?Ay8Mex zLgU9%PK4Q6ekz}#rZH^CI-HPb^Wq78#Bto+#$zt7_Akx(j6usL6&Z?m#8&mn?ci_q zTU}VzDJ8XqKqqp)JLckd2h@=xZ*m5G`*S0n613|+)P;|qqM`eE9FuV9zLtUxw&y&_ z(FxJJA7jb;ESWt$dJkvM|4h0`V;oi7!{qLvYX=po0KEpIPA3jr9M=PefZOeF7fW>6Go+Fa0orTNasbAx>W&!?RX zXC}c_AhLO+{~5>rTYTqZm&~|lJJfFI32HE6VMflHybH2Kgsr6v?q%PyuDb%kH10{o zv0#PXUZs=ZM^E#}ibQWvfK01;)pq5xvFC<&2g8Jf{7@aL_F_qfVaOQc6UG&tPk2hu zbV939ySNjIAl7=Q@7$|5x$YH#CuoH8HPWl*CMBp=XYOzJsF#)?1sJfiurTnq(WVOI55=dQ zSYHc0z=VBCDTRziKwBZ6QjMwo(nai_n+>E#VBwiZl0u0&W` z(TIC`|7k5{p7^{TTBB>;>uHsqd*3p$Xr^W9gLJre2q@Xx{I*H9)elF&@g>Ac)`c^` z)J={l+F>SSkz?PBbUPId|6SSlf+exwpuhwXao?zr9W%BDEyR~dE6ZL69g6ge#S*-RKG&BiboTU1(r^{?@ur_V z%NaV_&mKEC&ea(CJ?)>+fXW|Sk_#_X!NNzsIwT(`5$*7*_iXSNaQqw>S}1Ce;UFEy zOFye&J*CwmhQ3zaM?+=i-k`SBX!nJtHVtue%e+9K7_3@G_;W8+KN`($I5Lu~E9-z` z$09j`$fM_rBb3vSqMh<8_z{gFA%O-NiT3AsG4SKtMz~vn&@R_f4FnDciM0znNIo6X zr4P}&os`h`q-Af2+A^@6d7J<$znprnh?F|ofD01!L$~{YYN6wFk~VqE?`ck*eo)M1 zNUL8rG5nyP_&oZi6W0F9j=Zv%Ou~7JQ0lTiReK}o(fFXAL_G4W`izziNg*ch?hhOR zbmE-!HgxNys9NJ8NJW;XRuE%F@Zb3{Ql6 zZi^0YDDprNBH;Mhh!ooL#m|*2J;YP1L$Qi#LyAhyr=+WnN zf6=;kaRF7PQ{AmZPtZm$qHB;uWxES?NK0vIgpUlLSUQE16u{g4rI`BSv-qwrhfX&Y7qano-*(T<^cu1gku=^v!4xfhwM%T!XW;bmMD3Fd)Is`Xn^1V z9^y7WAvE{(2}ApDU?==xpiA!W<4*EQp%Aiz;*$Vjt`JeOUsZE(T zcy->sE#9PM2MiXp*t;|d?F4w_4f) zFh|Fdv=|u)9p}&@p{gkml141-q%UTpCmm6vq?PH}M&3HSg`9v$$bNS~BZjM*_N28Q z4o+T5a7Q96P3~-SVf;P81-z@#6k>6Q$6qOMqP3SU=aMV(QRka47+N>u!Y_8j;ah7% zDOzJK{iFBtu16nN%e?T6FCot>wfU_2uS7rODFVHUyBcAI^rd|yx$T171bUK(h);XY zZ^s*ddXb70sE4=%ji$NKs!cRP0p$@O4U@&L1%h^2$jIx1L!v9*iv*lF(Yr1XadtPZd}|!BS9ywl8Or^k!RV&wuNU`KqOf% zuSlzyv(F?cM@g2WQ+Et=K_kEY!_BqIDyFv;zTs%drn=~X1C1qPbl7Mn|!XYws^X@gXF3BEORo5Y0{>M2J!JqP#7hW)J_ z(z5AgL4fx(^IW)UVQ=|0!+s}&Z1FuI<1ZfkuYCB(*Y>QZAN%IR)er~+2<_A!6`}pJ zS;9ZIu`$FT6&H=n2%d?+d{@Hep8fJ^X^N35W0*)ED$BHE0J5<_= z2CdCoaeqQf9XJOUVbei580>Lx8HGS9>d|}aF^CcR-SZ)+N~Pk8Mz;*m=lt%)F9<4f z5)2J^EhW5+eO3jDjs*-uko@Hq>+5bl4*gwpxR*n50$&}FZeGF~`%c6hZxR}^wQoIK zhGPv+(6Eo--$&Q>y+Vm{I3wuz;poEC?Dz0birH}nPcM%i;2)H#>TyIf%_(c1qmN5z z8Ey_ZJ?K4EmhYC>Vg{#@BZe%Pt{DocwAh@gD8P61(}ouKLhFdW#dZ$eewATlW&Ch% zexfV09Y^8>wmmblP?HS7f7s3242WFuemk2HF;N2u!o`B#Bkwn^NQk!%Vjl5 zxQUaLo&&XET_ent+A#$6w&3hTFe>oTpG`_%3D%FFa8#?~MDl0Wh?A!jIq0!Fv6MU_ zCS?x{al+Yh;_u(%AC&Z%wtPxMoT6gs6uPeCzjL+B+N-*xrd|2vri+q%wbYs(C?gMZ z>#urnKTKHnW_%a)(D=`A?8H%u3Q0g(U2d>Py-*3LJ0@#8%rmH)8;O&0gF-5Jh(n~^ zKG7Ys?#*svISdL8g25_1nm5)`d_Gje{mI9x`5+LsE~_nlkVw8)U@->Z582rcPFV2) ziOq#T+y$&zo}JKfJm{8np_Vykb9##xD#8o00S#C-tz{f{j*6xJLVU|JZLI-~Fu^IW zj-z+G;wkUZ0iCAxqC7jN3Rp7{w6rrg?_KG9L8B?GU`ryY{R>~s;07kV>9E}XjyJ^w zmchgy`@5ACzPl|pAzxZp)8X2Y=(6mPd8|4iG;}%qpL*b8uNXt`T7*wx1<~^M;91Zr zrK2{IxRn;AluqJal)Zt$OGGsYknu(PBnG6rom9e?dvd+@x9cw-ryFCW9(Cf^*_|4J zl@$XT8lbr_pkHwGudOaGR|2aT)-vva}oB(F1TM2mn&*4AA1V4{s#?*B)85 z^}7&OjN)sfDQ;Ew%gT=k16#QEduc6F)7Q1CR>!G}cWA(WLOj^caW835oyq1^&s}5? z!x$CJHb~DntJO(PhJI7~3VjU$v}yB6u2Kc(c|IsGP64M^4c1Mm3R8^Fj`09yRa%b! zI+0a1?ML}o@-h||Ia8#K;EcU%B~yPny$m)0n}ef+%ei%IkOTDV3o7EH-E*A)V+%PI zZ%Ukt%(?BltlMOa;ut|em+Iku^3$q9DMQiNT%9t$h`#AQdzYOWCZ@+`DOT+LEB1;hH4w(S$zYiaIMcBG7uT)Z>x{!*Tk-srnWqbgz0Z_0EjO_ z>#|&BE*lg2PcA>OAzlfP(*NUzyMO*q6!ZTtdA(drBvAjr@jrt6a;_w#fe2BFQgmQ! zOXZ)zia~00o`3Kuw&^cYOC7X^JUYS~$8M?Ye?&RP`DvM4uXEW{B!J2Iw@9|Ql(`Ew!&Hm~J^&*wK&N0kiy2iSG5@0}{@2d^xL^O8wUy6}Wt8-vdI9PGP!w0U zFIgWEZI}+Y<^ZJb|0CdXXQx!os`MXFx0i)Iscz(H#Td+Hv{})U8EW>RR|9 zkIOds{5siy9C(Ui%RS| zPVc_(T;?CUG%1((^7WRsK3g?^z`)lFxjP_-JIS=L8W-YvUDYE$S3WX*zh4#_(ISn^ z&S0X|D1EZ-l=z-6Gy9sJe3aA8F_T`^ta383!*8p7$b6aL!qL&uRUB;N_Ipp->hgG9 zFbJaHkwBp4*K+$JwQ3Wgg)#*|vB2Xiw5qP=HEZVh&R)L#IdP=4mno5B<_~J@pvbMD z2T`K~f~u2Q`$~$C;duXLe_F{CcB!U=1fNGSDkd*LzSO2o^h68gxaL|wv63vi0}^`XcS!L zUuH-Q|L*N9=dAm}@5&l0PIQpqcLVz5gw%!GIaZcgIl@5Qi|cd_S+1Ys3tOM1ix6{a zVee#t!P8;$Fr~speM36F-jOMDY$~oNU@A(bJNrH%&&^KWSu z2!disQ9lAsa4rj-Ol)~s+O=O(egle*;w+B_fJOR>e05{#>6g?oIF5&}T} zwmt?as#&0{FGE!fFsN9j%eyv7P_2{!b&^z|$!`wGU2F6EMkXN(Qs(D20S6L(VlUEl}oUGSF)r310Suu{zJZMjy zp7_MB#EvS8_y^AW8TzTqg|Y+CH4}Q>wvS+LwWUPi<8yGXr$sB<{A1g!F_Gf%49sOl z^q7XVClI(QvnfE6n@><82=Ef)eCuDrsmB>*6$wIZ3-iFLj~tCMSssuh#-)}yi09Iq zed`o=8xKt4e}BZGBOjMH@D@R-#1p#Mao3v3ZaB8-XF>#HYCB!)*dn1gBC?9ED8bDP zJkjMPr{Oion&*;qm`u(+WEFfMk+PLvU%#CEB&f)s5m@$j{Nv}t&2?T?raHm%uwMAs zE_A8lO`2PhgF5`QEA}T23acDeEv>C2l8_xQ?bkv2xrO<9lc2gdi*1M4w&()#gW4Ii zwqr!xZ!^gHoioco`_@yP$e-ed;wPiy7>*@d^Cy%r%NfxXv?uBEd7F9%Ht;co9_K-U z<$Il9u3D&N3&NYxO%^PJE*(lFP+CY5H@#RDrdU)%pfSnD!3KS_X?-OSmX| zyod)#CKyHl%PIh~R9?5W*ku&Gs7v&v*de8cNl_V@BiCY=eU)ZS-o`Ojq~@iKlB*)4 zSlhpuaKT8D``g~HNj?LvX|+-9CeA7z)X(zm=vbAM2Bu!MOlP9Q(KA?0UO(+#V^+-1|Pmf8U@85 zbfuvGR@enu@@s(v7g}U63X0Xn^%QB|eXOU$?k;$JUjBU*Fywy|=^ za}GZuR_^CIuWk~bW#jhjI-eqrUww(13u#ay5Z96i6LgZKXSf7w zb#~?}A2XqVi{FS?P>i( z7MGAsQ_7Myk>kbj0g+$WUGq6ZE^!BHN=DhpdT8Un%<*60Z8R_#9vlEU@(C*;lR5Jp z-4|FkkelE9jD$mJV(6GfF#P208E{E-dReSw^VtGwqdR6Z;a7AU=;@mS2i20Nl~;7v*YNm|b(p)aEbD zE>cO$Zn+}Jo3fe?3xDjkKB2mOYZes@&8Dh7@Q+WCu2xuy^IGDcm~)rLqi;$>Mk_XX zzh zD?ws7pNgI4JC$IS1*7%T{GgUerUHNx*}TMA)#oMx24Cq z_bmzN6zy|0rH3L*w$yTD%PS26g;+?KML7Q?77S6BUWh2sz#9NfbA@EN!eX5 zjB4{aiHDW_G-J{3DvMMtt*k9*ra8(>oUlN!-vweNs~H+yD>DuibI}USn1B%2JM6;x zFWMf}Ht-Sohse_}gfnOHE23+4#sMzu+;oi~X(Tt33gd|Y(jC2dX4IWscrG^z35<{Ku? zM24pS;x8En4gUXE%Fq`ja>jGya#J^BWFm0^83UYtwe0}7WgWntBh09Q>@sgfA?g~ zpc9|}pvJlcY9<2Z!IV$orY%SJHgg6j@ve_0m94fgGmQmK+_vRfo=oOawJ4ou&ip{0VYM=6mwA#uLO?kl?wd;m779>Q2^eHw8v%~9 zQS{YWB98!?ozzO<%vXQZ`#Zs+wFcux4iI4D9|75M3!&;@PLOr4_; z_ybOXc}rgNrw|hNRb{l)-wY$2t^=_}5Ws#OM#&wux`T8}D{X%n@SVp9U)kWn?GVz0 zwba+0tlL@V2z70e01OTW`Jn<4ua4)i^U?TM7exV?y?2ZY!>FaW+x_!nXl9+B&PwoO zMkQ-34g!o@l7OhJq`&DbbtUWf^cXTSiL#RJ zz^Y3fBEVRRCy)A)njfew#JDNo7*Gb&cJU| z0uTF!L7(`b3+#?D?%DgGn-D*lr7FgdqCL63`wmOv=_7Ev?E4167$_;s6Cw$0Cuq5Fw}NG;&B zq6H2`OHCr~zAtSr3UlTd{s?8YZ|_K8*0GldD&O^#2ka4GWBtc$y2r?5jt6$1%(U5k z;u)fQlR8@v*Q@LxGpi{4U5no6w5#JRNKJcQww`v_z#e{L#{(SGtkYx)TpRPReYBP+ zsa?$=Q=eAkm2e1Sb7b|+(50RD!2cfN)^h5T^14#>lSLkChN9q8QyY@z0n z;(ewmzradH{xD9oL`v#l6roVj!Sv2Le?o(dREPSM%(NCBNqL=hTf!ymk=YR7tZpMze|AA`l@Dec~6LiQV1MO-Wex6df zBr^*gtzTkE;wFhS=eJd_&PR45p7r%3p^XFoV_g8X`gcn^wrc<6Z_vd%>2IzjLFhM6wERcd3cAoW zZ($Lr!}7sY(o3hO{1-bxF&Y$517mz<>)Z_hY=zRlTBU5)KF~z08xmep*-aE#fGdz6 zz5|MSNuQI%=lj_fQWHl zWw`P#!Tl-W_uM_Ry|6&r+g4G(o6bR zh5rbwcN}Ntw&5Lm2fu-Ez2fxVZzn@}<+SMQG;#$o!)pnm}VT*b9j~yguR;Z=xS& z#&?$}zpSH^7-)x!lg>+}^Ap@|%84ojN&&YVcNx4wjnZS*zi$fzC}97U)mWFo&?5v+ zpib+q4CX{JmAE<>(Jzb+7!J%iO`%~BDM`JvJC%?U660>(ssMgwoHw#})uVm=5rDe{ zU}?;;$ZVfnGJ#9gAOuOQ6i>wHwq68JCIaK99ct}2()yeI-Ga9)l0gCxu%GDSN z6wMm%iAz(VHu|J(UCIz0W_?rBSS22FNYM{H10f0dQ<()$yd#7L4)&5i$bur0PtjIl z<_c<{8fKAE_XPwct<2GM5E!ashLbT>5-NT`&UIvIGt<7_W}?I)^`G`n>dx}EiTgUyr#eg2V0U*s^7{+l2U_iK2 z=L=+iFQZf~(2$qdL*d3P7!#gNavGsS@^Y^coAswx>n$*b1!W{h`!mQ@4Jtk2V!;GKSVlI+J69|0=ry6qj56*%38)zq<*AqUoZ(B`)aetk}aRT3Oj zRQrG&I|3dKE(Fw+Y)^q@gCB-IFaUXcYAq0q?V;DiSfW2F3ZU=IH$Zf>#KFUaVqfuTo| zZ67-H)0SzNoNvcEK)svA8bNY2e|w=A4cf|n@H4K1=vqMwqx0Qfr3g}}j27gGxK|QR zGycTAKQYo1BY_-DC;{(8IK-r(7vQ0!6y#klsmc})X?NVtuDx2VexxM9YR0cSzAcPm z@r@uE&6A~ZH^0CTx4K_1`fv8fkkQfqY>PbuQ}V?$fE=}08xMBE&0CCc=#`r`6&)$2 z2Zr&FMkFx@-tsvA2~OB(V|#0@@s-}*=ghYX2$aUyknve>d}l6%Bnk(?vyZ zobEQ<+OsCPgxo0ho~$VNO={-TD!RQi!oG_|g20C&s&Q>IuhUHVDCW;|+i%W%?t~1I z9~)wP`1zqa0j>Dc5$`GXzdB1%;t$aSV_t6)dU!F49%>}RB9<2yp6}$#D=L`1?<~El zU6lNFrf_y1n;K1;GauXngzDzKKCWQWfg0r>VN71^JD70237A8qjyo*AGFDSnLs5v9 z2|TPwyB0OWAk-#{$`GN%jp{zkbC}zKVXJ|VI2Tbs?R`OH5bPu-|4{VmKLUM);!$K# zW1E|X3diYveIjHO6vnp)6V8!t@wF2)5h7ciS(Uf^F+hI?>{N(xI}G&`i;Sb!pGYmO zvHI)yA|?rwBG-vRT*?9;soIJtQB{zr$gC+V^J-AJIKg+E zr1>;Yjkk6o(b&COKDBt{9macJ8RW-Q1&laPSP}`+5_ho26QmW%Wr)Pr*Qu7eq6B_f z$#3kT9`{8}Qq|*s^|`ghCEz5EK*_C~2Z@1pv;i#1)J$YPew6lNY$&+Qki$o?0>v7M%51}XJs6ah7I3Aw;M{4n9hwY(S;GCXBTayi~QHZ&VkGD zLu3DZ%tCkQtTQdpPO;2Ajq`8GIDdA3FHxt`_UOj7?GEq&)$-X(Drf zvgXUbqJcPahCns9XayK71VDHy?=0;EvT0Z4K-rO?_9KJbMCXoCS(42c@Pk$U1tA|-PuUU!*Y z4#q=S*f*BUV@OR^T~fsFJV47DfE!Bz#wW{WbiV}zO?1vI@Sy%d@+b1ECk@_(@pG~l zZZWb8o7Yc(PZH!qvpDb|;6S73KMrVgtLCzOA#(d$w~Ns_nd1@(!ar*hX#~XIf#&uJfByj9mzJRX8L_xja6k+`5WM7R>{8 zaX`uttF}3sv%X+7AY6H51!b6UknC)D{MW2b?~eIOcrgWb0S|$#vu9k%f5(k-2fO;C zuv7J&Vf?C=&pRd!<>F?lS*bKVhJmzXvxWm@LSg!Wik+XW9AS>~8?y~0%tRg!9ku|w z3-jGcHp1V)VZ|SIJZ72LkZ{O{gKC}>Rfi$@knR@cp)SHw4i^n8u9Q|J<)Ta{mq+|j zqM`rPRkVUVD<`-U(-K#6e8j>wlRuYJSfp&df~6i_Ck@>Cwi(jAZWvFGPQ2|`y1@ zub&Q={#%7Kx9@=gU+I*f)tr@Bm2`)WTJpX6{}@bL3%5m>{XACJ;HcALU!475IBr)H zY*1lU4Jcb0jMA4q5;2w)J}&Wa%3ulZszbmf-zQ{JkwTN%dgMFI4g?8%CQb6*yWLo{ zwV3STKKy>W&3(wd89WoUi>#d#7yZyB>LaO*m;P_CBJT)#%_dJTl{mTa^Wzmtvx&C)*2pLiV4Da$u`Ry zwxABs;}ftn1WK2cHt!^WxgTkkb}kSDpmfi#ZAbd4YIF6{ zjAB>rcR-19wU;G{bQ7RSe5eOk}@A}1Ae!{yc2rSA8l&SJGcKrPD<+{D!PGPonyvZ8g8a;Ze z1(dn_2RVhV`3~c#Tk|dh%QDL%%#$prD|g?croLcd%-y zLP1#>RG$CKPmTpqiE6R!@H(no0T^kHsqd=gmSPyh)O5m)Km8?c463==wJ`XWf1J9B z#nzfFKr{6^CJN{$m=gUcEiGzo)qi4@jnJ48YGX)=e%oML?{=*e%d6 z)Y%1M+5EuoKmRS|)uUEbZvV=SIkVhgk&u-Yb#`VOUXz`TXC}biLzy8W&lD@$n;7xI zWKq*MNCn5?rcY3B7_C{Y`@2+lpk}Q1O&6!u;dSuYxBZ5BT#u|K>UU~-ifw{+O@h}) z0uw@K&iC41WIvpJuX(&!>)uJqV#_I8M;p-bNfK`Icx#^yaL#;>;X$A7%D8(&}87DpqWPA~9pKl?tdB?Q^&u0G_m4v`tV zZWA&Y_?xpiq#9UG8r&@wkc_;T7(tI zUoLqOwMy^O({_)P?;8upj3tP$B$d`KYJAOnydjB~4!qQwQo`+;>j>aub`Eg{6c)w2 zhnZXg@1f@s@8=8gC>0qECi#^4dj%e8dBC6U=EKfBiSW5`caZg(P#O8Mzi*0_m!j)0 z%nkQWw4~)3ba@jqFd#f`_%Ko^=AK=VA12+RCYS&RyZklN)$393PV63Ba;@el{&^62 z9#G@Ro z3tTXjX0}u4smfT0{atu46q!JRNsu0&WXKdjtWPFE7UPEKxCPiSq8bQ<8*`XWT?1ej zNKfMtjq^5wQ&{&=%fu`v4Wi~VdZ{*=Va{RL^;MLWm9f~Z(NgKO3;CQ@mSra?57WkG z_WJ;>X^;7xD*S$VbdoXJ-|_Q)b~(we0@Zt?f{hNow@fLnDA8hDP6mx{IOnEBEN-&& zTdc`a(f#gCtXr|f%`MB_0<1?OFk_Sb*|l z{QzX+o^>MNFxzCS=u~6z&vh!RNCxf8*U?njYX?!}4=hXrk0MTaRnjd>7DK?Y08linHdWbFiv)1O4g0Tpc z{Ay&LOi4>41**I1Hrvh&wMv972PFu-Q&u?L>bn!TurQ$GZ7tDJvrn@GIj06GFM2>`z^Xq0POxhLsT$y z7T^|~F)QN3d>)o-weZj85Mialo-6$B2Z0~;j&mt5Y!IOlBi45zJvAX@HunQ%+SGMLB^F+d6Ox5r+)##?qwA1@} zEGuvVOSp>jM&Em#OzbvOj*}8ZiS9iHPakiZj2p(|(oQyRW7mtChuF9KGgA#+_V5kD_p3NZf

!Y_`MOM20y=QQg-)1T`?>Tqi5??ThazjZ!h+mpRbe=07?= zFey{4^vd=UQ=1Ug3tEg)*|iAMLuMpk1vVH!g|xddGU616tdX~<#)eP!FZ+z~Vx;Nm zMf2S+Y3N4l^Q|uhT#pF$c6jhyGy)~%FzL-c6*<0%j5$sIs@L=kt)#^=7t?GvVf;20 z-UP^Q6|&a2o;)e4U?PJYpup6a1f8K5Zhbf^WT%@3bb>rYQM=b zJ76llMdp$RY3CZ>NlJIyQEA1`*srsed?LuYH2!9|9^k=K-#WJH2|{p#?jHwPW)IkL zJH~Rg|N1pI=i=_~K0US%V4w}xAbvy*7?=!zt^MPJ$t$1Z&vpK~OP( zhPZg!%O3L>^f{;&ENQ;LLd~B#V^ccCU!HT|rg*TuIZiisnMtE;3>wbAC!V$V|2!S3 ziM^inPioFzpWFyT!PvLhU$aD|{*dLXLnuY}oIfTuy4ZXW%`r*mb~KqU|T~~>@vAbS*jjCu{?$YI5&)Mvz z>AXsXDq>DxO6iWe&q4Dw$T9d{UhDZb+&lg> zw{a}tt})VSWhv8XMfrK#ILeAzh`a-tU6BBCRLl}nk)r2rv9k+>3+}_ud&fRDpfz}v2&@J_QtH#6?+I0 z!uYKrx9qj7o{yIxP%53fptBokc0nC6zR26!;9h^862}_s1W^m6b-oL=~eBKmO+ugEuYV z&bm%KPWCL7w(8J>&+mOVJ+uUbKO7t!J4JBkN{M$mcL^2QCFzw``a51#K|oDYP@DR-yQAZrsmm#8Et*v=DOp!7 z5!oE5le!fyq?AkpJ{@LAf%+n(arsm|tTwY#AFy!Xu9`%J|Avwe{XGmNe zG?g8fX&$Lu9BF@(N_X03dbZ~D_ZC`(fvnT&V1StUgH4Z)ui@vZl{53l8u4QWz8Ma6{KQp7a`DH^&7`WJdqcqHClKxo zhC$5%4s~FNq}3BW(YP-;5*|AxLF;W)Mr=gp-6&9MMIQoBr-rY3)4pQr-=C3N^qt1G}H}1DZ3ar5a^UW`HX2Qq5J4NZ$qge;wcG{~cwGYR|NO&4W@< zWoSj+Wje&`LpxUMy?HTzqnvgP`6YGnc~u~@h)?BUXBz;vnP@jbd?a2!#VjS1y2iw? zRFT_Bg?YQ}H`eEs_g*Ss8s*g6x<<=l>r3kj;`sjVmSrB`C=ocKZZEz52Up6%u08g2(<$ymdMhaVDzzs)GYFzb|c0bu_=Y??80SwgS|gM+)5gTnkKQ7MdxcOki{A)G7O8hWW`gf9r+XwrvTd4fds``}=S1u!T zyu=**T5Z~mgZa`}PF);pfklzfs>rM;Ob$7Lr5xro=olp49Z3q9k6a_w&(P4&007`u zjsHFEkF4&Zv~0ym#x&BxN#^mjZ}5!_9#2R4SYwHEN@s-OO_vs=X70t_Cp2s*s)tqL zFHzPtyrn6aXPJ?EG1LG;(giLmP>&5X@cBg{_Z-I`EB#X>c9`S$$Wp#O^gI1AJ1)C* z59ea8-L$bZ6xkA@U5sIIvS_<8fb=#Do6;8EYY&6YuNm=JG_*9Xw(kbxyGZEhp~^)P zM!yruM^Q_2{wrx%6K6IDarZ5GIH6nTLBC!dRko83uV_+P%gGy2#WF|me0?j1Z%Pb2 zpc^@(Kb#LV!xChG*6oIqc#Gsi8)evmys3StvwZR`eIRl*@aoOQx!%tPG(@il z7M&!t-APxbCFzwtTs3et<1`%BNJ?+1Rj%ts&UTu@ZN5SlzpG~1OCF-5YM30K7T%-X zCt?{!_Rzr#3oERC8C`2cHP6%Pbj?TOR$MEIX>vl26V=zpmx#tH=yHk4He@(N*iVH& z=K%8{xN7x0CPdax3jDoo!t6IOJd(~27f9iR*LXbXnr-+N$Xrm7V+xG7?X%Y zTS|F8=0#U0-J^2mUmtz zc5Xg8)W9u5jounA&>WnFHW<0OK&6eKTeoz#`GL3IsWUtH4p+P`iRxH+h=6x_pE~z< z222r=>hoR}5RtY6{x9M9zGQ`WJwG<}Wm*H0lHnF>{8$_+8P=2hUVVV68r_cO|!pP zJ{0>$ODQ9$o}bh}@eEVM!t%V`3AIF1%f24-B%!cqlb7DSyJ1L+$Ih+^#ac-UQB=Ac zuAEtpARxJ#4vv*F>{{lVgYC2S+LqL{Am)~| z0n-Z1IuCZ2Z^Ff{;zsG*L>&i;oecQFlM}ywHO%GwOZR~3{j#!UFEThW6&K+%gq`7m zf{jZ%1LvWMT4>DBJo61&(P6HbaGGFP1{miN1pecFO=-lQ-`$$lILS!hzQbB!`5g}56n{vukNjk zL;j&EAchv+Y38S@Vi0?{ef(l3{*VVCa?=VYebzGkhFpLdlGv5SYe=c@1kA$&L;IV; z1$l__Y$yolsqt6V=T*LYt{Z9A04i2AY?z22uG6koSZBDp-1vqB3W8P18Pu)fAF1U< z2RkP_{0y7<)Ivr6Z;G3#c$sN2MN==vf80=Ob#TQs1)9g(e{qbMPDo6t&$bYKru-h^ zA~Uu_b9n4b91)UHRFrgbszXtVH3;~8-AsAjdxK-q#7^MjMuC6zU>Rx04%5aQfppXH zx=Ub!A@xoEVjfs$8)xuyAoTOL>VCS;u@IV8p)Cs`m~Www%5wsii5uOPD(=3?HrtkC3K@_`tWu?IlCD^t)5axOFm?RkLdm-d7=yf^~g3)80Ec zAmQa*-KM3al*~|^RGchR6pL3(1Q2RRyxCc;c%Cr)FW`#rQwoc;kZ?W3s;5%Ke#P7_ z`-#Nwm0a%p8YCA7GpyE0k=QU=_c`zPiCcEWPbqx@u+C33ifHJ8C9%4-aZk>gYp&<$ z(5!f#DL^6R5GkD_9R*)f;115PI*twR6+aX?K&BbZrh zf6!s6=6%vOPaukXyww?Jhtn2oD=FBw-7(CtDse5#q`%u5Jx_hOjR$tlq);L%E4+(2tJVFJ>rE+q?TMJZ7F z1_*J4`#|)faPZPB{FPdmT^9bkc7@aHmgAawR_m%tAf%d=wI_A z+gJB713M_^Y8k%#g!DFyL_iZ>xpj{I;|B`H^+j++1S3S(7kHG5%>or|p)lW&FC6~Q#dbR{FQr1`Yt%n)fI zElB@3!~&(9?1E~Pb2eYskup5{=tNOQjoi@edJ`bG2O8EEtjL?t;7Ezv2zeoZSVyjV zg|AuS1;FUW>Gpzcyh1#)g3Cz|)tpMSRh<@ZCje+#xo?#n?d5<3mSW9G3Td(X$Hkii zDZIM-C3Q2V?8BBRaUx`Q=N}F6g#ErD1$EmPavKpw#+mgw!!a39c4#)Te3*j=H5vVO zE|kCp+ILsvFr&u`ie?>aF|(vne(SUfa;}-qaY}1$`O#pfQS!G!+twnlgJcgpgD}a% z`e@w=;h7DqX<2y>1Kb7vE4Tu`I~;!)h+wiXLipmNQ|b>lvO2z1GXqPlG#Jsyh68_V zt)4vfi$9I(pBc^P#Jrc2@w@Rd^bFKB*yJBekYkmUuWjrfPz31kMd`!R^pJ~Os|T9R`S~&mio-k5 z3&+czWaSubxEj=@W)(2>Wh}8n^V}yG*uzy~JFQ>LT0?o&sQ^cXz*@uB`E3%%yv*0k z2BLroNIkC1(ZdV7+uRj(HIj5H?wEz`ridzp90dok_vKoDXd4n5>%jeh zJYIhCA5UYm+am!SV3Nr{%gfPa>w5XVTxH<^FWB5*}5bsmKAG1T2lH^^xn2>B-t8LMO+eT2g%7AiYAfpuAfP zS9T8@j`f5E+f+5kgLzpiDa1V}4UG5z6GY&S*;u#2^MFj#||zOuTnPs?93_Tb6a zUgGXWj*#r|ko6z1%;#eOL_RaPEgvd=nxAnLzE^Uj25t9zskAi`#qU3%#RKdlx-1Kj z6a25(NZm3F6j)#Q_hKXo*{JC2c6o6UUNVCX-;uz=9&Cp+`6iwkwyh*?$ePE?RNx6v44);IcHus$M8G8Lb*LvEKZX8 zh4Y+M2cmX4u6BKe>+1conY$vj3|n80ZN@F{8KBELX<4-I)=s^=0mT{F%R1qCIVpkm z6ZNd!#RhTBy9le6(*XeD@v#Am{8{3zr~F1`j$Spg6HVb8UsDq>$~PgEI{ozt8FClCezDzu=`qP`f!9jH? z;y0d3Fouj0p-!T4G(ofUL~Lj!U&QDJ*rA%v{xQ}m18MotmNPVeZ4+CE1^(C=RtLcM zS_8-q9q=jC4NvbROo_OKp|<>RK6Ppx(ak;1?RBph9mbJctxr?b?sAR8>yGvB9sX4a zvcoP}PAa(F0_C>>&S1N6M>TNlyHTIkc4ohcUj6Dp{KOr%U0EXyYzMrvrs&@_a%wKY z8Raqx5K!GXfiqJg^SU=%!uRdxgT~eS56lbyCP)Gg>UlV>TPxIALarLuZNVomo2~3M z#-Sc#{w~X3-)4fWuN9HGK9wN-BqKGFd6r_a1U2*z-UKtRon#MDk)vJ2Y~&C$ICs}K z*>}1;bo-V4FLV*v3e{j|3m&5ua(JZXtC+^ivaE(AVa1~)LS{Hio0Nm{Fs!3Ayo|~^ zyUjFNKbj31f0Z}3oWHAAs=}spi>~DMy_G5P4ld7quZ2uewtLs{y%2J{YHj;@pSc=r z05vz1W@k4b+>y5)z3!z`i@?#CT~2nQ0GzP&IpYo@E9)^!-EG*zb|O`mT8w0G;hgp! zyYoeCj*U%D6KdxD!t@vSooqydMp)9r`wYIaU(C&CQZ`7LZrY!ArB0Up7an zIwpOo4MyWZ-X&?k#MWVaSXI)F>o`nwNdRK7N0Xk&;0p@)f*iZMo18nOypNgparb?8 zsBl<#=0Z~j-)lNk|7-|m)%q$VJxHK;7ebbd*jPEQBLdu78tdWGyT@>i0!iX;aIZ)6 zbUvk<@9bUsug?z?+6{bMuuUBPEfm0XbUi0d-Nz=bvRZXa`^xtj#HQCnBet!JI|8jM z3&xN*_Iw9IWYZ0yE=!ag8k-@`yvRi-pjn{IO{0yq@w(`xy2Q_m+dd^^Q)gaVUjLE! z(~1WuViL+FmLi6^fU)tg8CYm+61_d{9+!!ytyqaS`JCAUfu^KTd8)OAwGvdo{A^tleIi7Vi2Zze>OP@^Vh{lyw_jatzr(#!yP%+i7so&J<}Bl=twN4X@no21rE z;_q5Ys4A!Mz5l_nhFbM#7ZDFT7bKSpqt{bx=OB^NkgCQifLg`*bC?mnRsGnKWT8TT z_eBD{*e+iB9)9J!B}9FK#5{KxwlXihS&cuMQ6ao>GRUH3u%McoGs~_7ShczWru#*! z<%D06D+)7_Ycq&HA~utffs4)Jb$|Jp?0JJJ<4E|tFv$tPNMe1cD$a+PPt0d71K9wJ zM-HFQ!D>j@O^I65%q?cdU>^zW!gqGe>r}e=jqc>zXBHe*6}q6kA@D}*Z{JTZl@*oU zWo%!oP#cX3?Zbe#3)_@8NWU@UueD6#yvQ~BrIghXWhPyw4BJ`vtto9qMTAwRWi|U@ z%wfpsJjSq+6NLbcp61-2?Rox$x_*8>h9tT1bsX>ch;hO?${`(7f_i(tdp8^&*`M%i z{z4fR_=2l8(wlz4F1CbZf-DYuZ|Aygc)Axso#Hmmh^@o%epgC6{s9IUTVI=EFEVu_ zt#`M%WM7P`l}-P#{%AIQeIE04vN^BRun96S3fmxXB~o@Dr00dIvYWM)Pf8|1j|#$9 za68rfV*Tz_?6A0@cd!H!!WTi$dcyJ1TnJ4Vfw90TIe&52Jeh}DRZePcLwCQ)`!(Zk z;zgqP<0rIX#5}hH|2b8~KB0reOx{4_ef5X_Qb=&T9<%e?W$tf%-EU{;0o1vVhudIK2Txc{F{r5Zn-vk88X*muW1nkm#EFY8crOe}H zV>BlZ)}mt7+m~=&IKXXpT(2uKz$$5M?=lh?o^Qx5bNPK37Q-SKq}HEhuG1bQkN)%n zY^rhK7=s(aUsXNGM9)s!LD90c0Oc>nc613ASJHETaSSk8{C^eYBuvr`7jFZ#G-Dnf z4tE;Rq5EMSlO9re7C&`hF%Xs`KURDSWdn^QF0OOKnZabQ94*N)B9*i)%Y}?Ty;cVD z0*SwVY^*SOZG_?()?nS$KOb;C=Rlu!=LRSJ=gMl<@qYZ?vFm_Lmuq`3v<3XwzLFZv zt$={}5}&nq0L*f%;p6N^Vz~auH9Gz7G&`1C%0ucAOD_}Y;`7i}ScR;T)-#*}TWSQd zndOrcDZ;$1S}7{BK1rDW`wP2GzgX<=Qz_9x$G5DAr>#mjR$e$4N1y^a(*q7^=gjv8 zw~p(JIxjA(cX}6&b(!bNh^xg7Q1z#?Q^zxh_{H%9kd!f}@<)@_WyUX-<$c?`h&#co zd6u_0Gh+_$7srIbADU4uhl6)AtHiW($4?L_H_!&|Us zxw=ebj_?;p7AlH$?0>cf9&Ktnyh$f%<{(7T`;A{%-r|1%LRk+h3%5Wmc3; zrK2y(u@lBx)3;_qG4vd@yH3~q+_Ap|Jjb7myNpA1Qk{+hpa>EYwjm1YIBqSWrQ?== zw}Gj3RBGkvCc$dy5|xAXMf><_=NlCP!0QA}Fo0Nku5qkh$qStz{9>8;}PYhNu$^b?V@9$%!OL1xi_AZq&a`Rh(D*Z7ZJ> z>Cd((oAJj_upp6E-LSEjrWD$Q>^i~+DXEFb|V@)uA4|T0o*iz1XzJ!V0q8TV)*fd3(jg( zMUixD>a75A2w=i1RDA~7W{7*;gyQRrZ8N=^D7ae%I58RuA9Wx6=A#br6=4Y=?cXeH zd1yiPSk-@tmSBTrz89u=HF*76cghRveed%Xx~F!_{_|BFR(4LcvE5goH+-0&U-~+Y zBXc9<*{9)2q6>_;TF#^YvD9!N(1l#c1-iRxvacl!=}xnc29NWx4Z>}cKL+s>W*WdU zzd$ePl!Hv%Rn==Eo71D*STBH9H4t_{!^XxJ_E=88;@W%49DSl1$EYwa<`n!S=jDBW z#`o63h4B6|-uI1LQE_JF4paESPHv2^=}=>9_13vCYVvZ}uxFK~S(r|@1H^D1k|=*$ zzVk7739&72^Kd7`gX!z&yIQlfZ>}Y~-*b{BIVa}U*yVuhrW9OSm9qRUqQe$gTjyHt zN)^}Iw}Jbvl`t7x_}eRkKhF1T^>5>Z<7HhuQ16Yu6@KSADZ-8qA6l-e2VDlF10Kb- z;Gxr(58_f01Vt|$;jaHsptJ$AB>NX|!vMnIyMPH)LnU@BK1Wh>@JY3jyHl&6xJUX{ zpkj(^a?KXi6V^bQGveXgy7Ft%eR9e)owJay{DaB@a(HjopvC>>$_sWsEYdzCxE^}t zI8e;wXcM)}da1lilYKslF~AOspH$4I6m)nh;!AVExJwH1`(O`AfFY_kd-@<|E6246 z+n@ZV>t}@SPvo-K5iVjK%0QQIvl2x{g6@9Yu*Y@=aRo~+`v*GeR%+c017?W_| zEwAI8FtoA_2LhpvzH4(gXw%nc@~^&|N`XTaF;@;WLg!wqi~ekYp3WTkM>tl6Y*hLN zf*shl2@62lELcOAaW=|Cj=yFLKg2PkZo&$a80;BYPzpviJ>jO((7bHPQ>WNiPp8E5g} z(8t1=DIjL5z8&jpv`I4&iqlO_jcj?8Tl2MJdz(t#)_sQX=D-XOU@;ockHI>_r_o{C zK3eply*Mj^2yHli0Ng*^W`H?}mU&w3;?ey2To|?SR@|Mmq3DyOBW+f(s-55qXl01L>`B`W!YC|yyEozWwg z>Gq#%1y zlQ(zY>leZ`Wp5ZmQ> zw(JbewD=Ia)M8s?#E4wg*DadQ`Q8{ZY&6mP zSKMFjBm95m-^yM*pC0{F;>w>dQ@{0{Fog^t#X;3kV|dB(!GGpWe#RfCtY!Vk00f?{ KelF{r5}E*qLTW|; diff --git a/webstore-assets/banner1.jpg b/webstore-assets/v1/banner1.jpg similarity index 100% rename from webstore-assets/banner1.jpg rename to webstore-assets/v1/banner1.jpg diff --git a/webstore-assets/banner2.png b/webstore-assets/v1/banner2.png similarity index 100% rename from webstore-assets/banner2.png rename to webstore-assets/v1/banner2.png diff --git a/webstore-assets/banner3.jpg b/webstore-assets/v1/banner3.jpg similarity index 100% rename from webstore-assets/banner3.jpg rename to webstore-assets/v1/banner3.jpg diff --git a/webstore-assets/banner4.png b/webstore-assets/v1/banner4.png similarity index 100% rename from webstore-assets/banner4.png rename to webstore-assets/v1/banner4.png diff --git a/webstore-assets/icon-128x128.jpg b/webstore-assets/v1/icon-128x128.jpg similarity index 100% rename from webstore-assets/icon-128x128.jpg rename to webstore-assets/v1/icon-128x128.jpg diff --git a/webstore-assets/v2/banner1.jpg b/webstore-assets/v2/banner1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..69990f0e33d0a15a3defde9b7fa074b8404fc65f GIT binary patch literal 207038 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

KtjoEr=~_8$1IQ5B95f`ai|}jsOL` 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 }>)TRH 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%0AYn{N@ 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 E2gnHoE&u=k literal 0 HcmV?d00001 diff --git a/webstore-assets/v2/banner2.png b/webstore-assets/v2/banner2.png new file mode 100644 index 0000000000000000000000000000000000000000..39b7405540b541e8636f997ab4d59fdff6487ba2 GIT binary patch literal 259412 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%0DHjTx9Re5eoBiBP6g2x%~JI9m)hw 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 >`jqrY!rnzQg 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

6EY9B` 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 a^Y=E+wCPTQBw8-okbJ!SHx_#AJMjnPeJ&LM literal 0 HcmV?d00001 diff --git a/webstore-assets/v2/icon-128x128-black.jpg b/webstore-assets/v2/icon-128x128-black.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3d431dad51a54bc05a0b371b3ab42227ca70da2 GIT binary patch literal 16993 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 Date: Thu, 29 Feb 2024 10:25:34 -0500 Subject: [PATCH 39/87] Update README.md --- README.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/README.md b/README.md index d682dd2..f935344 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,6 @@ Find the extension on the Chrome Webstore right [here](https://chrome.google.com - [Donate](#donate) - [Update](#update) - [Set up](#set-up) - - [Inject the code into the moodle](#inject-the-code-into-the-moodle) - - [Remove injection](#remove-injection) - [Mode](#mode) - [Settings](#settings) - [Internal Features](#internal-features) @@ -61,14 +59,6 @@ See the [changelog](./CHANGELOG.md) to see every updates ! Go to "Manage my extensions" on your browser, then click on "Load unpacked extension" and select the "extension" folder. Afterwards, click on the extension icon and enter the ApiKey obtained from [openai api](https://platform.openai.com/api-keys). Finally, click on the reload button next to model (it should give you the last ChatGPT version, otherwise enter it by your self) and click on the save button (The extension need to be configured before entering the moodle quiz). -## Inject the code into the moodle - -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 - -Type back the code you entered into the extension configuration on the keyboard and the injection will be removed from the current page. If You didn't provide a code into the extension then there is no way to remove the injection. - ## Mode

@@ -87,7 +77,7 @@ Type back the code you entered into the extension configuration on the ke

- Api key: the openai api key. -- Code: code that you will need to inject/remove the code. +- Code: a code to be more discret for injecting/removing the extension from the page. Simply type your code you entered into the configuration on the keyboard when you are on your moodle quiz and the extension will be inject. If you want to remove the injection just simply type back the code on your keyboard. - GPT Model: the gpt model you want to use. You can click on the reload button to get the latest version of available gpt model for your account but you need to enter the api key first. - Cursor indication: show a pointer cursor and a hourglass to know when the request is finished. - Title indication: show some informations into the title to know for example if the code have been injected. From d2bc6c4c65ca536c366c3a85801956f9ca9b742d Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:38:56 -0500 Subject: [PATCH 40/87] Update settings.png --- assets/settings.png | Bin 8193 -> 19274 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/settings.png b/assets/settings.png index 4d51e300fcede4908e3210ff8f2018c19b743b75..568e261f3838869b283f59ea4a0406830d145556 100644 GIT binary patch literal 19274 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 E4Vh8w>;M1& literal 8193 zcma)hRa9NgmNo9~?!h&n}(M?_=tuZQc6>?XDp& z1y%Eh?C3p!vyoJhgo3I|M13}ce~*z}6!hJppfLLWd7y`!D=puXX0}>-9-2KN@cuAx>5rpZ5{S`mc!lqrm?eb8+(gXUD(y z{}USn9|&m9p`a+46lEl}yiLyXG1atm3og2SM)1l~a7?a$TuHKlK3EA`N;9;s;5jWJ z*i&(_(9cF?eSC4Ts7iyriw_*k(iuc7p@vBaOp+R4Rke?n&=&4NLtsV9H(>NdRmruf z6~(_UL(y%YXI5~uE3&q3I9T;-KZ@v@;$d5!xX_&Qy=ZIsym9XLxVF(2D0YyYY2te% zj|C@*rTOT*9T-A|WR8PJg&abKR|KVq1y>9OukfCOXOzH!lVp^DPN71Qf<{St-;VP5 zmC`Z?dJvtYa&Tz#a5?b@pSmg*9QNQNKGj_&qKlhn8jt9_c37*Y_B4+qmW;s7>CL2g zpx!6HBB}Y}QqJcIcOqTVUp6xvwDcM#*QovZ=3aHK0~(ZU(m3-RDkK`v zB{5Z%m?%oD<~Zj$zoV4FD08)vV*hb0hWe-*_`T>*1H zJL7-S(GBz1R+UGE=nmR>wpQfp;QsI(7;mgh@+?EY4~9njwJ^;G5F|M3IQBJgiq zy{Ea?wf`MNL1|1rHtPdY2ohfxtfc|;t${9sVfZfE0$2gxL#U|(@>6LA#v&&xJ7IN4 zpnyN(#+iYJiwoP;wdz;ZIxX&9G)XN7AZB1PW{K(M{pBVS7D7)y2F4cO2q0(ws=?@N z5&G*>MYtbtr#|YfADbw~j>SE5X%0uzUls?O!JaEZTqUoWt1I1KPQA;dNv`7Rc)~37jOWr9Z;(^l~(NQ*5O-I?vU0XA-W!U)O;|KN=35 zq7oaXdyl2RUdvF%)r>a9E)QVyN?|@K_5!O6TiMn^r~a!|4NHb|smRp1?o6xvr8iF7 z^&y|na~d*yKdp)F$m&mm$)u^P@)rOR=^F&p9};Y8!7d;&j`gI_-y-N;V#8xQSP$#e z9t|2}UD^r;nsBio97!xxq7CCyd&sYg1$rZaR^%mN_MUy8E8p1&RN?x%qfPj%fQk7I z`q7Gkm>=&r0WKnYn3Xd+^R)6lsrx91avXm*-8K?j8Vtpi{zQGE$5e z0c$X0=`WRM*-=TQqD_l|10fm5FN@kAd1vx4Y;@VYI`bKAydg?SOqnGXh5k;{ccWtT zY)CN7GTodB$$^9oXmjr7AwVZ9FO+pbYw24=-a`=W*ShyQG-8BPaQ;-GtnM=cHv?8m zE8vTs*8e4hD5%`u7)vR~8Hb>E7Mqk~ALMVX3BP9DiImq{1PchP80_c(`>4oOV+^9j zH--W57rsF^v&b$smcYz2vU#xd)4Z2;1OOVRvx)I#fc^BT6|X5^ZJs-Nv5B#5grndR zl?JwQvNdtE6JlneZ*)|fP{Pq0rFul8#PR2+GM4kPoF8VAt2q*^N(XQp5{eFa(Ah3% zMr(Pr*Cb8yNycd}G2D;B2+#7Eo)kU?RhR)~}jk zj|I1dh*}e?@;-Bz6-vHi6CBF_6R6aJ=#WCxf?((*vBF@e-6?m)pC`;@x?A3ujB>tRsF$xnI&OVQgjjlw-12rC3$gt zckY|a%r|_SH?RtqJga51!%|3Vs{rWfxT-`ZyW{JH(#{9tRu{=MEY$oYq$J@Cj94bC zlDCRH;<)GBXHV6Q*yL9R0=|_N=b`mZKWuVxHl;LTVq!@jAHg40RkFx+Q^>LINpJQ` z+>hcalQb(tzJQ9yeOiw{`*A@BdLsRC&qtpFuUQ1#9)0~^z-2}22?fVsVvt_L3-c3V zBqvpTcbR1GUVx&czztFkwL#49>cTNK-xm#?+mSYyb) z3FC(sV(#765&Sh-B2Y#m5{q{WXiBh%!J=}M(My>$SI?NGS>WAtnA&er5T(b$L6q-M zBMk%m^Pe0(PLlaNZeA5FD|uf*;9dp$lK zP)el#n}x|UmSdr4=uc#-6*1hHP?LW!k@Ex;W35NN|u= z)yF!0#xAq33&K-|kuVPed(4MbetH?SHUcl16Nf&t$hJL(uYzB9&&Wtl1aA}I*E5+VziVwz+oca}u_sLwE6&oLyi*;^ z(N&I@z_Y{tx%ub^pDlMHtAaaKwA|H=C%@ZF8;SDKo)PG}H~f_Xly+(BMV|{Lw8Uq9 zPjQ51yPyTMQ%KlX2y!;mNT|irzD-#i*BVu~x6AH0yL+1c+t-oD*BX2pGF2K>-nl}m zE_+-JJwiGzF;etNVwdAENmj(!*vL9=CT!Q`(qFc>jJttED`>;S+|(+Tr9Phi6WJ#z zTPH_cIw>In_phz12r~Eq5$1qktq@FG!_Yh0J-rWexgj+2%rRqQJ@RYnXPsg7w-CnZ zdUpIOj<*iRRz%Q?0%rVA1?I$9K)kf5IW)Ea=8q|dcnP}0{P^N>8)sBm6^uQi3+tAY=KnLp^T9}+DvD_ezNGz!&o6jLfEIE zUH$E0X>g!!(C+2taK}Q!2O%MxK(Yt2$@x%zkEzP@BCtg)QPba;5(CsC{i7~{?O%8! zz3DGzi(Q)31sk&FOU7KG6s_Q#3~11v#yV${gwqy0k-OE9YH% z;kbXh*AOl;W;xTHqbHx;@Ysxdbj+WZy8tFvUJ0Hj&n&afTOc||;>P0Y)|=*{@H$H) z4s1OKBgg9icA^mk;;wldKfg6-#d&BKkMa`C!H`l2mbEV$H@!u#bXx>#7{#@%jqWe8 zU_FsNBq!xjTN#Rh$A|_8%5v+t7{j!(=Z*C;3NU9X5eDZCzX;RWJ#?@m{<%J#dC56C zJQXeb*}o|8I{d0BD{uNNF7k)d$Fk(lwL@7oQ#f0U=TQ4;<<%hpj(brP_L{{hRC<+^ zSp*62uDmNWdXZ3bISi+EkjhSjG{&D#>XQonlvx_ErIYFGOE9(ubjl7&iU=pdbd%R# z6Z4P{1@KWbg66~e2`KFzY_TAMMGD(wcbOq20Xw|idRkj&ZoPz}PdNndkWy+V&v#ve zNegz?PuO%e_U}Zrv-B6LGx=jZ>6rTow*8`iXAMXpy-zV5_H<8JZI9rwN**R;pC}Od zfx{isd#oAv>nFxh!vvHQnlGL_5f(0{kS+_j@1&~K-18xFiN&H?cH|!BfJ1TP$@^6J ziD?}1!^6;>$!c_Rf&=(WJSrQXG?6pepgzXWGxwkJzhV{MA*0ops`Og4 zXSEB(q8bWy>ZAfs?0Snsn}{CtE>asAzqWWYt7{eeHdRvn3h*b3it2gTm^I&sl>Ji7GM|VHHtDM- z{3!r2<5M!$1rqlnCBfgpK3dAcm90ffdgLuet5g6t%H-fM|E+D*2y>DAh7lFvP>jo{ zf0JBG;9`1`uEmB&;1&?SOY3Kn?{{`N{biS{P=4HG2!48{r$d-= zoMhEkk5KI(?nv!_hS{`zkc`0HI?P1_LlI|TP9rsVSUf_VXo&u%H3KDot%irpq$U}& zZ;KuoL5heSft?QwvtMx`nwDHMY^l?##54G_wT445A?UH78QN;PNHOioT)oQaS%J zY(2wgx97T=s=sIEd8Q>*tlwU4U-rCtFlx<+Gl*8Zx{(j)SS&o1FeG%G-()jkU9Ru_ z3TdX!E2R@d{a!5*O;?gxld(rmjDMa7=LfbF2WPLPp(a4ST=-IC`xGn-vEA=h{$1F~ zKC5~cT8<_80={Z3($5)@!kyeIlRkxiRJR^?J+Ct5Ay=IoO^hddj+Qi&>C2mf0i*KY z*}E?MrgSzY#d3k?mdT30fT?vtL=&sF%+B(GcQ)LwYZDCAxKyEMp?SnhWX2G5Q{fBR z4kOLb91vI9H`fhwvijVTOLbc=d)66l{*6Ket3pC)i#4Xzl;48cJaPMgvJni4Gkt*# zz9P=~#IrX6inSGbvLI~Ag5TdK%mrtoh}Wa(?$iBFw#&R6qHH`}-ws+>%%0QE z@CSgl16E^Hjl|(4#w1A%+lhx=^Cd=^G9s4~kkf`t>bD%m6r?WaX_pcV-#p3YMsim@ zV+}E2N4|{|y~H&uSC-gtTZ!TVm02>z0ANHO{1lH&1i%YTH*doc0|v6&?0)L%UL-4f zy(8y2{eqoXhn!j3iCL=sCEk;?B-pQy zum0Z9g8Flgt?f)Cz;31i4t@$NdAB-K`a${yIIC#Rt<=HM4RcEs>NwJe&9zE`Jf^~@ zozHhn^}yls{F$QNQ;+q>@~^pL1hiX>XUYWq-K{_6_BnVK^UH%vn|?cDYgF4CgdF8+ zQ9r>`s?JnIC7~qcnS!YfVt$Sx9DL?h%V2N+t*rM|kiW;!_4)3_lc(=^FGEXm;A7~* z95PXtC$zQ-fygHt{cpAFV7kY9OnY~=)AfM+>}6~{!*9GMIH_&M(3-U*5wzdE7q!Ai z9$0v8y&-to)yg^9-iQDrGw#qnBJBZ*F62+)A-l-D*&H@Dech|QC41HRZ6_Zk3b}5& zsx8lGtig)aDyPzYT!KL?bG)Lx_bNGhm-iky^&}QAUqCks?>{S5HUFf5X@@$=&h)~5 zu_GWx%^lV~P%Pmq$3_Y{@Mj^_-9V4iK=wAIBO}_ZuuFU^!|34p{%(6#Xw#n!((v5& zyx#0t+In!Mvv)QrA8^Mw55QRoEX8`vOK*zVGyA>sAStBoSw~JA_)7AvPZK@Ssc>7R z8FTSs)sG#&Iq^nqyOD%we*p^$G2 zFmVXmvqC2@{8U{&!Z^>%_I?{*0hRJ61Q%eTWv-S}%MF^SokAGzZ6!4qp@NQNnCQ(> zDBbVaB;@NvBqO%JlvoMe zekfl5@h^xG!|C(B!7GU+`jP`4Y9Usy3!hGRVp-!e(`U~|*?)8repGf_8)F}SX?9bp zd?M#=q^

hA2&KcW7(BL)udt07O>ed@5(Gxm4|(5n$jSQ>;3SINal(M8*~q=#Fm) za2jmJ-v&=T;(^{yIQp;QN2|V1bxBn)d@JQK%(73Id_DzwSkes!WIct&Z&U*0kE^%= zd3k6)5~0!x@WZB0RN9D2rry0_AkXw)twS+hzo!Q}X;z6GNfI$WN;~jA#1AW9LK{Lv!M{ z^|doIKl{p5QR=4B?ztu0b_ofdWNojcx+jlIQzZNj=EG}n9Q$rv*q{vyvQ9eQr4Z*J zv@(D`7BNb@Cmk5Z5tFj*9OJ$Ix*g$_5zT=YS~mTaKSvZ40kYX{1AJR*af&>I=0;dG zkv-qFL`?_9IHidcQ8@B-L+wLP-cNj7o2R}d12FoH2fpJU!U|&B>qW}di*Z$E&S;!tKP02LGyyeL1R#wsq8vlu=`CU%^sX?ayXLfHgcqrMqe{Y3oYj|9Db?PGV#n4UX5nS{o)UpdK%Ti>r@1&H?f;x793*tw3U&$p(jm zTmx_i??~0COT`95)WtHLQQFcM?>|AB4D?}j#{+$f+5KIq_lyoCq9_bwI(o>iUl&%=Xs245mVHJ)dU2`RumIHpCFZc02?&Z4ZiF56X6J7luW7(B>KB5`zCF}XFQC)_ygCrS6(9XCU%I8_T|8e z<+9MHT#US{3Q=}WsUNZApC~O0cf@c~xI?Id9edf&n0Emb!TUWIt|t-dvqydI{Co+- zJV60C!NWG4C%U2x^dPm%vw?HDl?fcsT@gHf_j2@}?z4#eexGb~9aoa1o7mN!HeRf? zv^{P6&?2<3ZuoCB-lt>bf#AeTx-u9#20gLidmLQWcVjSb-$aOz`EVNSLxe~nW)PO8 zD-+3}g4(3JF@($3Xj|>4(TTcbNXqq`Lm7==e547fUC!}?O^Jx4yd+f^7{@gpSm{Saj!(skG9#-)U z50Y*UmFWdG@qIsV`-VmI;*j|#a4m%xEP?`hh9*L;G50Bku0ULQfrbGTLhMfXUULxN zf<2~9CP$89sej`u!_JrbtpF`FoHD^JZ#;~F;B}J2a1ABD9yH-GqO$RZg*eqr1~)hU zVSAHeu`Q1@3U|vrM?^jP{l1aI!AQ!fGYm_GnSG(Gi(&ovml6v7Au9`^2f1c)FYs$x zcVYdF`bhH8m^jfsh$t9|i)kmQTv_C}tqtL28VmK5cQ&y-p1HEQ;l*pnqB2}>-jCQW zH2JND`-$9GhI(c%0q@RD6j6o3f^Y?r2M4q_FXT> z;mQ4Eq8EL)y;%YdXJuysZYFN1ZyqIpJ|&9+Rso}kd#x3G+jbXW=&P>w zc*psyvE6?oo>nbo23>|M*glbCg&3fVO%3!+YY7T>@5G%C|EKG~Td?{E<`T9daR|}o zh^f;!IAg``u=(mDBfQC>qy2<1W1i;S{OP@w9KCc;a#b+U4Tp^QIw%$j&jhepw5*Is$XX+nG9ahBr%hrCGU~k?jN$q^4fBiITaA zJ;gUv5p=9uXA`#sU$98hPxctrnvW?1Imsa(_{c1la`jsF4ESGLX%HjgU@W_)Fj5UU z2)Nx=Rt3dAx?ZHNsR_ zm`&rSrCOv|-Ee~{8bQz*-P2pM2;>xAS_-1o;WGb0@l+QbXX$}8tu&yM%x#^tfSpQE zoxQ^G(`|tX2LRO8iYv=+{!2a$@Uq0|P=gojDgPsY6kb|a+}9U!wN!Bb5 zJv0CgMeJ%D9O|RrY8;2bTLtp`nJ)q455?f`xNHnYW`lv{uUsEz$PNW6Ksv2bi6noJ13t9CJ!<3d8RN?KYr>1#34G-l@-t27 z4(dm5DzV&>sE-kpg#L&}MY&5BHMeuDLM!(`PaXKK>v!Kx7=NK+D8(?YXR*;U60{bA ztOU%i^oL2odwpniW`Gz!Xpn(>OVsxmcFrXl|Yp)|cQ From 1365ccb56decedab6bafd2e35fae99f48250836f Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:39:33 -0500 Subject: [PATCH 41/87] Includes images to the question --- extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- extension/popup/index.html | 14 ++++-- extension/popup/js/gptVersion.js | 17 ++++++- extension/popup/js/index.js | 19 ++++---- extension/popup/js/modeHandler.js | 11 +++-- extension/popup/js/utils.js | 13 ++++++ extension/popup/style.css | 3 +- src/core/get-response.ts | 71 +++++++++++++++++++++++++++-- src/core/reply.ts | 8 ++-- src/types/config.ts | 3 +- src/utils/image-to-base64.ts | 34 ++++++++++++++ src/utils/version-support-images.ts | 14 ++++++ 13 files changed, 182 insertions(+), 29 deletions(-) create mode 100644 src/utils/image-to-base64.ts create mode 100644 src/utils/version-support-images.ts diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index 3df2e1d..63c4573 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,2 +1,2 @@ -!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={}));const l="\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),c={url:null,system:{role:s.SYSTEM,content:l},history:[]};function a(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function u(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function f(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function d(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function p(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function m(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function h(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function g(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function v(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+a(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),l=yield function(e,t){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&c.url===n||(c.url=n,c.history=[]);const o=new AbortController,r=setTimeout((()=>o.abort()),15e3),l={role:s.USER,content:t},a=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?o.signal:null,body:JSON.stringify({model:e.model,messages:[c.system,...c.history,l],temperature:.8,top_p:1,presence_penalty:1,stop:null})});clearTimeout(r);const u=(yield a.json()).choices[0].message.content;return e.history&&(c.history.push(l),c.history.push({role:s.ASSISTANT,content:u})),{question:t,response:u,normalizedResponse:i(u)}}))}(e.config,t).catch((e=>({error:e}))),v="object"==typeof l&&"error"in l;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||v?"pointer":"initial"),v)console.error(l.error);else switch(e.config.logs&&(r.question(t),r.response(l)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),u(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:l,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:l,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[f,g,d,h,p,m];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;u(e.config,e.gptAnswer)}({config:e.config,gptAnswer:l,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const y=[],w=[];function A(e){const n=w.findIndex((n=>n.element===e));if(-1!==n){const e=w.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function E(n){if(w.length>0){for(const e of w)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(w.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=v.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>A(o)});w.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){y.push(n.key),y.length>e.code.length&&y.shift(),y.join("")===e.code&&(y.length=0,E(e))}))}(n):E(n)}))})); +!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={url:null,system:{role:s.SYSTEM,content:c},history:[]};function u(e,t,o){return n(this,void 0,void 0,(function*(){const n=t.querySelectorAll("img");if(!e.includeImages||!function(e){const n=e.match(/gpt-(\d+)/);return!!(null==n?void 0:n[1])&&Number(n[1])>=4}(e.model)||0===n.length)return o;let r=[];const i=Array.from(n).map((e=>{return n=e,new Promise(((e,t)=>{const o=document.createElement("canvas"),r=o.getContext("2d");if(!r)return void e(null);const i=new Image;i.crossOrigin="Anonymous",i.onload=()=>{o.width=i.width,o.height=i.height,r.drawImage(i,0,0);const n=o.toDataURL("image/png");e(n)},i.onerror=e=>{t(e)},i.src=n.src}));var n})),s=(yield Promise.all(i)).filter((e=>null!==e));for(const e of s)r.push({type:l.IMAGE,content:e});return r.length>0?r.push({type:l.TEXT,content:o}):r=o,r}))}function f(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function d(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function m(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function p(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function h(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function g(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function v(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function y(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function w(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+f(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),l=yield function(e,t,o){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&a.url===n||(a.url=n,a.history=[]);const r=new AbortController,l=setTimeout((()=>r.abort()),15e3),c=yield u(e,t,o),f={role:s.USER,content:c},d=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?r.signal:null,body:JSON.stringify({model:e.model,messages:[a.system,...a.history,f],temperature:.8,top_p:1,presence_penalty:1,stop:null})});clearTimeout(l);const m=(yield d.json()).choices[0].message.content;return e.history&&(a.history.push(f),a.history.push({role:s.ASSISTANT,content:m})),{question:o,response:m,normalizedResponse:i(m)}}))}(e.config,e.questionElement,t).catch((e=>({error:e}))),c="object"==typeof l&&"error"in l;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||c?"pointer":"initial"),c)console.error(l.error);else switch(e.config.logs&&(r.question(t),r.response(l)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),d(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:l,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:l,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[m,y,p,v,h,g];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;d(e.config,e.gptAnswer)}({config:e.config,gptAnswer:l,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const A=[],E=[];function S(e){const n=E.findIndex((n=>n.element===e));if(-1!==n){const e=E.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function x(n){if(E.length>0){for(const e of E)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(E.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=w.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>S(o)});E.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){A.push(n.key),A.length>e.code.length&&A.shift(),A.join("")===e.code&&(A.length=0,x(e))}))}(n):x(n)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index cd0322c..1e7abaf 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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/core/get-response.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport normalizeText from '@utils/normalize-text';\n\ntype History = {\n url: string | null;\n system: { role: ROLE; content: string };\n history: { role: ROLE; content: string }[];\n};\n\nenum ROLE {\n SYSTEM = 'system',\n USER = 'user',\n ASSISTANT = 'assistant'\n}\n\nconst INSTRUCTION: string = `\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\n- Always reply in the format: '\\n\\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n`.trim();\n\nconst history: History = {\n url: null,\n system: {\n role: ROLE.SYSTEM,\n content: INSTRUCTION\n },\n history: []\n};\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(config: Config, question: string): Promise {\n const URL = location.hostname + location.pathname;\n\n // We reset the history when we enter a new moodle quiz or when it's desactivate\n if (!config.history || history.url !== URL) {\n history.url = URL;\n history.history = [];\n }\n\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 15 * 1000);\n\n const message = { role: ROLE.USER, content: question };\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: [history.system, ...history.history, message],\n temperature: 0.8,\n top_p: 1.0,\n presence_penalty: 1.0,\n stop: null\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Register the conversation\n if (config.history) {\n history.history.push(message);\n history.history.push({ role: ROLE.ASSISTANT, content: response });\n }\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, question).catch(error => ({\n error\n }));\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","INSTRUCTION","history","url","system","role","SYSTEM","content","htmlTableToString","table","tab","lines","Array","from","querySelectorAll","maxColumnsLength","map","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","config","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","type","number","_b","match","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","filter","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","questionElement","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","model","messages","temperature","top_p","presence_penalty","stop","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","error","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/core/get-response.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport imageToBase64 from '@utils/image-to-base64';\nimport normalizeText from '@utils/normalize-text';\nimport isCurrentVersionSupportingImages from '@utils/version-support-images';\n\ntype Content =\n | string\n | Array<{\n type: CONTENT_TYPE;\n content: string;\n }>;\n\ntype History = {\n url: string | null;\n system: { role: ROLE; content: Content };\n history: { role: ROLE; content: Content }[];\n};\n\nenum ROLE {\n SYSTEM = 'system',\n USER = 'user',\n ASSISTANT = 'assistant'\n}\n\nenum CONTENT_TYPE {\n TEXT = 'text',\n IMAGE = 'image_url'\n}\n\nconst INSTRUCTION: string = `\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\n- Always reply in the format: '\\n\\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n`.trim();\n\nconst history: History = {\n url: null,\n system: {\n role: ROLE.SYSTEM,\n content: INSTRUCTION\n },\n history: []\n};\n\n/**\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\n * @param config\n */\nasync function getContent(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const imagesElements = questionElement.querySelectorAll('img');\n\n if (\n !config.includeImages ||\n !isCurrentVersionSupportingImages(config.model) ||\n imagesElements.length === 0\n ) {\n return question;\n }\n\n let content: Content = [];\n\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\n const results = await Promise.all(base64Images);\n const filteredResults = results.filter(value => value !== null) as string[];\n\n for (const result of filteredResults) {\n content.push({\n type: CONTENT_TYPE.IMAGE,\n content: result\n });\n }\n\n if (content.length > 0) {\n content.push({\n type: CONTENT_TYPE.TEXT,\n content: question\n });\n } else {\n content = question;\n }\n\n return content;\n}\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const URL = location.hostname + location.pathname;\n\n // We reset the history when we enter a new moodle quiz or when it's desactivate\n if (!config.history || history.url !== URL) {\n history.url = URL;\n history.history = [];\n }\n\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 15 * 1000);\n\n const content = await getContent(config, questionElement, question);\n const message = { role: ROLE.USER, content };\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: [history.system, ...history.history, message],\n temperature: 0.8,\n top_p: 1.0,\n presence_penalty: 1.0,\n stop: null\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Register the conversation\n if (config.history) {\n history.history.push(message);\n history.history.push({ role: ROLE.ASSISTANT, content: response });\n }\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","/**\r\n * Check if the current ChatGPT version support image sending\r\n * @param version\r\n * @returns\r\n */\r\nfunction isCurrentVersionSupportingImages(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isCurrentVersionSupportingImages;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n resolve(null);\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png');\r\n resolve(base64);\r\n };\r\n img.onerror = error => {\r\n reject(error);\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","history","url","system","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isCurrentVersionSupportingImages","model","base64Images","Array","from","map","imgEl","imageToBase64","imageElement","canvas","createElement","ctx","getContext","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","error","src","filteredResults","all","filter","type","IMAGE","TEXT","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","_b","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","messages","temperature","top_p","presence_penalty","stop","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file diff --git a/extension/popup/index.html b/extension/popup/index.html index ca94616..34b4612 100644 --- a/extension/popup/index.html +++ b/extension/popup/index.html @@ -27,14 +27,15 @@

-
+
icon + > + icon +

MoodleGPT

@@ -113,9 +114,14 @@
+ +
-

Message

+

{Message}

diff --git a/extension/popup/js/gptVersion.js b/extension/popup/js/gptVersion.js index 9cb7c0a..cae27f1 100644 --- a/extension/popup/js/gptVersion.js +++ b/extension/popup/js/gptVersion.js @@ -1,5 +1,18 @@ 'use strict'; +const modelInput = document.querySelector('#model'); +const imagesIntegrationLine = document.querySelector('#includeImages-line'); + +// Check if the gpt version is at least 4 to show the option 'Include images' +modelInput.addEventListener('input', function () { + const version = modelInput.value; + if (isCurrentVersionSupportingImages(version)) { + imagesIntegrationLine.style.display = 'flex'; + } else { + imagesIntegrationLine.style.display = 'none'; + } +}); + /** * Get the last ChatGPT version */ @@ -7,7 +20,7 @@ function getLastChatGPTVersion() { const apiKeySelector = document.querySelector('#apiKey'); const reloadModel = document.querySelector('#reloadModel'); - let apiKey = apiKeySelector.value; + let apiKey = apiKeySelector.value?.trim(); // If the api key is set we enable the button to get the last chatgpt version function checkFiledApiKey() { @@ -40,7 +53,7 @@ function getLastChatGPTVersion() { }); const rep = await req.json(); const model = rep.data.find(model => model.id.startsWith('gpt')); - document.querySelector('#model').value = model.id; + modelInput.value = model.id; } catch (err) { console.error(err); showMessage({ msg: 'Failed to fetch last ChatGPT version', error: true }); diff --git a/extension/popup/js/index.js b/extension/popup/js/index.js index caad3df..f293fbf 100644 --- a/extension/popup/js/index.js +++ b/extension/popup/js/index.js @@ -1,6 +1,8 @@ +'use strict'; + const saveBtn = document.querySelector('.save'); -/* inputs id */ +// inputs id const inputsText = ['apiKey', 'code', 'model']; const inputsCheckbox = [ 'logs', @@ -10,20 +12,20 @@ const inputsCheckbox = [ 'mouseover', 'infinite', 'timeout', - 'history' + 'history', + 'includeImages' ]; -/* Save the configuration */ +// Save the configuration saveBtn.addEventListener('click', function () { const [apiKey, code, model] = inputsText.map(selector => document.querySelector('#' + selector).value.trim() ); - const [logs, title, cursor, typing, mouseover, infinite, timeout, history] = inputsCheckbox.map( - selector => { + const [logs, title, cursor, typing, mouseover, infinite, timeout, history, includeImages] = + inputsCheckbox.map(selector => { const element = document.querySelector('#' + selector); return element.checked && element.parentElement.style.display !== 'none'; - } - ); + }); if (!apiKey || !model) { showMessage({ msg: 'Please complete all the form', error: true }); @@ -51,6 +53,7 @@ saveBtn.addEventListener('click', function () { infinite, timeout, history, + includeImages, mode: actualMode } }); @@ -58,7 +61,7 @@ saveBtn.addEventListener('click', function () { showMessage({ msg: 'Configuration saved' }); }); -/* we load back the configuration */ +// we load back the configuration chrome.storage.sync.get(['moodleGPT']).then(function (storage) { const config = storage.moodleGPT; diff --git a/extension/popup/js/modeHandler.js b/extension/popup/js/modeHandler.js index 1d77676..60dccac 100644 --- a/extension/popup/js/modeHandler.js +++ b/extension/popup/js/modeHandler.js @@ -5,7 +5,10 @@ const modes = mode.querySelectorAll('button'); let actualMode = 'autocomplete'; -/* inputs id that need to be disabled for a specific mode */ +// input to don't take in consideration +const toExcludes = ['includeImages']; + +// inputs id that need to be disabled for a specific mode const disabledForThisMode = { autocomplete: [], clipboard: ['typing', 'mouseover'], @@ -17,7 +20,9 @@ const disabledForThisMode = { */ function handleModeChange() { const needDisable = disabledForThisMode[actualMode]; - const dontNeedDisable = inputsCheckbox.filter(input => !needDisable.includes(input)); + const dontNeedDisable = inputsCheckbox.filter( + input => !needDisable.includes(input) && !toExcludes.includes(input) + ); for (const id of needDisable) { document.querySelector('#' + id).parentElement.style.display = 'none'; } @@ -26,7 +31,7 @@ function handleModeChange() { } } -/* Mode handler */ +// Mode hanlder for (const button of modes) { button.addEventListener('click', function () { const value = button.value; diff --git a/extension/popup/js/utils.js b/extension/popup/js/utils.js index 17a42cb..0c71661 100644 --- a/extension/popup/js/utils.js +++ b/extension/popup/js/utils.js @@ -10,3 +10,16 @@ function showMessage({ msg, error, infinite }) { message.style.display = 'block'; if (!infinite) setTimeout(() => (message.style.display = 'none'), 5000); } + +/** + * Check if the current model support images integrations + * @param {string} version + * @returns + */ +function isCurrentVersionSupportingImages(version) { + const versionNumber = version.match(/gpt-(\d+)/); + if (!versionNumber?.[1]) { + return false; + } + return Number(versionNumber[1]) >= 4; +} diff --git a/extension/popup/style.css b/extension/popup/style.css index fa48bbb..85b8c39 100644 --- a/extension/popup/style.css +++ b/extension/popup/style.css @@ -132,8 +132,7 @@ a { #message { display: none; - margin-top: 0.75rem; - margin-bottom: -0.25rem; + margin-bottom: -0.5rem; } #reloadModel { diff --git a/src/core/get-response.ts b/src/core/get-response.ts index 9a32435..2828a9e 100644 --- a/src/core/get-response.ts +++ b/src/core/get-response.ts @@ -1,11 +1,20 @@ import type Config from '@typing/config'; import type GPTAnswer from '@typing/gptAnswer'; +import imageToBase64 from '@utils/image-to-base64'; import normalizeText from '@utils/normalize-text'; +import isCurrentVersionSupportingImages from '@utils/version-support-images'; + +type Content = + | string + | Array<{ + type: CONTENT_TYPE; + content: string; + }>; type History = { url: string | null; - system: { role: ROLE; content: string }; - history: { role: ROLE; content: string }[]; + system: { role: ROLE; content: Content }; + history: { role: ROLE; content: Content }[]; }; enum ROLE { @@ -14,6 +23,11 @@ enum ROLE { ASSISTANT = 'assistant' } +enum CONTENT_TYPE { + TEXT = 'text', + IMAGE = 'image_url' +} + const INSTRUCTION: string = ` Act as a quiz solver for the best notation with the following rules: - When asked for the result of an equation, provide only the result without any other information and skip the other rules. @@ -37,13 +51,61 @@ const history: History = { history: [] }; +/** + * Get the content to send to ChatGPT API (it allows to includes images if supported) + * @param config + */ +async function getContent( + config: Config, + questionElement: HTMLElement, + question: string +): Promise { + const imagesElements = questionElement.querySelectorAll('img'); + + if ( + !config.includeImages || + !isCurrentVersionSupportingImages(config.model) || + imagesElements.length === 0 + ) { + return question; + } + + let content: Content = []; + + const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl)); + const results = await Promise.all(base64Images); + const filteredResults = results.filter(value => value !== null) as string[]; + + for (const result of filteredResults) { + content.push({ + type: CONTENT_TYPE.IMAGE, + content: result + }); + } + + if (content.length > 0) { + content.push({ + type: CONTENT_TYPE.TEXT, + content: question + }); + } else { + content = question; + } + + return content; +} + /** * Get the response from chatGPT api * @param config * @param question * @returns */ -async function getChatGPTResponse(config: Config, question: string): Promise { +async function getChatGPTResponse( + config: Config, + questionElement: HTMLElement, + question: string +): Promise { const URL = location.hostname + location.pathname; // We reset the history when we enter a new moodle quiz or when it's desactivate @@ -55,7 +117,8 @@ async function getChatGPTResponse(config: Config, question: string): Promise controller.abort(), 15 * 1000); - const message = { role: ROLE.USER, content: question }; + const content = await getContent(config, questionElement, question); + const message = { role: ROLE.USER, content }; const req = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', diff --git a/src/core/reply.ts b/src/core/reply.ts index 84e619e..f00122a 100644 --- a/src/core/reply.ts +++ b/src/core/reply.ts @@ -25,9 +25,11 @@ async function reply(props: Props): Promise { const question = createAndNormalizeQuestion(props.form); const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery); - const gptAnswer = await getChatGPTResponse(props.config, question).catch(error => ({ - error - })); + const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch( + error => ({ + error + }) + ); const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer; diff --git a/src/types/config.ts b/src/types/config.ts index ab8205a..cf31c87 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -1,7 +1,7 @@ type Config = { apiKey: string; + model: string; code?: string; - model?: string; infinite?: boolean; typing?: boolean; mouseover?: boolean; @@ -10,6 +10,7 @@ type Config = { title?: boolean; timeout?: boolean; history?: boolean; + includeImages?: boolean; mode?: 'autocomplete' | 'question-to-answer' | 'clipboard'; }; diff --git a/src/utils/image-to-base64.ts b/src/utils/image-to-base64.ts new file mode 100644 index 0000000..6549a64 --- /dev/null +++ b/src/utils/image-to-base64.ts @@ -0,0 +1,34 @@ +/** + * Convert an image html element into a base64 image string + * @param imageElement + * @returns + */ +function imageToBase64(imageElement: HTMLImageElement): Promise { + return new Promise((resolve, reject) => { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + + if (!ctx) { + resolve(null); + return; + } + + const img = new Image(); + img.crossOrigin = 'Anonymous'; + img.onload = () => { + canvas.width = img.width; + canvas.height = img.height; + ctx.drawImage(img, 0, 0); + + const base64 = canvas.toDataURL('image/png'); + resolve(base64); + }; + img.onerror = error => { + reject(error); + }; + + img.src = imageElement.src; + }); +} + +export default imageToBase64; diff --git a/src/utils/version-support-images.ts b/src/utils/version-support-images.ts new file mode 100644 index 0000000..103cb69 --- /dev/null +++ b/src/utils/version-support-images.ts @@ -0,0 +1,14 @@ +/** + * Check if the current ChatGPT version support image sending + * @param version + * @returns + */ +function isCurrentVersionSupportingImages(version: string): boolean { + const versionNumber = version.match(/gpt-(\d+)/); + if (!versionNumber?.[1]) { + return false; + } + return Number(versionNumber[1]) >= 4; +} + +export default isCurrentVersionSupportingImages; From 7308297802a8c9a709012a04f5887ef5e3cdd70e Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 29 Feb 2024 11:39:44 -0500 Subject: [PATCH 42/87] Doc update --- README.md | 1 + TODO.md | 2 ++ 2 files changed, 3 insertions(+) diff --git a/README.md b/README.md index f935344..61d5f81 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ Go to "Manage my extensions" on your browser, then click on "Load unpa
![Mouseover2](./assets/mouseover2.gif) - Infinite try: click as much as you want on the question (don't forget to reset the question). - Save history: allows you to create a conversation with ChatGPT by saving the previous question with its answer. However, note that it can consume a significant number of tokens. +- Include images (only work with gpt-4): allows you to include the images from the question to be send to the chatgpt api. However, note that it can consume a significant number of tokens. ## Internal Features diff --git a/TODO.md b/TODO.md index 036f1b3..dcbbce3 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,8 @@ # TODO - Historic for questions (implemented but need testing) +- Image integration for gpt-4 (implemented but need testing) + - Better prompt (Fixe put in order question, Fixe calculation question) - Support math equation from image stocked in the `data-mathml` attribute - Better webstore assets From ece1e832a724b9993104a453c6b4116661adab10 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 29 Feb 2024 13:02:21 -0500 Subject: [PATCH 43/87] implemented images support for gpt4 --- README.md | 1 + TODO.md | 3 --- assets/images.gif | Bin 0 -> 219082 bytes extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- extension/popup/js/gptVersion.js | 11 ++++++++--- src/core/get-response.ts | 26 ++++++++++++++++---------- src/utils/version-support-images.ts | 6 +++--- test/fake-moodle/assets/cat1.jpg | Bin 0 -> 4666 bytes test/fake-moodle/assets/cat2.jpg | Bin 0 -> 22523 bytes test/fake-moodle/css/style.css | 4 ++++ test/fake-moodle/index.html | 17 ++++++++++++++++- 12 files changed, 50 insertions(+), 22 deletions(-) create mode 100644 assets/images.gif create mode 100644 test/fake-moodle/assets/cat1.jpg create mode 100644 test/fake-moodle/assets/cat2.jpg diff --git a/README.md b/README.md index 61d5f81..5fe2fd7 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Go to "Manage my extensions" on your browser, then click on "Load unpa - Infinite try: click as much as you want on the question (don't forget to reset the question). - Save history: allows you to create a conversation with ChatGPT by saving the previous question with its answer. However, note that it can consume a significant number of tokens. - Include images (only work with gpt-4): allows you to include the images from the question to be send to the chatgpt api. However, note that it can consume a significant number of tokens. +
![Images](./assets/images.gif) ## Internal Features diff --git a/TODO.md b/TODO.md index dcbbce3..8c87e9b 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,5 @@ # TODO - Historic for questions (implemented but need testing) -- Image integration for gpt-4 (implemented but need testing) - - Better prompt (Fixe put in order question, Fixe calculation question) -- Support math equation from image stocked in the `data-mathml` attribute - Better webstore assets diff --git a/assets/images.gif b/assets/images.gif new file mode 100644 index 0000000000000000000000000000000000000000..7dd9c2406ee5493c539b47a9f4cc520dd93d4197 GIT binary patch literal 219082 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 emsEQ8PR^_WZoaOp#*W_3&K@Rrue!Madocument.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={url:null,system:{role:s.SYSTEM,content:c},history:[]};function u(e,t,o){return n(this,void 0,void 0,(function*(){const n=t.querySelectorAll("img");if(!e.includeImages||!function(e){const n=e.match(/gpt-(\d+)/);return!!(null==n?void 0:n[1])&&Number(n[1])>=4}(e.model)||0===n.length)return o;let r=[];const i=Array.from(n).map((e=>{return n=e,new Promise(((e,t)=>{const o=document.createElement("canvas"),r=o.getContext("2d");if(!r)return void e(null);const i=new Image;i.crossOrigin="Anonymous",i.onload=()=>{o.width=i.width,o.height=i.height,r.drawImage(i,0,0);const n=o.toDataURL("image/png");e(n)},i.onerror=e=>{t(e)},i.src=n.src}));var n})),s=(yield Promise.all(i)).filter((e=>null!==e));for(const e of s)r.push({type:l.IMAGE,content:e});return r.length>0?r.push({type:l.TEXT,content:o}):r=o,r}))}function f(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function d(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function m(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function p(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function h(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function g(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function v(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function y(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function w(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+f(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),l=yield function(e,t,o){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&a.url===n||(a.url=n,a.history=[]);const r=new AbortController,l=setTimeout((()=>r.abort()),15e3),c=yield u(e,t,o),f={role:s.USER,content:c},d=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?r.signal:null,body:JSON.stringify({model:e.model,messages:[a.system,...a.history,f],temperature:.8,top_p:1,presence_penalty:1,stop:null})});clearTimeout(l);const m=(yield d.json()).choices[0].message.content;return e.history&&(a.history.push(f),a.history.push({role:s.ASSISTANT,content:m})),{question:o,response:m,normalizedResponse:i(m)}}))}(e.config,e.questionElement,t).catch((e=>({error:e}))),c="object"==typeof l&&"error"in l;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||c?"pointer":"initial"),c)console.error(l.error);else switch(e.config.logs&&(r.question(t),r.response(l)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),d(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:l,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:l,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[m,y,p,v,h,g];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;d(e.config,e.gptAnswer)}({config:e.config,gptAnswer:l,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const A=[],E=[];function S(e){const n=E.findIndex((n=>n.element===e));if(-1!==n){const e=E.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function x(n){if(E.length>0){for(const e of E)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(E.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=w.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>S(o)});E.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){A.push(n.key),A.length>e.code.length&&A.shift(),A.join("")===e.code&&(A.length=0,x(e))}))}(n):x(n)}))})); +!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}function s(e){const n=e.match(/gpt-(\d+)/);return!!(null==n?void 0:n[1])&&Number(n[1])>=4}var l,c;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(l||(l={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(c||(c={}));const a="\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),u={url:null,system:{role:l.SYSTEM,content:a},history:[]};function f(e,t,o){return n(this,void 0,void 0,(function*(){const n=t.querySelectorAll("img");if(e.includeImages&&s(e.model)&&0===n.length)return o;let r=[];const i=Array.from(n).map((e=>{return n=e,new Promise(((e,t)=>{const o=document.createElement("canvas"),r=o.getContext("2d");if(!r)return void e(null);const i=new Image;i.crossOrigin="Anonymous",i.onload=()=>{o.width=i.width,o.height=i.height,r.drawImage(i,0,0);const n=o.toDataURL("image/png");e(n)},i.onerror=e=>{t(e)},i.src=n.src}));var n})),l=(yield Promise.all(i)).filter((e=>null!==e));for(const e of l)r.push({type:c.IMAGE,image_url:{url:e}});return r.length>0?r.push({type:c.TEXT,text:o}):r=o,r}))}function d(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function m(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function p(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function h(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function g(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function v(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function y(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function w(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function A(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+d(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),c=yield function(e,t,o){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&u.url===n||(u.url=n,u.history=[]);const r=new AbortController,c=setTimeout((()=>r.abort()),15e3),a=yield f(e,t,o),d={role:l.USER,content:a},m=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?r.signal:null,body:JSON.stringify(Object.assign({model:e.model,messages:[u.system,...u.history,d],temperature:.8,top_p:1,presence_penalty:1},s(e.model)?{max_tokens:1e3}:{stop:null}))});clearTimeout(c);const p=(yield m.json()).choices[0].message.content;return e.history&&(u.history.push(d),u.history.push({role:l.ASSISTANT,content:p})),{question:o,response:p,normalizedResponse:i(p)}}))}(e.config,e.questionElement,t).catch((e=>({error:e}))),a="object"==typeof c&&"error"in c;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||a?"pointer":"initial"),a)console.error(c.error);else switch(e.config.logs&&(r.question(t),r.response(c)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),m(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:c,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:c,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[p,w,h,y,g,v];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;m(e.config,e.gptAnswer)}({config:e.config,gptAnswer:c,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const E=[],x=[];function S(e){const n=x.findIndex((n=>n.element===e));if(-1!==n){const e=x.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function q(n){if(x.length>0){for(const e of x)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(x.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=A.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>S(o)});x.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){E.push(n.key),E.length>e.code.length&&E.shift(),E.join("")===e.code&&(E.length=0,q(e))}))}(n):q(n)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index 1e7abaf..9fd19cf 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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/core/get-response.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport imageToBase64 from '@utils/image-to-base64';\nimport normalizeText from '@utils/normalize-text';\nimport isCurrentVersionSupportingImages from '@utils/version-support-images';\n\ntype Content =\n | string\n | Array<{\n type: CONTENT_TYPE;\n content: string;\n }>;\n\ntype History = {\n url: string | null;\n system: { role: ROLE; content: Content };\n history: { role: ROLE; content: Content }[];\n};\n\nenum ROLE {\n SYSTEM = 'system',\n USER = 'user',\n ASSISTANT = 'assistant'\n}\n\nenum CONTENT_TYPE {\n TEXT = 'text',\n IMAGE = 'image_url'\n}\n\nconst INSTRUCTION: string = `\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\n- Always reply in the format: '\\n\\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n`.trim();\n\nconst history: History = {\n url: null,\n system: {\n role: ROLE.SYSTEM,\n content: INSTRUCTION\n },\n history: []\n};\n\n/**\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\n * @param config\n */\nasync function getContent(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const imagesElements = questionElement.querySelectorAll('img');\n\n if (\n !config.includeImages ||\n !isCurrentVersionSupportingImages(config.model) ||\n imagesElements.length === 0\n ) {\n return question;\n }\n\n let content: Content = [];\n\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\n const results = await Promise.all(base64Images);\n const filteredResults = results.filter(value => value !== null) as string[];\n\n for (const result of filteredResults) {\n content.push({\n type: CONTENT_TYPE.IMAGE,\n content: result\n });\n }\n\n if (content.length > 0) {\n content.push({\n type: CONTENT_TYPE.TEXT,\n content: question\n });\n } else {\n content = question;\n }\n\n return content;\n}\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const URL = location.hostname + location.pathname;\n\n // We reset the history when we enter a new moodle quiz or when it's desactivate\n if (!config.history || history.url !== URL) {\n history.url = URL;\n history.history = [];\n }\n\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 15 * 1000);\n\n const content = await getContent(config, questionElement, question);\n const message = { role: ROLE.USER, content };\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: [history.system, ...history.history, message],\n temperature: 0.8,\n top_p: 1.0,\n presence_penalty: 1.0,\n stop: null\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Register the conversation\n if (config.history) {\n history.history.push(message);\n history.history.push({ role: ROLE.ASSISTANT, content: response });\n }\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","/**\r\n * Check if the current ChatGPT version support image sending\r\n * @param version\r\n * @returns\r\n */\r\nfunction isCurrentVersionSupportingImages(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isCurrentVersionSupportingImages;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n resolve(null);\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png');\r\n resolve(base64);\r\n };\r\n img.onerror = error => {\r\n reject(error);\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","history","url","system","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isCurrentVersionSupportingImages","model","base64Images","Array","from","map","imgEl","imageToBase64","imageElement","canvas","createElement","ctx","getContext","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","error","src","filteredResults","all","filter","type","IMAGE","TEXT","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","_b","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","messages","temperature","top_p","presence_penalty","stop","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/utils/version-support-images.ts","../src/core/get-response.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport imageToBase64 from '@utils/image-to-base64';\nimport normalizeText from '@utils/normalize-text';\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\n\ntype Content =\n | string\n | Array<\n | {\n type: CONTENT_TYPE.TEXT;\n text: string;\n }\n | {\n type: CONTENT_TYPE.IMAGE;\n image_url: { url: string };\n }\n >;\n\ntype History = {\n url: string | null;\n system: { role: ROLE; content: Content };\n history: { role: ROLE; content: Content }[];\n};\n\nenum ROLE {\n SYSTEM = 'system',\n USER = 'user',\n ASSISTANT = 'assistant'\n}\n\nenum CONTENT_TYPE {\n TEXT = 'text',\n IMAGE = 'image_url'\n}\n\nconst INSTRUCTION: string = `\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\n- Always reply in the format: '\\n\\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n`.trim();\n\nconst history: History = {\n url: null,\n system: {\n role: ROLE.SYSTEM,\n content: INSTRUCTION\n },\n history: []\n};\n\n/**\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\n * @param config\n */\nasync function getContent(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const imagesElements = questionElement.querySelectorAll('img');\n\n if (\n config.includeImages &&\n isGPTModelGreaterOrEqualTo4(config.model) &&\n imagesElements.length === 0\n ) {\n return question;\n }\n\n let content: Content = [];\n\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\n const results = await Promise.all(base64Images);\n const filteredResults = results.filter(value => value !== null) as string[];\n\n for (const result of filteredResults) {\n content.push({\n type: CONTENT_TYPE.IMAGE,\n image_url: { url: result }\n });\n }\n\n if (content.length > 0) {\n content.push({\n type: CONTENT_TYPE.TEXT,\n text: question\n });\n } else {\n content = question;\n }\n\n return content;\n}\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const URL = location.hostname + location.pathname;\n\n // We reset the history when we enter a new moodle quiz or when it's desactivate\n if (!config.history || history.url !== URL) {\n history.url = URL;\n history.history = [];\n }\n\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 15 * 1000);\n\n const content = await getContent(config, questionElement, question);\n const message = { role: ROLE.USER, content };\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: [history.system, ...history.history, message],\n temperature: 0.8,\n top_p: 1.0,\n presence_penalty: 1.0,\n ...(isGPTModelGreaterOrEqualTo4(config.model) ? { max_tokens: 1000 } : { stop: null }) // look like that on 3.5 we can say stop do null but not on gpt >= 4\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Register the conversation\n if (config.history) {\n history.history.push(message);\n history.history.push({ role: ROLE.ASSISTANT, content: response });\n }\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n resolve(null);\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png');\r\n resolve(base64);\r\n };\r\n img.onerror = error => {\r\n reject(error);\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","isGPTModelGreaterOrEqualTo4","version","versionNumber","match","Number","ROLE","CONTENT_TYPE","INSTRUCTION","history","url","system","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","model","base64Images","Array","from","map","imgEl","imageToBase64","imageElement","canvas","createElement","ctx","getContext","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","error","src","filteredResults","all","filter","type","IMAGE","image_url","TEXT","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","_b","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","Object","assign","messages","temperature","top_p","presence_penalty","max_tokens","stop","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file diff --git a/extension/popup/js/gptVersion.js b/extension/popup/js/gptVersion.js index cae27f1..00b1488 100644 --- a/extension/popup/js/gptVersion.js +++ b/extension/popup/js/gptVersion.js @@ -3,15 +3,20 @@ const modelInput = document.querySelector('#model'); const imagesIntegrationLine = document.querySelector('#includeImages-line'); -// Check if the gpt version is at least 4 to show the option 'Include images' -modelInput.addEventListener('input', function () { +/** + * Check if the gpt version is at least 4 to show the option 'Include images' + */ +function checkCanIncludeImages() { const version = modelInput.value; if (isCurrentVersionSupportingImages(version)) { imagesIntegrationLine.style.display = 'flex'; } else { imagesIntegrationLine.style.display = 'none'; } -}); +} + +checkCanIncludeImages(); +modelInput.addEventListener('input', checkCanIncludeImages); /** * Get the last ChatGPT version diff --git a/src/core/get-response.ts b/src/core/get-response.ts index 2828a9e..5b9fb63 100644 --- a/src/core/get-response.ts +++ b/src/core/get-response.ts @@ -2,14 +2,20 @@ import type Config from '@typing/config'; import type GPTAnswer from '@typing/gptAnswer'; import imageToBase64 from '@utils/image-to-base64'; import normalizeText from '@utils/normalize-text'; -import isCurrentVersionSupportingImages from '@utils/version-support-images'; +import isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images'; type Content = | string - | Array<{ - type: CONTENT_TYPE; - content: string; - }>; + | Array< + | { + type: CONTENT_TYPE.TEXT; + text: string; + } + | { + type: CONTENT_TYPE.IMAGE; + image_url: { url: string }; + } + >; type History = { url: string | null; @@ -63,8 +69,8 @@ async function getContent( const imagesElements = questionElement.querySelectorAll('img'); if ( - !config.includeImages || - !isCurrentVersionSupportingImages(config.model) || + config.includeImages && + isGPTModelGreaterOrEqualTo4(config.model) && imagesElements.length === 0 ) { return question; @@ -79,14 +85,14 @@ async function getContent( for (const result of filteredResults) { content.push({ type: CONTENT_TYPE.IMAGE, - content: result + image_url: { url: result } }); } if (content.length > 0) { content.push({ type: CONTENT_TYPE.TEXT, - content: question + text: question }); } else { content = question; @@ -133,7 +139,7 @@ async function getChatGPTResponse( temperature: 0.8, top_p: 1.0, presence_penalty: 1.0, - stop: null + ...(isGPTModelGreaterOrEqualTo4(config.model) ? { max_tokens: 1000 } : { stop: null }) // look like that on 3.5 we can say stop do null but not on gpt >= 4 }) }); diff --git a/src/utils/version-support-images.ts b/src/utils/version-support-images.ts index 103cb69..98f1d0a 100644 --- a/src/utils/version-support-images.ts +++ b/src/utils/version-support-images.ts @@ -1,9 +1,9 @@ /** - * Check if the current ChatGPT version support image sending + * Check if the current ChatGPT version is greater or equal to 4 * @param version * @returns */ -function isCurrentVersionSupportingImages(version: string): boolean { +function isGPTModelGreaterOrEqualTo4(version: string): boolean { const versionNumber = version.match(/gpt-(\d+)/); if (!versionNumber?.[1]) { return false; @@ -11,4 +11,4 @@ function isCurrentVersionSupportingImages(version: string): boolean { return Number(versionNumber[1]) >= 4; } -export default isCurrentVersionSupportingImages; +export default isGPTModelGreaterOrEqualTo4; diff --git a/test/fake-moodle/assets/cat1.jpg b/test/fake-moodle/assets/cat1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..70d140c43ad87f00cb74edef8628a993a72d14ed GIT binary patch literal 4666 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 b6XmZB0}1hRDs46;Wy*4T;n?KVtGWLHaYt$X literal 0 HcmV?d00001 diff --git a/test/fake-moodle/assets/cat2.jpg b/test/fake-moodle/assets/cat2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e771b425f36ff33d64340cabdb8f51af1ea1ec7b GIT binary patch literal 22523 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 TxYecbNmZ-3dF5$|zmxw5AF%G= literal 0 HcmV?d00001 diff --git a/test/fake-moodle/css/style.css b/test/fake-moodle/css/style.css index 3fe7434..29ded4f 100644 --- a/test/fake-moodle/css/style.css +++ b/test/fake-moodle/css/style.css @@ -65,3 +65,7 @@ textarea { white-space: pre-wrap; overflow-y: auto; } + +img { + height: 5rem; +} diff --git a/test/fake-moodle/index.html b/test/fake-moodle/index.html index 93abd99..3e2a34c 100644 --- a/test/fake-moodle/index.html +++ b/test/fake-moodle/index.html @@ -269,7 +269,7 @@

hA2&KcW7(BL)udt07O>ed@5(Gxm4|(5n$jSQ>;3SINal(M8*~q=#Fm) za2jmJ-v&=T;(^{yIQp;QN2|V1bxBn)d@JQK%(73Id_DzwSkes!WIct&Z&U*0kE^%= zd3k6)5~0!x@WZB0RN9D2rry0_AkXw)twS+hzo!Q}X;z6GNfI$WN;~jA#1AW9LK{Lv!M{ z^|doIKl{p5QR=4B?ztu0b_ofdWNojcx+jlIQzZNj=EG}n9Q$rv*q{vyvQ9eQr4Z*J zv@(D`7BNb@Cmk5Z5tFj*9OJ$Ix*g$_5zT=YS~mTaKSvZ40kYX{1AJR*af&>I=0;dG zkv-qFL`?_9IHidcQ8@B-L+wLP-cNj7o2R}d12FoH2fpJU!U|&B>qW}di*Z$E&S;!tKP02LGyyeL1R#wsq8vlu=`CU%^sX?ayXLfHgcqrMqe{Y3oYj|9Db?PGV#n4UX5nS{o)UpdK%Ti>r@1&H?f;x793*tw3U&$p(jm zTmx_i??~0COT`95)WtHLQQFcM?>|AB4D?}j#{+$f+5KIq_lyoCq9_bwI(o>iUl&%=Xs245mVHJ)dU2`RumIHpCFZc02?&Z4ZiF56X6J7luW7(B>KB5`zCF}XFQC)_ygCrS6(9XCU%I8_T|8e z<+9MHT#US{3Q=}WsUNZApC~O0cf@c~xI?Id9edf&n0Emb!TUWIt|t-dvqydI{Co+- zJV60C!NWG4C%U2x^dPm%vw?HDl?fcsT@gHf_j2@}?z4#eexGb~9aoa1o7mN!HeRf? zv^{P6&?2<3ZuoCB-lt>bf#AeTx-u9#20gLidmLQWcVjSb-$aOz`EVNSLxe~nW)PO8 zD-+3}g4(3JF@($3Xj|>4(TTcbNXqq`Lm7==e547fUC!}?O^Jx4yd+f^7{@gpSm{Saj!(skG9#-)U z50Y*UmFWdG@qIsV`-VmI;*j|#a4m%xEP?`hh9*L;G50Bku0ULQfrbGTLhMfXUULxN zf<2~9CP$89sej`u!_JrbtpF`FoHD^JZ#;~F;B}J2a1ABD9yH-GqO$RZg*eqr1~)hU zVSAHeu`Q1@3U|vrM?^jP{l1aI!AQ!fGYm_GnSG(Gi(&ovml6v7Au9`^2f1c)FYs$x zcVYdF`bhH8m^jfsh$t9|i)kmQTv_C}tqtL28VmK5cQ&y-p1HEQ;l*pnqB2}>-jCQW zH2JND`-$9GhI(c%0q@RD6j6o3f^Y?r2M4q_FXT> z;mQ4Eq8EL)y;%YdXJuysZYFN1ZyqIpJ|&9+Rso}kd#x3G+jbXW=&P>w zc*psyvE6?oo>nbo23>|M*glbCg&3fVO%3!+YY7T>@5G%C|EKG~Td?{E<`T9daR|}o zh^f;!IAg``u=(mDBfQC>qy2<1W1i;S{OP@w9KCc;a#b+U4Tp^QIw%$j&jhepw5*Is$XX+nG9ahBr%hrCGU~k?jN$q^4fBiITaA zJ;gUv5p=9uXA`#sU$98hPxctrnvW?1Imsa(_{c1la`jsF4ESGLX%HjgU@W_)Fj5UU z2)Nx=Rt3dAx?ZHNsR_ zm`&rSrCOv|-Ee~{8bQz*-P2pM2;>xAS_-1o;WGb0@l+QbXX$}8tu&yM%x#^tfSpQE zoxQ^G(`|tX2LRO8iYv=+{!2a$@Uq0|P=gojDgPsY6kb|a+}9U!wN!Bb5 zJv0CgMeJ%D9O|RrY8;2bTLtp`nJ)q455?f`xNHnYW`lv{uUsEz$PNW6Ksv2bi6noJ13t9CJ!<3d8RN?KYr>1#34G-l@-t27 z4(dm5DzV&>sE-kpg#L&}MY&5BHMeuDLM!(`PaXKK>v!Kx7=NK+D8(?YXR*;U60{bA ztOU%i^oL2odwpniW`Gz!Xpn(>OVsxmcFrXl|Yp)|cQ literal 10441 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 Date: Wed, 28 Feb 2024 20:17:05 -0500 Subject: [PATCH 27/87] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab221b5..0239f48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # CHANGELOG -## v1.0.4 +## v1.1.0 - `code` is not required anymore - Issue [#9](https://github.com/yoannchb-pro/MoodleGPT/issues/9) resolved From 7f070c422276e013a6024d180d44d8e9d55cff4c Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 20:17:16 -0500 Subject: [PATCH 28/87] Update CONTRIBUTE.md --- CONTRIBUTE.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md index c43a67b..115f299 100644 --- a/CONTRIBUTE.md +++ b/CONTRIBUTE.md @@ -1,8 +1,23 @@ # CONTRIBUTE -This file is not completed yet and still under devlopement +When contributing to this repository, please first discuss the change you wish to make via issue, +email, or any other method with the owners of this repository before making a change. -## Steps to work on the project +Please note we have a code of conduct, please follow it in all your interactions with the project. + +## Code of Conduct + +See the code of conduct [here](./CODE_OF_CONDUCT.md) + +## Pull Request Process + +1. Update the README.md with details of changes to the extension. +2. Increase the version numbers in any examples files and the README.md to the new version that this + Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). +3. You may merge the Pull Request in once you have the sign-off of two other developers, or if you + do not have permission to do that, you may request the second reviewer to merge it for you. + +## Setup the project ``` node: 18.13.0 @@ -15,13 +30,13 @@ npm: 8.19.2 $ npm install ``` -## 2. Setup Git hooks +### 2. Setup Git hooks ``` $ git config --local core.hooksPath .githooks/ ``` -## 3. Build project +### 3. Build project ``` $ npm run build From 6a19f476a047601b7db898cf2366f4076388a30e Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 28 Feb 2024 20:17:26 -0500 Subject: [PATCH 29/87] Update README.md --- README.md | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 662f5ef..200235d 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" >Mortarboard icons created by itim2101 - Flaticon

- +

@@ -281,5 +281,20 @@

+ + +
+

+ Warning ! Only work with gpt-4 and if "includes images" is activate +

+
+

Tell me what you see on thoses images

+ + +
+
+
+
+
From 2f0126b1314e24f1924e80b9bcf6fbc4cea7af97 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 29 Feb 2024 14:52:46 -0500 Subject: [PATCH 44/87] linting and formtage on build --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 19151f2..ae6e778 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.1.0", "description": "This extension allows you to hide CHAT-GPT in a Moodle quiz.", "scripts": { - "build": "rollup -c", + "build": "npm run prettier && npm run lint && rollup -c", "lint": "eslint . --ext .ts", "prettier": "prettier --write ." }, From 24441e4040728c8446cd4f44c55c7bdbc5f23dfa Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 29 Feb 2024 14:52:58 -0500 Subject: [PATCH 45/87] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0239f48..5760213 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ - Better algorithm to find the correct answer (levenshtein distance) - Better ChatGPT prompt - Added `history` to the options/configuration +- Added `include images` to the option/configuration +- `gpt-4` support ## v1.0.3 From 08674b5b830d1ea3130d7bb51926905fd73a4516 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 29 Feb 2024 14:53:04 -0500 Subject: [PATCH 46/87] Update TODO.md --- TODO.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TODO.md b/TODO.md index 8c87e9b..855edfc 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,7 @@ # TODO - Historic for questions (implemented but need testing) +- Fixe include images button display - Better prompt (Fixe put in order question, Fixe calculation question) - Better webstore assets +- Do some tests From e300f64bf645de2e40c4d914addfc95953e363bd Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 29 Feb 2024 14:53:10 -0500 Subject: [PATCH 47/87] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5fe2fd7..1edcf47 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Go to "Manage my extensions" on your browser, then click on "Load unpa
![Injected](./assets/title-injected.png) - Console logs: show logs into the console for the question, chatgpt answer and which response has been chosen.
Logs -- Request timeout: if the request is too long it will be abort after 15seconds. +- Request timeout: if the request is too long it will be abort after 20 seconds. - 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.
![Typing](./assets/typing.gif) - Mouseover effect: you will need to hover (or click for select) the question response to complete it automaticaly. From 3782dc937b9bb1af90bae2a62152a4bae1929bb0 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 29 Feb 2024 14:53:24 -0500 Subject: [PATCH 48/87] updated openai api parameters --- extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- src/core/get-response.ts | 15 ++++++++------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index fe09862..16dd9a6 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,2 +1,2 @@ -!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}function s(e){const n=e.match(/gpt-(\d+)/);return!!(null==n?void 0:n[1])&&Number(n[1])>=4}var l,c;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(l||(l={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(c||(c={}));const a="\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),u={url:null,system:{role:l.SYSTEM,content:a},history:[]};function f(e,t,o){return n(this,void 0,void 0,(function*(){const n=t.querySelectorAll("img");if(e.includeImages&&s(e.model)&&0===n.length)return o;let r=[];const i=Array.from(n).map((e=>{return n=e,new Promise(((e,t)=>{const o=document.createElement("canvas"),r=o.getContext("2d");if(!r)return void e(null);const i=new Image;i.crossOrigin="Anonymous",i.onload=()=>{o.width=i.width,o.height=i.height,r.drawImage(i,0,0);const n=o.toDataURL("image/png");e(n)},i.onerror=e=>{t(e)},i.src=n.src}));var n})),l=(yield Promise.all(i)).filter((e=>null!==e));for(const e of l)r.push({type:c.IMAGE,image_url:{url:e}});return r.length>0?r.push({type:c.TEXT,text:o}):r=o,r}))}function d(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function m(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function p(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function h(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function g(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function v(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function y(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function w(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function A(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+d(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),c=yield function(e,t,o){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&u.url===n||(u.url=n,u.history=[]);const r=new AbortController,c=setTimeout((()=>r.abort()),15e3),a=yield f(e,t,o),d={role:l.USER,content:a},m=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?r.signal:null,body:JSON.stringify(Object.assign({model:e.model,messages:[u.system,...u.history,d],temperature:.8,top_p:1,presence_penalty:1},s(e.model)?{max_tokens:1e3}:{stop:null}))});clearTimeout(c);const p=(yield m.json()).choices[0].message.content;return e.history&&(u.history.push(d),u.history.push({role:l.ASSISTANT,content:p})),{question:o,response:p,normalizedResponse:i(p)}}))}(e.config,e.questionElement,t).catch((e=>({error:e}))),a="object"==typeof c&&"error"in c;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||a?"pointer":"initial"),a)console.error(c.error);else switch(e.config.logs&&(r.question(t),r.response(c)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),m(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:c,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:c,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[p,w,h,y,g,v];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;m(e.config,e.gptAnswer)}({config:e.config,gptAnswer:c,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const E=[],x=[];function S(e){const n=x.findIndex((n=>n.element===e));if(-1!==n){const e=x.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function q(n){if(x.length>0){for(const e of x)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(x.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=A.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>S(o)});x.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){E.push(n.key),E.length>e.code.length&&E.shift(),E.join("")===e.code&&(E.length=0,q(e))}))}(n):q(n)}))})); +!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: explenation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={url:null,system:{role:s.SYSTEM,content:c},history:[]};function u(e,t,o){return n(this,void 0,void 0,(function*(){const n=t.querySelectorAll("img");if(e.includeImages&&function(e){const n=e.match(/gpt-(\d+)/);return!!(null==n?void 0:n[1])&&Number(n[1])>=4}(e.model)&&0===n.length)return o;let r=[];const i=Array.from(n).map((e=>{return n=e,new Promise(((e,t)=>{const o=document.createElement("canvas"),r=o.getContext("2d");if(!r)return void e(null);const i=new Image;i.crossOrigin="Anonymous",i.onload=()=>{o.width=i.width,o.height=i.height,r.drawImage(i,0,0);const n=o.toDataURL("image/png");e(n)},i.onerror=e=>{t(e)},i.src=n.src}));var n})),s=(yield Promise.all(i)).filter((e=>null!==e));for(const e of s)r.push({type:l.IMAGE,image_url:{url:e}});return r.length>0?r.push({type:l.TEXT,text:o}):r=o,r}))}function f(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function m(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function d(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function p(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function h(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function g(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function v(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function y(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function w(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+f(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),l=yield function(e,t,o){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&a.url===n||(a.url=n,a.history=[]);const r=new AbortController,l=setTimeout((()=>r.abort()),2e4),c=yield u(e,t,o),f={role:s.USER,content:c},m=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?r.signal:null,body:JSON.stringify({model:e.model,messages:[a.system,...a.history,f],temperature:.1,top_p:1,presence_penalty:0,max_tokens:2e3})});clearTimeout(l);const d=(yield m.json()).choices[0].message.content;return e.history&&(a.history.push(f),a.history.push({role:s.ASSISTANT,content:d})),{question:o,response:d,normalizedResponse:i(d)}}))}(e.config,e.questionElement,t).catch((e=>({error:e}))),c="object"==typeof l&&"error"in l;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||c?"pointer":"initial"),c)console.error(l.error);else switch(e.config.logs&&(r.question(t),r.response(l)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),m(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:l,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:l,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[d,y,p,v,h,g];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;m(e.config,e.gptAnswer)}({config:e.config,gptAnswer:l,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const A=[],E=[];function x(e){const n=E.findIndex((n=>n.element===e));if(-1!==n){const e=E.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function S(n){if(E.length>0){for(const e of E)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(E.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=w.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>x(o)});E.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){A.push(n.key),A.length>e.code.length&&A.shift(),A.join("")===e.code&&(A.length=0,S(e))}))}(n):S(n)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index 9fd19cf..34cea61 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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/utils/version-support-images.ts","../src/core/get-response.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport imageToBase64 from '@utils/image-to-base64';\nimport normalizeText from '@utils/normalize-text';\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\n\ntype Content =\n | string\n | Array<\n | {\n type: CONTENT_TYPE.TEXT;\n text: string;\n }\n | {\n type: CONTENT_TYPE.IMAGE;\n image_url: { url: string };\n }\n >;\n\ntype History = {\n url: string | null;\n system: { role: ROLE; content: Content };\n history: { role: ROLE; content: Content }[];\n};\n\nenum ROLE {\n SYSTEM = 'system',\n USER = 'user',\n ASSISTANT = 'assistant'\n}\n\nenum CONTENT_TYPE {\n TEXT = 'text',\n IMAGE = 'image_url'\n}\n\nconst INSTRUCTION: string = `\nAct as a quiz solver for the best notation with the following rules:\n- When asked for the result of an equation, provide only the result without any other information and skip the other rules.\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation.\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\n- Always reply in the format: '\\n\\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n`.trim();\n\nconst history: History = {\n url: null,\n system: {\n role: ROLE.SYSTEM,\n content: INSTRUCTION\n },\n history: []\n};\n\n/**\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\n * @param config\n */\nasync function getContent(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const imagesElements = questionElement.querySelectorAll('img');\n\n if (\n config.includeImages &&\n isGPTModelGreaterOrEqualTo4(config.model) &&\n imagesElements.length === 0\n ) {\n return question;\n }\n\n let content: Content = [];\n\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\n const results = await Promise.all(base64Images);\n const filteredResults = results.filter(value => value !== null) as string[];\n\n for (const result of filteredResults) {\n content.push({\n type: CONTENT_TYPE.IMAGE,\n image_url: { url: result }\n });\n }\n\n if (content.length > 0) {\n content.push({\n type: CONTENT_TYPE.TEXT,\n text: question\n });\n } else {\n content = question;\n }\n\n return content;\n}\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const URL = location.hostname + location.pathname;\n\n // We reset the history when we enter a new moodle quiz or when it's desactivate\n if (!config.history || history.url !== URL) {\n history.url = URL;\n history.history = [];\n }\n\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 15 * 1000);\n\n const content = await getContent(config, questionElement, question);\n const message = { role: ROLE.USER, content };\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: [history.system, ...history.history, message],\n temperature: 0.8,\n top_p: 1.0,\n presence_penalty: 1.0,\n ...(isGPTModelGreaterOrEqualTo4(config.model) ? { max_tokens: 1000 } : { stop: null }) // look like that on 3.5 we can say stop do null but not on gpt >= 4\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Register the conversation\n if (config.history) {\n history.history.push(message);\n history.history.push({ role: ROLE.ASSISTANT, content: response });\n }\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n resolve(null);\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png');\r\n resolve(base64);\r\n };\r\n img.onerror = error => {\r\n reject(error);\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","isGPTModelGreaterOrEqualTo4","version","versionNumber","match","Number","ROLE","CONTENT_TYPE","INSTRUCTION","history","url","system","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","model","base64Images","Array","from","map","imgEl","imageToBase64","imageElement","canvas","createElement","ctx","getContext","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","error","src","filteredResults","all","filter","type","IMAGE","image_url","TEXT","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","_b","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","Object","assign","messages","temperature","top_p","presence_penalty","max_tokens","stop","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/core/get-response.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport imageToBase64 from '@utils/image-to-base64';\nimport normalizeText from '@utils/normalize-text';\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\n\ntype Content =\n | string\n | Array<\n | {\n type: CONTENT_TYPE.TEXT;\n text: string;\n }\n | {\n type: CONTENT_TYPE.IMAGE;\n image_url: { url: string };\n }\n >;\n\ntype History = {\n url: string | null;\n system: { role: ROLE; content: Content };\n history: { role: ROLE; content: Content }[];\n};\n\nenum ROLE {\n SYSTEM = 'system',\n USER = 'user',\n ASSISTANT = 'assistant'\n}\n\nenum CONTENT_TYPE {\n TEXT = 'text',\n IMAGE = 'image_url'\n}\n\nconst INSTRUCTION: string = `\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: explenation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\n- Always reply in the format: '\\n\\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n`.trim();\n\nconst history: History = {\n url: null,\n system: {\n role: ROLE.SYSTEM,\n content: INSTRUCTION\n },\n history: []\n};\n\n/**\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\n * @param config\n */\nasync function getContent(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const imagesElements = questionElement.querySelectorAll('img');\n\n if (\n config.includeImages &&\n isGPTModelGreaterOrEqualTo4(config.model) &&\n imagesElements.length === 0\n ) {\n return question;\n }\n\n let content: Content = [];\n\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\n const results = await Promise.all(base64Images);\n const filteredResults = results.filter(value => value !== null) as string[];\n\n for (const result of filteredResults) {\n content.push({\n type: CONTENT_TYPE.IMAGE,\n image_url: { url: result }\n });\n }\n\n if (content.length > 0) {\n content.push({\n type: CONTENT_TYPE.TEXT,\n text: question\n });\n } else {\n content = question;\n }\n\n return content;\n}\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const URL = location.hostname + location.pathname;\n\n // We reset the history when we enter a new moodle quiz or when it's desactivate\n if (!config.history || history.url !== URL) {\n history.url = URL;\n history.history = [];\n }\n\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n const content = await getContent(config, questionElement, question);\n const message = { role: ROLE.USER, content };\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: [history.system, ...history.history, message],\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 1, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Register the conversation\n if (config.history) {\n history.history.push(message);\n history.history.push({ role: ROLE.ASSISTANT, content: response });\n }\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n resolve(null);\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png');\r\n resolve(base64);\r\n };\r\n img.onerror = error => {\r\n reject(error);\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","history","url","system","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","base64Images","Array","from","map","imgEl","imageToBase64","imageElement","canvas","createElement","ctx","getContext","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","error","src","filteredResults","all","filter","type","IMAGE","image_url","TEXT","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","_b","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","messages","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file diff --git a/src/core/get-response.ts b/src/core/get-response.ts index 5b9fb63..b5dc9a6 100644 --- a/src/core/get-response.ts +++ b/src/core/get-response.ts @@ -36,8 +36,8 @@ enum CONTENT_TYPE { const INSTRUCTION: string = ` Act as a quiz solver for the best notation with the following rules: -- When asked for the result of an equation, provide only the result without any other information and skip the other rules. -- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. +- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. + But for the calculation provide this format 'result: explenation: ' - For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...' - Always reply in the format: '\n\n...'. - Retain only the correct answer(s). @@ -121,7 +121,7 @@ async function getChatGPTResponse( } const controller = new AbortController(); - const timeoutControler = setTimeout(() => controller.abort(), 15 * 1000); + const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000); const content = await getContent(config, questionElement, question); const message = { role: ROLE.USER, content }; @@ -136,10 +136,11 @@ async function getChatGPTResponse( body: JSON.stringify({ model: config.model, messages: [history.system, ...history.history, message], - temperature: 0.8, - top_p: 1.0, - presence_penalty: 1.0, - ...(isGPTModelGreaterOrEqualTo4(config.model) ? { max_tokens: 1000 } : { stop: null }) // look like that on 3.5 we can say stop do null but not on gpt >= 4 + + temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity. + top_p: 1, // Determines the diversity of the generated responses + presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text. + max_tokens: 2000 // Maximum length of the response }) }); From 5e5544c28a3da91362eb889dd4d6d4ddc70c8796 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:11:14 -0500 Subject: [PATCH 49/87] stop parameter --- extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- src/core/get-response.ts | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index 16dd9a6..0b3c5ee 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,2 +1,2 @@ -!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: explenation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={url:null,system:{role:s.SYSTEM,content:c},history:[]};function u(e,t,o){return n(this,void 0,void 0,(function*(){const n=t.querySelectorAll("img");if(e.includeImages&&function(e){const n=e.match(/gpt-(\d+)/);return!!(null==n?void 0:n[1])&&Number(n[1])>=4}(e.model)&&0===n.length)return o;let r=[];const i=Array.from(n).map((e=>{return n=e,new Promise(((e,t)=>{const o=document.createElement("canvas"),r=o.getContext("2d");if(!r)return void e(null);const i=new Image;i.crossOrigin="Anonymous",i.onload=()=>{o.width=i.width,o.height=i.height,r.drawImage(i,0,0);const n=o.toDataURL("image/png");e(n)},i.onerror=e=>{t(e)},i.src=n.src}));var n})),s=(yield Promise.all(i)).filter((e=>null!==e));for(const e of s)r.push({type:l.IMAGE,image_url:{url:e}});return r.length>0?r.push({type:l.TEXT,text:o}):r=o,r}))}function f(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function m(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function d(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function p(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function h(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function g(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function v(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function y(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function w(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+f(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),l=yield function(e,t,o){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&a.url===n||(a.url=n,a.history=[]);const r=new AbortController,l=setTimeout((()=>r.abort()),2e4),c=yield u(e,t,o),f={role:s.USER,content:c},m=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?r.signal:null,body:JSON.stringify({model:e.model,messages:[a.system,...a.history,f],temperature:.1,top_p:1,presence_penalty:0,max_tokens:2e3})});clearTimeout(l);const d=(yield m.json()).choices[0].message.content;return e.history&&(a.history.push(f),a.history.push({role:s.ASSISTANT,content:d})),{question:o,response:d,normalizedResponse:i(d)}}))}(e.config,e.questionElement,t).catch((e=>({error:e}))),c="object"==typeof l&&"error"in l;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||c?"pointer":"initial"),c)console.error(l.error);else switch(e.config.logs&&(r.question(t),r.response(l)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),m(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:l,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:l,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[d,y,p,v,h,g];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;m(e.config,e.gptAnswer)}({config:e.config,gptAnswer:l,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const A=[],E=[];function x(e){const n=E.findIndex((n=>n.element===e));if(-1!==n){const e=E.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function S(n){if(E.length>0){for(const e of E)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(E.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=w.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>x(o)});E.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){A.push(n.key),A.length>e.code.length&&A.shift(),A.join("")===e.code&&(A.length=0,S(e))}))}(n):S(n)}))})); +!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: explenation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={url:null,system:{role:s.SYSTEM,content:c},history:[]};function u(e,t,o){return n(this,void 0,void 0,(function*(){const n=t.querySelectorAll("img");if(e.includeImages&&function(e){const n=e.match(/gpt-(\d+)/);return!!(null==n?void 0:n[1])&&Number(n[1])>=4}(e.model)&&0===n.length)return o;let r=[];const i=Array.from(n).map((e=>{return n=e,new Promise(((e,t)=>{const o=document.createElement("canvas"),r=o.getContext("2d");if(!r)return void e(null);const i=new Image;i.crossOrigin="Anonymous",i.onload=()=>{o.width=i.width,o.height=i.height,r.drawImage(i,0,0);const n=o.toDataURL("image/png");e(n)},i.onerror=e=>{t(e)},i.src=n.src}));var n})),s=(yield Promise.all(i)).filter((e=>null!==e));for(const e of s)r.push({type:l.IMAGE,image_url:{url:e}});return r.length>0?r.push({type:l.TEXT,text:o}):r=o,r}))}function f(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function m(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function d(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function p(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function h(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function g(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function v(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function y(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function w(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+f(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),l=yield function(e,t,o){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&a.url===n||(a.url=n,a.history=[]);const r=new AbortController,l=setTimeout((()=>r.abort()),2e4),c=yield u(e,t,o),f={role:s.USER,content:c},m=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?r.signal:null,body:JSON.stringify({model:e.model,messages:[a.system,...a.history,f],temperature:.1,top_p:1,presence_penalty:0,max_tokens:2e3,stop:[".","!","?"]})});clearTimeout(l);const d=(yield m.json()).choices[0].message.content;return e.history&&(a.history.push(f),a.history.push({role:s.ASSISTANT,content:d})),{question:o,response:d,normalizedResponse:i(d)}}))}(e.config,e.questionElement,t).catch((e=>({error:e}))),c="object"==typeof l&&"error"in l;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||c?"pointer":"initial"),c)console.error(l.error);else switch(e.config.logs&&(r.question(t),r.response(l)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),m(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:l,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:l,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[d,y,p,v,h,g];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;m(e.config,e.gptAnswer)}({config:e.config,gptAnswer:l,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const A=[],E=[];function x(e){const n=E.findIndex((n=>n.element===e));if(-1!==n){const e=E.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function S(n){if(E.length>0){for(const e of E)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(E.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=w.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>x(o)});E.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){A.push(n.key),A.length>e.code.length&&A.shift(),A.join("")===e.code&&(A.length=0,S(e))}))}(n):S(n)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index 34cea61..7edee76 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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/core/get-response.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport imageToBase64 from '@utils/image-to-base64';\nimport normalizeText from '@utils/normalize-text';\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\n\ntype Content =\n | string\n | Array<\n | {\n type: CONTENT_TYPE.TEXT;\n text: string;\n }\n | {\n type: CONTENT_TYPE.IMAGE;\n image_url: { url: string };\n }\n >;\n\ntype History = {\n url: string | null;\n system: { role: ROLE; content: Content };\n history: { role: ROLE; content: Content }[];\n};\n\nenum ROLE {\n SYSTEM = 'system',\n USER = 'user',\n ASSISTANT = 'assistant'\n}\n\nenum CONTENT_TYPE {\n TEXT = 'text',\n IMAGE = 'image_url'\n}\n\nconst INSTRUCTION: string = `\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: explenation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\n- Always reply in the format: '\\n\\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n`.trim();\n\nconst history: History = {\n url: null,\n system: {\n role: ROLE.SYSTEM,\n content: INSTRUCTION\n },\n history: []\n};\n\n/**\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\n * @param config\n */\nasync function getContent(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const imagesElements = questionElement.querySelectorAll('img');\n\n if (\n config.includeImages &&\n isGPTModelGreaterOrEqualTo4(config.model) &&\n imagesElements.length === 0\n ) {\n return question;\n }\n\n let content: Content = [];\n\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\n const results = await Promise.all(base64Images);\n const filteredResults = results.filter(value => value !== null) as string[];\n\n for (const result of filteredResults) {\n content.push({\n type: CONTENT_TYPE.IMAGE,\n image_url: { url: result }\n });\n }\n\n if (content.length > 0) {\n content.push({\n type: CONTENT_TYPE.TEXT,\n text: question\n });\n } else {\n content = question;\n }\n\n return content;\n}\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const URL = location.hostname + location.pathname;\n\n // We reset the history when we enter a new moodle quiz or when it's desactivate\n if (!config.history || history.url !== URL) {\n history.url = URL;\n history.history = [];\n }\n\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n const content = await getContent(config, questionElement, question);\n const message = { role: ROLE.USER, content };\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: [history.system, ...history.history, message],\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 1, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Register the conversation\n if (config.history) {\n history.history.push(message);\n history.history.push({ role: ROLE.ASSISTANT, content: response });\n }\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n resolve(null);\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png');\r\n resolve(base64);\r\n };\r\n img.onerror = error => {\r\n reject(error);\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","history","url","system","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","base64Images","Array","from","map","imgEl","imageToBase64","imageElement","canvas","createElement","ctx","getContext","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","error","src","filteredResults","all","filter","type","IMAGE","image_url","TEXT","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","_b","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","messages","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/core/get-response.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport imageToBase64 from '@utils/image-to-base64';\nimport normalizeText from '@utils/normalize-text';\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\n\ntype Content =\n | string\n | Array<\n | {\n type: CONTENT_TYPE.TEXT;\n text: string;\n }\n | {\n type: CONTENT_TYPE.IMAGE;\n image_url: { url: string };\n }\n >;\n\ntype History = {\n url: string | null;\n system: { role: ROLE; content: Content };\n history: { role: ROLE; content: Content }[];\n};\n\nenum ROLE {\n SYSTEM = 'system',\n USER = 'user',\n ASSISTANT = 'assistant'\n}\n\nenum CONTENT_TYPE {\n TEXT = 'text',\n IMAGE = 'image_url'\n}\n\nconst INSTRUCTION: string = `\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: explenation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\n- Always reply in the format: '\\n\\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n`.trim();\n\nconst history: History = {\n url: null,\n system: {\n role: ROLE.SYSTEM,\n content: INSTRUCTION\n },\n history: []\n};\n\n/**\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\n * @param config\n */\nasync function getContent(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const imagesElements = questionElement.querySelectorAll('img');\n\n if (\n config.includeImages &&\n isGPTModelGreaterOrEqualTo4(config.model) &&\n imagesElements.length === 0\n ) {\n return question;\n }\n\n let content: Content = [];\n\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\n const results = await Promise.all(base64Images);\n const filteredResults = results.filter(value => value !== null) as string[];\n\n for (const result of filteredResults) {\n content.push({\n type: CONTENT_TYPE.IMAGE,\n image_url: { url: result }\n });\n }\n\n if (content.length > 0) {\n content.push({\n type: CONTENT_TYPE.TEXT,\n text: question\n });\n } else {\n content = question;\n }\n\n return content;\n}\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const URL = location.hostname + location.pathname;\n\n // We reset the history when we enter a new moodle quiz or when it's desactivate\n if (!config.history || history.url !== URL) {\n history.url = URL;\n history.history = [];\n }\n\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n const content = await getContent(config, questionElement, question);\n const message = { role: ROLE.USER, content };\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: [history.system, ...history.history, message],\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 1, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000, // Maximum length of the response\n stop: ['.', '!', '?'] // Stop on the ponctuation to do not cut the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Register the conversation\n if (config.history) {\n history.history.push(message);\n history.history.push({ role: ROLE.ASSISTANT, content: response });\n }\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n resolve(null);\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png');\r\n resolve(base64);\r\n };\r\n img.onerror = error => {\r\n reject(error);\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","history","url","system","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","base64Images","Array","from","map","imgEl","imageToBase64","imageElement","canvas","createElement","ctx","getContext","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","error","src","filteredResults","all","filter","type","IMAGE","image_url","TEXT","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","_b","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","messages","temperature","top_p","presence_penalty","max_tokens","stop","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file diff --git a/src/core/get-response.ts b/src/core/get-response.ts index b5dc9a6..7b1bf31 100644 --- a/src/core/get-response.ts +++ b/src/core/get-response.ts @@ -140,7 +140,8 @@ async function getChatGPTResponse( temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity. top_p: 1, // Determines the diversity of the generated responses presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text. - max_tokens: 2000 // Maximum length of the response + max_tokens: 2000, // Maximum length of the response + stop: ['.', '!', '?'] // Stop on the ponctuation to do not cut the response }) }); From c207abb1f6ca9934c325ea0230edb2085bf359ed Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:34:19 -0500 Subject: [PATCH 50/87] fixed images reading --- assets/images.gif | Bin 219082 -> 170097 bytes extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- src/core/get-response.ts | 5 ++--- src/utils/image-to-base64.ts | 11 ++++++++--- test/fake-moodle/assets/cat1.jpg | Bin 4666 -> 0 bytes test/fake-moodle/assets/cat2.jpg | Bin 22523 -> 0 bytes test/fake-moodle/index.html | 12 +++++++++--- 8 files changed, 21 insertions(+), 11 deletions(-) delete mode 100644 test/fake-moodle/assets/cat1.jpg delete mode 100644 test/fake-moodle/assets/cat2.jpg diff --git a/assets/images.gif b/assets/images.gif index 7dd9c2406ee5493c539b47a9f4cc520dd93d4197..84fc686b4d80a719ae7c64c1106ea39e6060b936 100644 GIT binary patch literal 170097 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%0ATt?$D271F=0r^7DO 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
-

Tell me what you see on thoses images

- - +

What is the race of those cats:

+ black cat + white cat
From 6e68ff470a3fd4c14b6d2d1e45c2629e3859aa4b Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 11 Mar 2024 19:25:14 -0400 Subject: [PATCH 51/87] fixed include images button --- TODO.md | 1 - extension/popup/js/gptVersion.js | 4 +++- extension/popup/js/index.js | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index 855edfc..815cb61 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,6 @@ # TODO - Historic for questions (implemented but need testing) -- Fixe include images button display - Better prompt (Fixe put in order question, Fixe calculation question) - Better webstore assets - Do some tests diff --git a/extension/popup/js/gptVersion.js b/extension/popup/js/gptVersion.js index 00b1488..917c55e 100644 --- a/extension/popup/js/gptVersion.js +++ b/extension/popup/js/gptVersion.js @@ -15,7 +15,6 @@ function checkCanIncludeImages() { } } -checkCanIncludeImages(); modelInput.addEventListener('input', checkCanIncludeImages); /** @@ -57,8 +56,11 @@ function getLastChatGPTVersion() { } }); const rep = await req.json(); + rep.data.sort((a, b) => b.id.localeCompare(a.id)); // we sort the model to get the best chatgpt version const model = rep.data.find(model => model.id.startsWith('gpt')); modelInput.value = model.id; + + checkCanIncludeImages(); } catch (err) { console.error(err); showMessage({ msg: 'Failed to fetch last ChatGPT version', error: true }); diff --git a/extension/popup/js/index.js b/extension/popup/js/index.js index f293fbf..d7c2515 100644 --- a/extension/popup/js/index.js +++ b/extension/popup/js/index.js @@ -85,4 +85,5 @@ chrome.storage.sync.get(['moodleGPT']).then(function (storage) { handleModeChange(); getLastChatGPTVersion(); + checkCanIncludeImages(); }); From 906a938e9c95a36b711019751ec9c668366c0bb3 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 11 Mar 2024 19:25:29 -0400 Subject: [PATCH 52/87] Create HELP_REQUEST.md --- .github/ISSUE_TEMPLATE/HELP_REQUEST.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/HELP_REQUEST.md diff --git a/.github/ISSUE_TEMPLATE/HELP_REQUEST.md b/.github/ISSUE_TEMPLATE/HELP_REQUEST.md new file mode 100644 index 0000000..66eddb6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/HELP_REQUEST.md @@ -0,0 +1,24 @@ +## Help Request + +**Issue Summary** + +[Summarize the issue you are facing concisely.] + +**Describe the problem** + +[Describe what is the problem] + +**Environment** + +- Operating System: [Your OS] +- Browser: [Your Browser] +- Version: [Version Number] +- Any other relevant information + +### Screenshots + +[Include any relevant screenshots if they can help illustrate the issue.] + +### Additional Information + +[Any additional information that may be helpful in diagnosing the issue.] From aeb9443b18f17116ad39ec08c57f494422c09b2c Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:47:39 -0400 Subject: [PATCH 53/87] Updating dependencies --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ae6e778..977f49f 100644 --- a/package.json +++ b/package.json @@ -26,14 +26,14 @@ "homepage": "https://github.com/yoannchb-pro/MoodleGPT#readme", "devDependencies": { "@rollup/plugin-terser": "^0.4.4", - "@types/chrome": "^0.0.262", - "@typescript-eslint/eslint-plugin": "^7.1.0", - "@typescript-eslint/parser": "^7.1.0", + "@types/chrome": "^0.0.263", + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "prettier": "^3.2.5", - "rollup": "^4.12.0", + "rollup": "^4.13.0", "rollup-plugin-ts": "^3.2.0", - "typescript": "^5.3.3" + "typescript": "^5.4.2" } } From d2441bfff35e776aeae5ea2f572e50a2adc370c5 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:47:53 -0400 Subject: [PATCH 54/87] Create package-lock.json --- package-lock.json | 3411 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3411 insertions(+) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a1018a0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3411 @@ +{ + "name": "moodlegpt", + "version": "1.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "moodlegpt", + "version": "1.1.0", + "license": "MIT", + "devDependencies": { + "@rollup/plugin-terser": "^0.4.4", + "@types/chrome": "^0.0.263", + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "prettier": "^3.2.5", + "rollup": "^4.13.0", + "rollup-plugin-ts": "^3.2.0", + "typescript": "^5.4.2" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.19", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mdn/browser-compat-data": { + "version": "5.3.16", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", + "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/chrome": { + "version": "0.0.263", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.263.tgz", + "integrity": "sha512-As0vzv99ov3M6ZR7R6VzhMWFZXkPMrFrCEXXVrMN576Cm70fTkj7Df2CF+qEo170JepX50pd11cX6O4DSAtl2Q==", + "dev": true, + "dependencies": { + "@types/filesystem": "*", + "@types/har-format": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/filesystem": { + "version": "0.0.33", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filewriter": "*" + } + }, + "node_modules/@types/filewriter": { + "version": "0.0.30", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/har-format": { + "version": "1.2.12", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "17.0.45", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/object-path": { + "version": "0.11.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.5.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ua-parser-js": { + "version": "0.7.37", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz", + "integrity": "sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "7.2.0", + "@typescript-eslint/type-utils": "7.2.0", + "@typescript-eslint/utils": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", + "integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.2.0", + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/typescript-estree": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz", + "integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz", + "integrity": "sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.2.0", + "@typescript-eslint/utils": "7.2.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz", + "integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz", + "integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.2.0.tgz", + "integrity": "sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "7.2.0", + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/typescript-estree": "7.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz", + "integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.2.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@wessberg/stringutil": { + "version": "1.0.19", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.10", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/browserslist-generator": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@mdn/browser-compat-data": "^5.3.7", + "@types/object-path": "^0.11.1", + "@types/semver": "^7.5.0", + "@types/ua-parser-js": "^0.7.36", + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001518", + "isbot": "^3.6.13", + "object-path": "^0.11.8", + "semver": "^7.5.4", + "ua-parser-js": "^1.0.35" + }, + "engines": { + "node": ">=16.15.1", + "npm": ">=7.0.0", + "pnpm": ">=3.2.0", + "yarn": ">=1.13" + }, + "funding": { + "type": "github", + "url": "https://github.com/wessberg/browserslist-generator?sponsor=1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "2.20.3", + "dev": true, + "license": "MIT" + }, + "node_modules/compatfactory": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "helpertypes": "^0.0.19" + }, + "engines": { + "node": ">=14.9.0" + }, + "peerDependencies": { + "typescript": ">=3.x || >= 4.x || >= 5.x" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crosspath": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^17.0.36" + }, + "engines": { + "node": ">=14.9.0" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.522", + "dev": true, + "license": "ISC" + }, + "node_modules/escalade": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "dev": true, + "license": "ISC" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/helpertypes": { + "version": "0.0.19", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isbot": { + "version": "3.6.13", + "dev": true, + "license": "Unlicense", + "engines": { + "node": ">=12" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.30.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.13", + "dev": true, + "license": "MIT" + }, + "node_modules/object-path": { + "version": "0.11.8", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", + "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.13.0", + "@rollup/rollup-android-arm64": "4.13.0", + "@rollup/rollup-darwin-arm64": "4.13.0", + "@rollup/rollup-darwin-x64": "4.13.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@rollup/rollup-linux-arm64-musl": "4.13.0", + "@rollup/rollup-linux-riscv64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-musl": "4.13.0", + "@rollup/rollup-win32-arm64-msvc": "4.13.0", + "@rollup/rollup-win32-ia32-msvc": "4.13.0", + "@rollup/rollup-win32-x64-msvc": "4.13.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-ts": { + "version": "3.4.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.2", + "@wessberg/stringutil": "^1.0.19", + "ansi-colors": "^4.1.3", + "browserslist": "^4.21.10", + "browserslist-generator": "^2.1.0", + "compatfactory": "^3.0.0", + "crosspath": "^2.0.0", + "magic-string": "^0.30.2", + "ts-clone-node": "^3.0.0", + "tslib": "^2.6.1" + }, + "engines": { + "node": ">=16.15.1", + "npm": ">=7.0.0", + "pnpm": ">=3.2.0", + "yarn": ">=1.13" + }, + "funding": { + "type": "github", + "url": "https://github.com/wessberg/rollup-plugin-ts?sponsor=1" + }, + "peerDependencies": { + "@babel/core": ">=7.x", + "@babel/plugin-transform-runtime": ">=7.x", + "@babel/preset-env": ">=7.x", + "@babel/preset-typescript": ">=7.x", + "@babel/runtime": ">=7.x", + "@swc/core": ">=1.x", + "@swc/helpers": ">=0.2", + "rollup": ">=1.x || >=2.x || >=3.x", + "typescript": ">=3.2.x || >= 4.x || >= 5.x" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@babel/plugin-transform-runtime": { + "optional": true + }, + "@babel/preset-env": { + "optional": true + }, + "@babel/preset-typescript": { + "optional": true + }, + "@babel/runtime": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.5.4", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smob": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser": { + "version": "5.19.4", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-clone-node": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "compatfactory": "^3.0.0" + }, + "engines": { + "node": ">=14.9.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/wessberg/ts-clone-node?sponsor=1" + }, + "peerDependencies": { + "typescript": "^3.x || ^4.x || ^5.x" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "1.0.36", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.11", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "dev": true + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.10.0", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.1.4", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "@eslint/js": { + "version": "8.57.0", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.11.14", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "2.0.2", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.5", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.19", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "@mdn/browser-compat-data": { + "version": "5.3.16", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "requires": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + } + }, + "@rollup/pluginutils": { + "version": "5.1.0", + "dev": true, + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + } + }, + "@rollup/rollup-win32-x64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", + "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", + "dev": true, + "optional": true + }, + "@types/chrome": { + "version": "0.0.263", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.263.tgz", + "integrity": "sha512-As0vzv99ov3M6ZR7R6VzhMWFZXkPMrFrCEXXVrMN576Cm70fTkj7Df2CF+qEo170JepX50pd11cX6O4DSAtl2Q==", + "dev": true, + "requires": { + "@types/filesystem": "*", + "@types/har-format": "*" + } + }, + "@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "@types/filesystem": { + "version": "0.0.33", + "dev": true, + "requires": { + "@types/filewriter": "*" + } + }, + "@types/filewriter": { + "version": "0.0.30", + "dev": true + }, + "@types/har-format": { + "version": "1.2.12", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "@types/node": { + "version": "17.0.45", + "dev": true + }, + "@types/object-path": { + "version": "0.11.2", + "dev": true + }, + "@types/semver": { + "version": "7.5.2", + "dev": true + }, + "@types/ua-parser-js": { + "version": "0.7.37", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz", + "integrity": "sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "7.2.0", + "@typescript-eslint/type-utils": "7.2.0", + "@typescript-eslint/utils": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/parser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", + "integrity": "sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "7.2.0", + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/typescript-estree": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz", + "integrity": "sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz", + "integrity": "sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "7.2.0", + "@typescript-eslint/utils": "7.2.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/types": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.2.0.tgz", + "integrity": "sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz", + "integrity": "sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/visitor-keys": "7.2.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/utils": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.2.0.tgz", + "integrity": "sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "7.2.0", + "@typescript-eslint/types": "7.2.0", + "@typescript-eslint/typescript-estree": "7.2.0", + "semver": "^7.5.4" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz", + "integrity": "sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.2.0", + "eslint-visitor-keys": "^3.4.1" + } + }, + "@ungap/structured-clone": { + "version": "1.2.0", + "dev": true + }, + "@wessberg/stringutil": { + "version": "1.0.19", + "dev": true + }, + "acorn": { + "version": "8.10.0", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.3", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.21.10", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" + } + }, + "browserslist-generator": { + "version": "2.1.0", + "dev": true, + "requires": { + "@mdn/browser-compat-data": "^5.3.7", + "@types/object-path": "^0.11.1", + "@types/semver": "^7.5.0", + "@types/ua-parser-js": "^0.7.36", + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001518", + "isbot": "^3.6.13", + "object-path": "^0.11.8", + "semver": "^7.5.4", + "ua-parser-js": "^1.0.35" + } + }, + "buffer-from": { + "version": "1.1.2", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "dev": true + }, + "commander": { + "version": "2.20.3", + "dev": true + }, + "compatfactory": { + "version": "3.0.0", + "dev": true, + "requires": { + "helpertypes": "^0.0.19" + } + }, + "concat-map": { + "version": "0.0.1", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crosspath": { + "version": "2.0.0", + "dev": true, + "requires": { + "@types/node": "^17.0.36" + } + }, + "debug": { + "version": "4.3.4", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.4", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "electron-to-chromium": { + "version": "1.4.522", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "dev": true + }, + "eslint": { + "version": "8.57.0", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "eslint-config-prettier": { + "version": "9.1.0", + "dev": true, + "requires": {} + }, + "eslint-scope": { + "version": "7.2.2", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "dev": true + }, + "espree": { + "version": "9.6.1", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esquery": { + "version": "1.5.0", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "dev": true + }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "dev": true + }, + "fastq": { + "version": "1.17.1", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.2.0", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.3.1", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "dev": true + }, + "glob": { + "version": "7.2.3", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "glob-parent": { + "version": "6.0.2", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.24.0", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "graphemer": { + "version": "1.4.0", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "dev": true + }, + "helpertypes": { + "version": "0.0.19", + "dev": true + }, + "ignore": { + "version": "5.3.1", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "dev": true + }, + "isbot": { + "version": "3.6.13", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-buffer": { + "version": "3.0.1", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true + }, + "keyv": { + "version": "4.5.4", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "levn": { + "version": "0.4.1", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "locate-path": { + "version": "6.0.0", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash.merge": { + "version": "4.6.2", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "magic-string": { + "version": "0.30.3", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "ms": { + "version": "2.1.2", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "dev": true + }, + "node-releases": { + "version": "2.0.13", + "dev": true + }, + "object-path": { + "version": "0.11.8", + "dev": true + }, + "once": { + "version": "1.4.0", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.3", + "dev": true, + "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + } + }, + "p-limit": { + "version": "3.1.0", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "parent-module": { + "version": "1.0.1", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-exists": { + "version": "4.0.0", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "dev": true + }, + "prettier": { + "version": "3.2.5", + "dev": true + }, + "punycode": { + "version": "2.3.1", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", + "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "dev": true, + "requires": { + "@rollup/rollup-android-arm-eabi": "4.13.0", + "@rollup/rollup-android-arm64": "4.13.0", + "@rollup/rollup-darwin-arm64": "4.13.0", + "@rollup/rollup-darwin-x64": "4.13.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@rollup/rollup-linux-arm64-musl": "4.13.0", + "@rollup/rollup-linux-riscv64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-musl": "4.13.0", + "@rollup/rollup-win32-arm64-msvc": "4.13.0", + "@rollup/rollup-win32-ia32-msvc": "4.13.0", + "@rollup/rollup-win32-x64-msvc": "4.13.0", + "@types/estree": "1.0.5", + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-ts": { + "version": "3.4.5", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.2", + "@wessberg/stringutil": "^1.0.19", + "ansi-colors": "^4.1.3", + "browserslist": "^4.21.10", + "browserslist-generator": "^2.1.0", + "compatfactory": "^3.0.0", + "crosspath": "^2.0.0", + "magic-string": "^0.30.2", + "ts-clone-node": "^3.0.0", + "tslib": "^2.6.1" + } + }, + "run-parallel": { + "version": "1.2.0", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "dev": true + }, + "semver": { + "version": "7.5.4", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "serialize-javascript": { + "version": "6.0.1", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "smob": { + "version": "1.4.0", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "terser": { + "version": "5.19.4", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + }, + "text-table": { + "version": "0.2.0", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-api-utils": { + "version": "1.2.1", + "dev": true, + "requires": {} + }, + "ts-clone-node": { + "version": "3.0.0", + "dev": true, + "requires": { + "compatfactory": "^3.0.0" + } + }, + "tslib": { + "version": "2.6.2", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "dev": true + }, + "typescript": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "dev": true + }, + "ua-parser-js": { + "version": "1.0.36", + "dev": true + }, + "update-browserslist-db": { + "version": "1.0.11", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "which": { + "version": "2.0.2", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "dev": true + } + } +} From c01a82168b52dee4897de2f9a78f297c9eca4615 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:48:40 -0400 Subject: [PATCH 55/87] reduce image quality to 75% --- README.md | 2 +- src/utils/image-to-base64.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1edcf47..52a3fe0 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Go to "Manage my extensions" on your browser, then click on "Load unpa
![Mouseover2](./assets/mouseover2.gif) - Infinite try: click as much as you want on the question (don't forget to reset the question). - Save history: allows you to create a conversation with ChatGPT by saving the previous question with its answer. However, note that it can consume a significant number of tokens. -- Include images (only work with gpt-4): allows you to include the images from the question to be send to the chatgpt api. However, note that it can consume a significant number of tokens. +- Include images (only work with gpt-4): allows you to include the images from the question to be send to the chatgpt api. The quality is reduced to 75% to use less tokens.However, note that it can consume a significant number of tokens.
![Images](./assets/images.gif) ## Internal Features diff --git a/src/utils/image-to-base64.ts b/src/utils/image-to-base64.ts index f642c34..4232f53 100644 --- a/src/utils/image-to-base64.ts +++ b/src/utils/image-to-base64.ts @@ -1,9 +1,10 @@ /** * Convert an image html element into a base64 image string * @param imageElement + * @param quality (default: 0.75 -> 75%) * @returns */ -function imageToBase64(imageElement: HTMLImageElement): Promise { +function imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise { return new Promise(resolve => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); @@ -21,7 +22,7 @@ function imageToBase64(imageElement: HTMLImageElement): Promise { canvas.height = img.height; ctx.drawImage(img, 0, 0); - const base64 = canvas.toDataURL('image/png'); + const base64 = canvas.toDataURL('image/png', quality); resolve(base64); canvas.remove(); From cb34ec8093bd2bd5a891c2fdf281027524a2e1b0 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:57:19 -0400 Subject: [PATCH 56/87] history and snake case fixe --- extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- src/core/get-content-with-history.ts | 167 ++++++++++++++++++++++ src/core/get-response.ts | 122 +--------------- src/core/modes/autocomplete.ts | 2 +- src/core/modes/clipboard.ts | 2 +- src/core/modes/question-to-answer.ts | 2 +- src/core/questions/checkbox.ts | 2 +- src/core/questions/clipboard.ts | 2 +- src/core/questions/contenteditable.ts | 2 +- src/core/questions/number.ts | 2 +- src/core/questions/radio.ts | 2 +- src/core/questions/select.ts | 2 +- src/core/questions/textbox.ts | 2 +- src/types/{gptAnswer.ts => gpt-answer.ts} | 0 src/types/message.ts | 28 ++++ src/utils/logs.ts | 2 +- 17 files changed, 214 insertions(+), 129 deletions(-) create mode 100644 src/core/get-content-with-history.ts rename src/types/{gptAnswer.ts => gpt-answer.ts} (100%) create mode 100644 src/types/message.ts diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index 5f84e68..81c8253 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,2 +1,2 @@ -!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: \nexplanation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={url:null,system:{role:s.SYSTEM,content:c},history:[]};function u(e,t,o){return n(this,void 0,void 0,(function*(){const n=t.querySelectorAll("img");if(e.includeImages&&function(e){const n=e.match(/gpt-(\d+)/);return!!(null==n?void 0:n[1])&&Number(n[1])>=4}(e.model)&&0===n.length)return o;let r=[];const i=Array.from(n).map((e=>{return n=e,new Promise((e=>{const t=document.createElement("canvas"),o=t.getContext("2d");if(!o)return e(null),void t.remove();const r=new Image;r.crossOrigin="Anonymous",r.onload=()=>{t.width=r.width,t.height=r.height,o.drawImage(r,0,0);const n=t.toDataURL("image/png");e(n),t.remove()},r.onerror=()=>{e(null),t.remove()},r.src=n.src}));var n})),s=(yield Promise.all(i)).filter((e=>null!==e));for(const e of s)r.push({type:l.IMAGE,image_url:{url:e}});return r.length>0?r.push({type:l.TEXT,text:o}):r=o,r}))}function f(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function m(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function d(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function p(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function h(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function g(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function v(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function y(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function w(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+f(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),l=yield function(e,t,o){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&a.url===n||(a.url=n,a.history=[]);const r=new AbortController,l=setTimeout((()=>r.abort()),2e4),c=yield u(e,t,o),f={role:s.USER,content:c},m=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?r.signal:null,body:JSON.stringify({model:e.model,messages:[a.system,...a.history,f],temperature:.1,top_p:1,presence_penalty:0,max_tokens:2e3})});clearTimeout(l);const d=(yield m.json()).choices[0].message.content;return e.history&&(a.history.push(f),a.history.push({role:s.ASSISTANT,content:d})),{question:o,response:d,normalizedResponse:i(d)}}))}(e.config,e.questionElement,t).catch((e=>({error:e}))),c="object"==typeof l&&"error"in l;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||c?"pointer":"initial"),c)console.error(l.error);else switch(e.config.logs&&(r.question(t),r.response(l)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),m(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:l,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:l,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[d,y,p,v,h,g];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;m(e.config,e.gptAnswer)}({config:e.config,gptAnswer:l,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const A=[],E=[];function x(e){const n=E.findIndex((n=>n.element===e));if(-1!==n){const e=E.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function S(n){if(E.length>0){for(const e of E)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(E.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=w.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>x(o)});E.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){A.push(n.key),A.length>e.code.length&&A.shift(),A.join("")===e.code&&(A.length=0,S(e))}))}(n):S(n)}))})); +!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: \nexplanation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={role:s.SYSTEM,content:c};function u(e,t,o){return n(this,void 0,void 0,(function*(){const n=t.querySelectorAll("img");if(e.includeImages&&function(e){const n=e.match(/gpt-(\d+)/);return!!(null==n?void 0:n[1])&&Number(n[1])>=4}(e.model)&&0===n.length)return o;let r=[];const i=Array.from(n).map((e=>function(e,n=.75){return new Promise((t=>{const o=document.createElement("canvas"),r=o.getContext("2d");if(!r)return t(null),void o.remove();const i=new Image;i.crossOrigin="Anonymous",i.onload=()=>{o.width=i.width,o.height=i.height,r.drawImage(i,0,0);const e=o.toDataURL("image/png",n);t(e),o.remove()},i.onerror=()=>{t(null),o.remove()},i.src=e.src}))}(e))),s=(yield Promise.all(i)).filter((e=>null!==e));for(const e of s)r.push({type:l.IMAGE,image_url:{url:e}});return r.length>0?r.push({type:l.TEXT,text:o}):r=o,r}))}function f(e,t,o){return n(this,void 0,void 0,(function*(){const n=yield u(e,t,o),r={role:s.USER,content:n};if(!e.history)return{messages:[a,r]};let i;const l=JSON.parse(null!==(c=sessionStorage.moodleGPTHistory)&&void 0!==c?c:"null");var c;const f=function(){const e=new URLSearchParams(document.location.search).entries(),n={};for(const[t,o]of e)"page"!==t&&(n[t]=o);return{url:document.location.host,params:n,history:[]}}();return i=null!==l&&function(e,n){if(e.url!==n.url)return!1;if(Object.keys(e.params).length!==Object.keys(n.params).length)return!1;for(const[t,o]of Object.entries(e.params))if(!(t in n.params)||n.params[t]!==o)return!1;return!0}(l,f)?l:f,{messages:[a,...i.history,r],saveResponse(n){e.history&&(i.history.push(r),i.history.push({role:s.ASSISTANT,content:n}),sessionStorage.moodleGPTHistory=JSON.stringify(i))}}}))}function m(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function d(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function p(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function h(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function g(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function v(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function y(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function w(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function A(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+m(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),s=yield function(e,t,o){return n(this,void 0,void 0,(function*(){const n=new AbortController,r=setTimeout((()=>n.abort()),2e4),s=yield f(e,t,o),l=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?n.signal:null,body:JSON.stringify({model:e.model,messages:s.messages,temperature:.1,top_p:1,presence_penalty:0,max_tokens:2e3})});clearTimeout(r);const c=(yield l.json()).choices[0].message.content;return s.saveResponse&&s.saveResponse(c),{question:o,response:c,normalizedResponse:i(c)}}))}(e.config,e.questionElement,t).catch((e=>({error:e}))),l="object"==typeof s&&"error"in s;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||l?"pointer":"initial"),l)console.error(s.error);else switch(e.config.logs&&(r.question(t),r.response(s)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),d(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:s,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:s,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[p,w,h,y,g,v];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;d(e.config,e.gptAnswer)}({config:e.config,gptAnswer:s,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const E=[],S=[];function x(e){const n=S.findIndex((n=>n.element===e));if(-1!==n){const e=S.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function q(n){if(S.length>0){for(const e of S)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(S.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=A.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>x(o)});S.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){E.push(n.key),E.length>e.code.length&&E.shift(),E.join("")===e.code&&(E.length=0,q(e))}))}(n):q(n)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index ecf9c7e..bb45dfb 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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/core/get-response.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport imageToBase64 from '@utils/image-to-base64';\nimport normalizeText from '@utils/normalize-text';\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\n\ntype Content =\n | string\n | Array<\n | {\n type: CONTENT_TYPE.TEXT;\n text: string;\n }\n | {\n type: CONTENT_TYPE.IMAGE;\n image_url: { url: string };\n }\n >;\n\ntype History = {\n url: string | null;\n system: { role: ROLE; content: Content };\n history: { role: ROLE; content: Content }[];\n};\n\nenum ROLE {\n SYSTEM = 'system',\n USER = 'user',\n ASSISTANT = 'assistant'\n}\n\nenum CONTENT_TYPE {\n TEXT = 'text',\n IMAGE = 'image_url'\n}\n\nconst INSTRUCTION: string = `\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: \\nexplanation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\n- Always reply in the format: '\\n\\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n`.trim();\n\nconst history: History = {\n url: null,\n system: {\n role: ROLE.SYSTEM,\n content: INSTRUCTION\n },\n history: []\n};\n\n/**\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\n * @param config\n */\nasync function getContent(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const imagesElements = questionElement.querySelectorAll('img');\n\n if (\n config.includeImages &&\n isGPTModelGreaterOrEqualTo4(config.model) &&\n imagesElements.length === 0\n ) {\n return question;\n }\n\n let content: Content = [];\n\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\n const results = await Promise.all(base64Images);\n const filteredResults = results.filter(value => value !== null) as string[];\n\n for (const result of filteredResults) {\n content.push({\n type: CONTENT_TYPE.IMAGE,\n image_url: { url: result }\n });\n }\n\n if (content.length > 0) {\n content.push({\n type: CONTENT_TYPE.TEXT,\n text: question\n });\n } else {\n content = question;\n }\n\n return content;\n}\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const URL = location.hostname + location.pathname;\n\n // We reset the history when we enter a new moodle quiz or when it's desactivate\n if (!config.history || history.url !== URL) {\n history.url = URL;\n history.history = [];\n }\n\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n const content = await getContent(config, questionElement, question);\n const message = { role: ROLE.USER, content };\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: [history.system, ...history.history, message],\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 1, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Register the conversation\n if (config.history) {\n history.history.push(message);\n history.history.push({ role: ROLE.ASSISTANT, content: response });\n }\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement): Promise {\r\n return new Promise(resolve => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n resolve(null);\r\n canvas.remove();\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png');\r\n resolve(base64);\r\n\r\n canvas.remove();\r\n };\r\n\r\n img.onerror = () => {\r\n resolve(null);\r\n canvas.remove();\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","history","url","system","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","base64Images","Array","from","map","imgEl","imageToBase64","imageElement","canvas","createElement","ctx","getContext","remove","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","src","filteredResults","all","filter","type","IMAGE","image_url","TEXT","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","_b","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","messages","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","error","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/types/message.ts","../src/core/get-content-with-history.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/get-response.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","export enum ROLE {\r\n SYSTEM = 'system',\r\n USER = 'user',\r\n ASSISTANT = 'assistant'\r\n}\r\n\r\nexport enum CONTENT_TYPE {\r\n TEXT = 'text',\r\n IMAGE = 'image_url'\r\n}\r\n\r\nexport type MessageContent =\r\n | string\r\n | Array<\r\n | {\r\n type: CONTENT_TYPE.TEXT;\r\n text: string;\r\n }\r\n | {\r\n type: CONTENT_TYPE.IMAGE;\r\n image_url: { url: string };\r\n }\r\n >;\r\n\r\nexport type Message = {\r\n role: ROLE;\r\n content: MessageContent;\r\n};\r\n","import type Config from '@typing/config';\r\nimport { ROLE, CONTENT_TYPE, type MessageContent, type Message } from '@typing/message';\r\nimport imageToBase64 from '@utils/image-to-base64';\r\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\r\n\r\ntype History = {\r\n url: string | null;\r\n params: Record;\r\n history: { role: ROLE; content: MessageContent }[];\r\n};\r\n\r\nconst INSTRUCTION: string = `\r\nAct as a quiz solver for the best notation with the following rules:\r\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \r\n But for the calculation provide this format 'result: \\nexplanation: '\r\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\r\n- Always reply in the format: '\\n\\n...'.\r\n- Retain only the correct answer(s).\r\n- Maintain the same order for the answers as in the text.\r\n- Retain all text from the answer with its description, content or definition.\r\n- Only provide answers that exactly match the given answer in the text.\r\n- The question always has the correct answer(s), so you should always provide an answer.\r\n- Always respond in the same language as the user's question.\r\n`.trim();\r\n\r\nconst SYSTEM_INSTRUCTION_MESSAGE = {\r\n role: ROLE.SYSTEM,\r\n content: INSTRUCTION\r\n} as const;\r\n\r\n/**\r\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\r\n * @param config\r\n */\r\nasync function getContent(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise {\r\n const imagesElements = questionElement.querySelectorAll('img');\r\n\r\n if (\r\n config.includeImages &&\r\n isGPTModelGreaterOrEqualTo4(config.model) &&\r\n imagesElements.length === 0\r\n ) {\r\n return question;\r\n }\r\n\r\n let content: MessageContent = [];\r\n\r\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\r\n const results = await Promise.all(base64Images);\r\n const filteredResults = results.filter(value => value !== null) as string[];\r\n\r\n for (const result of filteredResults) {\r\n content.push({\r\n type: CONTENT_TYPE.IMAGE,\r\n image_url: { url: result }\r\n });\r\n }\r\n\r\n if (content.length > 0) {\r\n content.push({\r\n type: CONTENT_TYPE.TEXT,\r\n text: question\r\n });\r\n } else {\r\n content = question;\r\n }\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * Create a new history object from the current page\r\n * @returns\r\n */\r\nfunction createNewHistory(): History {\r\n const url_params = new URLSearchParams(document.location.search).entries();\r\n const params: Record = {};\r\n\r\n for (const [key, value] of url_params) {\r\n if (key === 'page') continue;\r\n params[key] = value;\r\n }\r\n\r\n return {\r\n url: document.location.host,\r\n params,\r\n history: []\r\n };\r\n}\r\n\r\n/**\r\n * Load the past history from the session storage otherwise return the default history object\r\n * @returns\r\n */\r\nfunction loadPastHistory(): History | null {\r\n return JSON.parse(sessionStorage.moodleGPTHistory ?? 'null');\r\n}\r\n\r\n/**\r\n * Check if two history are from the same origin\r\n * @param a\r\n * @param b\r\n * @returns\r\n */\r\nfunction areHistorySameOrigin(a: History, b: History): boolean {\r\n if (a.url !== b.url) return false;\r\n\r\n if (Object.keys(a.params).length !== Object.keys(b.params).length) return false;\r\n\r\n for (const [key, value] of Object.entries(a.params)) {\r\n if (!(key in b.params) || b.params[key] !== value) return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Return the content to send to chatgpt api with history if needed\r\n * @param config\r\n * @param questionElement\r\n * @param question\r\n * @returns\r\n */\r\nasync function getContentWithHistory(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise<{\r\n messages: [typeof SYSTEM_INSTRUCTION_MESSAGE, ...Message[]];\r\n saveResponse?: (response: string) => void;\r\n}> {\r\n const content = await getContent(config, questionElement, question);\r\n const message = { role: ROLE.USER, content };\r\n\r\n if (!config.history) return { messages: [SYSTEM_INSTRUCTION_MESSAGE, message] };\r\n\r\n let history: History;\r\n\r\n const pastHistory: History | null = loadPastHistory();\r\n const newHistory: History = createNewHistory();\r\n\r\n if (pastHistory === null || !areHistorySameOrigin(pastHistory, newHistory)) {\r\n history = newHistory;\r\n } else {\r\n history = pastHistory;\r\n }\r\n\r\n return {\r\n messages: [SYSTEM_INSTRUCTION_MESSAGE, ...history.history, message],\r\n saveResponse(response: string) {\r\n // Register the conversation\r\n if (config.history) {\r\n history.history.push(message);\r\n history.history.push({ role: ROLE.ASSISTANT, content: response });\r\n sessionStorage.moodleGPTHistory = JSON.stringify(history);\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default getContentWithHistory;\r\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @param quality (default: 0.75 -> 75%)\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise {\r\n return new Promise(resolve => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n resolve(null);\r\n canvas.remove();\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png', quality);\r\n resolve(base64);\r\n\r\n canvas.remove();\r\n };\r\n\r\n img.onerror = () => {\r\n resolve(null);\r\n canvas.remove();\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport normalizeText from '@utils/normalize-text';\nimport getContentWithHistory from './get-content-with-history';\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n const contentHandler = await getContentWithHistory(config, questionElement, question);\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: contentHandler.messages,\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 1, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Save the response into the history\n if (contentHandler.saveResponse) contentHandler.saveResponse(response);\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","SYSTEM_INSTRUCTION_MESSAGE","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","base64Images","Array","from","map","imgEl","imageElement","quality","canvas","createElement","ctx","getContext","remove","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","src","imageToBase64","filteredResults","all","filter","type","IMAGE","image_url","url","TEXT","getContentWithHistory","message","USER","history","messages","pastHistory","JSON","parse","_a","sessionStorage","moodleGPTHistory","newHistory","url_params","URLSearchParams","location","search","entries","params","key","host","createNewHistory","a","b","Object","keys","areHistorySameOrigin","saveResponse","ASSISTANT","stringify","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","textContent","max","lineSeparationSize","reduce","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","_b","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","controller","AbortController","timeoutControler","abort","contentHandler","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","getChatGPTResponse","catch","error","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file diff --git a/src/core/get-content-with-history.ts b/src/core/get-content-with-history.ts new file mode 100644 index 0000000..e13408f --- /dev/null +++ b/src/core/get-content-with-history.ts @@ -0,0 +1,167 @@ +import type Config from '@typing/config'; +import { ROLE, CONTENT_TYPE, type MessageContent, type Message } from '@typing/message'; +import imageToBase64 from '@utils/image-to-base64'; +import isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images'; + +// @TODO: implement cmid, attempt, effacer choix + +type History = { + url: string | null; + params: Record; + history: { role: ROLE; content: MessageContent }[]; +}; + +const INSTRUCTION: string = ` +Act as a quiz solver for the best notation with the following rules: +- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. + But for the calculation provide this format 'result: \nexplanation: ' +- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...' +- Always reply in the format: '\n\n...'. +- Retain only the correct answer(s). +- Maintain the same order for the answers as in the text. +- Retain all text from the answer with its description, content or definition. +- Only provide answers that exactly match the given answer in the text. +- The question always has the correct answer(s), so you should always provide an answer. +- Always respond in the same language as the user's question. +`.trim(); + +const SYSTEM_INSTRUCTION_MESSAGE = { + role: ROLE.SYSTEM, + content: INSTRUCTION +} as const; + +/** + * Get the content to send to ChatGPT API (it allows to includes images if supported) + * @param config + */ +async function getContent( + config: Config, + questionElement: HTMLElement, + question: string +): Promise { + const imagesElements = questionElement.querySelectorAll('img'); + + if ( + config.includeImages && + isGPTModelGreaterOrEqualTo4(config.model) && + imagesElements.length === 0 + ) { + return question; + } + + let content: MessageContent = []; + + const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl)); + const results = await Promise.all(base64Images); + const filteredResults = results.filter(value => value !== null) as string[]; + + for (const result of filteredResults) { + content.push({ + type: CONTENT_TYPE.IMAGE, + image_url: { url: result } + }); + } + + if (content.length > 0) { + content.push({ + type: CONTENT_TYPE.TEXT, + text: question + }); + } else { + content = question; + } + + return content; +} + +/** + * Create a new history object from the current page + * @returns + */ +function createNewHistory(): History { + const url_params = new URLSearchParams(document.location.search).entries(); + const params: Record = {}; + + for (const [key, value] of url_params) { + if (key === 'page') continue; + params[key] = value; + } + + return { + url: document.location.host, + params, + history: [] + }; +} + +/** + * Load the past history from the session storage otherwise return the default history object + * @returns + */ +function loadPastHistory(): History | null { + return JSON.parse(sessionStorage.moodleGPTHistory ?? 'null'); +} + +/** + * Check if two history are from the same origin + * @param a + * @param b + * @returns + */ +function areHistorySameOrigin(a: History, b: History): boolean { + if (a.url !== b.url) return false; + + if (Object.keys(a.params).length !== Object.keys(b.params).length) return false; + + for (const [key, value] of Object.entries(a.params)) { + if (!(key in b.params) || b.params[key] !== value) return false; + } + + return true; +} + +/** + * Return the content to send to chatgpt api with history if needed + * @param config + * @param questionElement + * @param question + * @returns + */ +async function getContentWithHistory( + config: Config, + questionElement: HTMLElement, + question: string +): Promise<{ + messages: [typeof SYSTEM_INSTRUCTION_MESSAGE, ...Message[]]; + saveResponse?: (response: string) => void; +}> { + const content = await getContent(config, questionElement, question); + const message = { role: ROLE.USER, content }; + + if (!config.history) return { messages: [SYSTEM_INSTRUCTION_MESSAGE, message] }; + + let history: History; + + const pastHistory: History | null = loadPastHistory(); + const newHistory: History = createNewHistory(); + + if (pastHistory === null || !areHistorySameOrigin(pastHistory, newHistory)) { + history = newHistory; + } else { + history = pastHistory; + } + + return { + messages: [SYSTEM_INSTRUCTION_MESSAGE, ...history.history, message], + saveResponse(response: string) { + // Register the conversation + if (config.history) { + history.history.push(message); + history.history.push({ role: ROLE.ASSISTANT, content: response }); + sessionStorage.moodleGPTHistory = JSON.stringify(history); + } + } + }; +} + +export default getContentWithHistory; diff --git a/src/core/get-response.ts b/src/core/get-response.ts index 623ad88..9defdb5 100644 --- a/src/core/get-response.ts +++ b/src/core/get-response.ts @@ -1,105 +1,7 @@ import type Config from '@typing/config'; -import type GPTAnswer from '@typing/gptAnswer'; -import imageToBase64 from '@utils/image-to-base64'; +import type GPTAnswer from '@typing/gpt-answer'; import normalizeText from '@utils/normalize-text'; -import isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images'; - -type Content = - | string - | Array< - | { - type: CONTENT_TYPE.TEXT; - text: string; - } - | { - type: CONTENT_TYPE.IMAGE; - image_url: { url: string }; - } - >; - -type History = { - url: string | null; - system: { role: ROLE; content: Content }; - history: { role: ROLE; content: Content }[]; -}; - -enum ROLE { - SYSTEM = 'system', - USER = 'user', - ASSISTANT = 'assistant' -} - -enum CONTENT_TYPE { - TEXT = 'text', - IMAGE = 'image_url' -} - -const INSTRUCTION: string = ` -Act as a quiz solver for the best notation with the following rules: -- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. - But for the calculation provide this format 'result: \nexplanation: ' -- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...' -- Always reply in the format: '\n\n...'. -- Retain only the correct answer(s). -- Maintain the same order for the answers as in the text. -- Retain all text from the answer with its description, content or definition. -- Only provide answers that exactly match the given answer in the text. -- The question always has the correct answer(s), so you should always provide an answer. -- Always respond in the same language as the user's question. -`.trim(); - -const history: History = { - url: null, - system: { - role: ROLE.SYSTEM, - content: INSTRUCTION - }, - history: [] -}; - -/** - * Get the content to send to ChatGPT API (it allows to includes images if supported) - * @param config - */ -async function getContent( - config: Config, - questionElement: HTMLElement, - question: string -): Promise { - const imagesElements = questionElement.querySelectorAll('img'); - - if ( - config.includeImages && - isGPTModelGreaterOrEqualTo4(config.model) && - imagesElements.length === 0 - ) { - return question; - } - - let content: Content = []; - - const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl)); - const results = await Promise.all(base64Images); - const filteredResults = results.filter(value => value !== null) as string[]; - - for (const result of filteredResults) { - content.push({ - type: CONTENT_TYPE.IMAGE, - image_url: { url: result } - }); - } - - if (content.length > 0) { - content.push({ - type: CONTENT_TYPE.TEXT, - text: question - }); - } else { - content = question; - } - - return content; -} +import getContentWithHistory from './get-content-with-history'; /** * Get the response from chatGPT api @@ -112,19 +14,10 @@ async function getChatGPTResponse( questionElement: HTMLElement, question: string ): Promise { - const URL = location.hostname + location.pathname; - - // We reset the history when we enter a new moodle quiz or when it's desactivate - if (!config.history || history.url !== URL) { - history.url = URL; - history.history = []; - } - const controller = new AbortController(); const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000); - const content = await getContent(config, questionElement, question); - const message = { role: ROLE.USER, content }; + const contentHandler = await getContentWithHistory(config, questionElement, question); const req = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', @@ -135,7 +28,7 @@ async function getChatGPTResponse( signal: config.timeout ? controller.signal : null, body: JSON.stringify({ model: config.model, - messages: [history.system, ...history.history, message], + messages: contentHandler.messages, temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity. top_p: 1, // Determines the diversity of the generated responses @@ -149,11 +42,8 @@ async function getChatGPTResponse( const rep = await req.json(); const response = rep.choices[0].message.content; - // Register the conversation - if (config.history) { - history.history.push(message); - history.history.push({ role: ROLE.ASSISTANT, content: response }); - } + // Save the response into the history + if (contentHandler.saveResponse) contentHandler.saveResponse(response); return { question, diff --git a/src/core/modes/autocomplete.ts b/src/core/modes/autocomplete.ts index 63f7f32..5f8f9a2 100644 --- a/src/core/modes/autocomplete.ts +++ b/src/core/modes/autocomplete.ts @@ -1,4 +1,4 @@ -import type GPTAnswer from '@typing/gptAnswer'; +import type GPTAnswer from '@typing/gpt-answer'; import type Config from '@typing/config'; import handleClipboard from '@core/questions/clipboard'; import handleContentEditable from '@core/questions/contenteditable'; diff --git a/src/core/modes/clipboard.ts b/src/core/modes/clipboard.ts index 782b6d3..a8a1090 100644 --- a/src/core/modes/clipboard.ts +++ b/src/core/modes/clipboard.ts @@ -1,5 +1,5 @@ import type Config from '@typing/config'; -import type GPTAnswer from '@typing/gptAnswer'; +import type GPTAnswer from '@typing/gpt-answer'; import handleClipboard from '@core/questions/clipboard'; type Props = { diff --git a/src/core/modes/question-to-answer.ts b/src/core/modes/question-to-answer.ts index 9250010..ccb7c5a 100644 --- a/src/core/modes/question-to-answer.ts +++ b/src/core/modes/question-to-answer.ts @@ -1,4 +1,4 @@ -import type GPTAnswer from '@typing/gptAnswer'; +import type GPTAnswer from '@typing/gpt-answer'; type Props = { questionElement: HTMLElement; diff --git a/src/core/questions/checkbox.ts b/src/core/questions/checkbox.ts index 5446e71..7764191 100644 --- a/src/core/questions/checkbox.ts +++ b/src/core/questions/checkbox.ts @@ -1,5 +1,5 @@ import type Config from '@typing/config'; -import type GPTAnswer from '@typing/gptAnswer'; +import type GPTAnswer from '@typing/gpt-answer'; import Logs from '@utils/logs'; import normalizeText from '@utils/normalize-text'; import { pickBestReponse } from '@utils/pick-best-response'; diff --git a/src/core/questions/clipboard.ts b/src/core/questions/clipboard.ts index f5af75d..7bf3b04 100644 --- a/src/core/questions/clipboard.ts +++ b/src/core/questions/clipboard.ts @@ -1,5 +1,5 @@ import type Config from '@typing/config'; -import type GPTAnswer from '@typing/gptAnswer'; +import type GPTAnswer from '@typing/gpt-answer'; import titleIndications from '@utils/title-indications'; /** diff --git a/src/core/questions/contenteditable.ts b/src/core/questions/contenteditable.ts index f10c750..188ffc7 100644 --- a/src/core/questions/contenteditable.ts +++ b/src/core/questions/contenteditable.ts @@ -1,5 +1,5 @@ import type Config from '@typing/config'; -import type GPTAnswer from '@typing/gptAnswer'; +import type GPTAnswer from '@typing/gpt-answer'; /** * Hanlde contenteditable elements diff --git a/src/core/questions/number.ts b/src/core/questions/number.ts index 5e52599..c145d2c 100644 --- a/src/core/questions/number.ts +++ b/src/core/questions/number.ts @@ -1,5 +1,5 @@ import type Config from '@typing/config'; -import type GPTAnswer from '@typing/gptAnswer'; +import type GPTAnswer from '@typing/gpt-answer'; /** * Handle number input diff --git a/src/core/questions/radio.ts b/src/core/questions/radio.ts index e903dad..9c31561 100644 --- a/src/core/questions/radio.ts +++ b/src/core/questions/radio.ts @@ -1,5 +1,5 @@ import type Config from '@typing/config'; -import type GPTAnswer from '@typing/gptAnswer'; +import type GPTAnswer from '@typing/gpt-answer'; import Logs from '@utils/logs'; import normalizeText from '@utils/normalize-text'; import { pickBestReponse } from '@utils/pick-best-response'; diff --git a/src/core/questions/select.ts b/src/core/questions/select.ts index 49cf762..e6e35c5 100644 --- a/src/core/questions/select.ts +++ b/src/core/questions/select.ts @@ -1,5 +1,5 @@ import type Config from '@typing/config'; -import type GPTAnswer from '@typing/gptAnswer'; +import type GPTAnswer from '@typing/gpt-answer'; import Logs from '@utils/logs'; import normalizeText from '@utils/normalize-text'; import { pickBestReponse } from '@utils/pick-best-response'; diff --git a/src/core/questions/textbox.ts b/src/core/questions/textbox.ts index 810c883..3accaaa 100644 --- a/src/core/questions/textbox.ts +++ b/src/core/questions/textbox.ts @@ -1,5 +1,5 @@ import type Config from '@typing/config'; -import type GPTAnswer from '@typing/gptAnswer'; +import type GPTAnswer from '@typing/gpt-answer'; /** * Handle textbox diff --git a/src/types/gptAnswer.ts b/src/types/gpt-answer.ts similarity index 100% rename from src/types/gptAnswer.ts rename to src/types/gpt-answer.ts diff --git a/src/types/message.ts b/src/types/message.ts new file mode 100644 index 0000000..165e73f --- /dev/null +++ b/src/types/message.ts @@ -0,0 +1,28 @@ +export enum ROLE { + SYSTEM = 'system', + USER = 'user', + ASSISTANT = 'assistant' +} + +export enum CONTENT_TYPE { + TEXT = 'text', + IMAGE = 'image_url' +} + +export type MessageContent = + | string + | Array< + | { + type: CONTENT_TYPE.TEXT; + text: string; + } + | { + type: CONTENT_TYPE.IMAGE; + image_url: { url: string }; + } + >; + +export type Message = { + role: ROLE; + content: MessageContent; +}; diff --git a/src/utils/logs.ts b/src/utils/logs.ts index eb4a9d1..30a0b0e 100644 --- a/src/utils/logs.ts +++ b/src/utils/logs.ts @@ -1,4 +1,4 @@ -import GPTAnswer from '@typing/gptAnswer'; +import GPTAnswer from '@typing/gpt-answer'; import { toPourcentage } from './pick-best-response'; class Logs { From 59ae5b23cc6487f5b6f51d5bc793daa0fabd4457 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 14 Mar 2024 16:46:12 -0400 Subject: [PATCH 57/87] Update TODO.md --- TODO.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index 815cb61..86366e7 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,7 @@ # TODO -- Historic for questions (implemented but need testing) +- Fixe select mouse hover and add "clean my choice" when selecting answer +- Historic for questions - Better prompt (Fixe put in order question, Fixe calculation question) - Better webstore assets - Do some tests From 334e30c1c3d66148333080c6c633780ee1138eae Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 14 Mar 2024 16:46:36 -0400 Subject: [PATCH 58/87] reject error for logs when we can't convert image to base64 --- src/utils/image-to-base64.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/utils/image-to-base64.ts b/src/utils/image-to-base64.ts index 4232f53..6b7f498 100644 --- a/src/utils/image-to-base64.ts +++ b/src/utils/image-to-base64.ts @@ -4,13 +4,13 @@ * @param quality (default: 0.75 -> 75%) * @returns */ -function imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise { - return new Promise(resolve => { +function imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise { + return new Promise((resolve, reject) => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); if (!ctx) { - resolve(null); + reject("Can't get the canvas context, ensure your navigator support canvas"); canvas.remove(); return; } @@ -28,8 +28,8 @@ function imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise< canvas.remove(); }; - img.onerror = () => { - resolve(null); + img.onerror = err => { + reject(err); canvas.remove(); }; From b0d2fc8f4804908cacebadc691bf8ced5f5b0d11 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 14 Mar 2024 16:46:58 -0400 Subject: [PATCH 59/87] better history based on cmid and attempt --- extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- src/core/get-content-with-history.ts | 72 +++++++++++++--------------- src/core/get-response.ts | 4 +- 4 files changed, 37 insertions(+), 43 deletions(-) diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index 81c8253..c5b8e12 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,2 +1,2 @@ -!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: \nexplanation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={role:s.SYSTEM,content:c};function u(e,t,o){return n(this,void 0,void 0,(function*(){const n=t.querySelectorAll("img");if(e.includeImages&&function(e){const n=e.match(/gpt-(\d+)/);return!!(null==n?void 0:n[1])&&Number(n[1])>=4}(e.model)&&0===n.length)return o;let r=[];const i=Array.from(n).map((e=>function(e,n=.75){return new Promise((t=>{const o=document.createElement("canvas"),r=o.getContext("2d");if(!r)return t(null),void o.remove();const i=new Image;i.crossOrigin="Anonymous",i.onload=()=>{o.width=i.width,o.height=i.height,r.drawImage(i,0,0);const e=o.toDataURL("image/png",n);t(e),o.remove()},i.onerror=()=>{t(null),o.remove()},i.src=e.src}))}(e))),s=(yield Promise.all(i)).filter((e=>null!==e));for(const e of s)r.push({type:l.IMAGE,image_url:{url:e}});return r.length>0?r.push({type:l.TEXT,text:o}):r=o,r}))}function f(e,t,o){return n(this,void 0,void 0,(function*(){const n=yield u(e,t,o),r={role:s.USER,content:n};if(!e.history)return{messages:[a,r]};let i;const l=JSON.parse(null!==(c=sessionStorage.moodleGPTHistory)&&void 0!==c?c:"null");var c;const f=function(){const e=new URLSearchParams(document.location.search).entries(),n={};for(const[t,o]of e)"page"!==t&&(n[t]=o);return{url:document.location.host,params:n,history:[]}}();return i=null!==l&&function(e,n){if(e.url!==n.url)return!1;if(Object.keys(e.params).length!==Object.keys(n.params).length)return!1;for(const[t,o]of Object.entries(e.params))if(!(t in n.params)||n.params[t]!==o)return!1;return!0}(l,f)?l:f,{messages:[a,...i.history,r],saveResponse(n){e.history&&(i.history.push(r),i.history.push({role:s.ASSISTANT,content:n}),sessionStorage.moodleGPTHistory=JSON.stringify(i))}}}))}function m(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function d(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function p(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function h(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function g(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function v(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function y(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function w(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function A(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+m(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),s=yield function(e,t,o){return n(this,void 0,void 0,(function*(){const n=new AbortController,r=setTimeout((()=>n.abort()),2e4),s=yield f(e,t,o),l=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?n.signal:null,body:JSON.stringify({model:e.model,messages:s.messages,temperature:.1,top_p:1,presence_penalty:0,max_tokens:2e3})});clearTimeout(r);const c=(yield l.json()).choices[0].message.content;return s.saveResponse&&s.saveResponse(c),{question:o,response:c,normalizedResponse:i(c)}}))}(e.config,e.questionElement,t).catch((e=>({error:e}))),l="object"==typeof s&&"error"in s;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||l?"pointer":"initial"),l)console.error(s.error);else switch(e.config.logs&&(r.question(t),r.response(s)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),d(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:s,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:s,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[p,w,h,y,g,v];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;d(e.config,e.gptAnswer)}({config:e.config,gptAnswer:s,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const E=[],S=[];function x(e){const n=S.findIndex((n=>n.element===e));if(-1!==n){const e=S.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function q(n){if(S.length>0){for(const e of S)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(S.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=A.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>x(o)});S.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){E.push(n.key),E.length>e.code.length&&E.shift(),E.join("")===e.code&&(E.length=0,q(e))}))}(n):q(n)}))})); +!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,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(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(s,l)}c((o=o.apply(e,t||[])).next())}))}function n(e,t){const n=e.length>t.length?e.length:t.length;return 0===n?1:(n-function(e,t){if(0===e.length)return t.length;if(0===t.length)return e.length;const n=[],o=e.replace(/\s+/,""),r=t.replace(/\s+/,"");for(let e=0;e<=o.length;++e){n.push([e]);for(let t=1;t<=r.length;++t)n[e][t]=0===e?t:Math.min(n[e-1][t]+1,n[e][t-1]+1,n[e-1][t-1]+(o[e-1]===r[t-1]?0:1))}return n[o.length][r.length]}(e,t))/n}function o(e,t){let o={element:null,similarity:0,value:null};for(const r of t){const t=n(r.value,e);if(1===t)return{element:r.element,value:r.value,similarity:t};t>o.similarity&&(o={element:r.element,value:r.value,similarity:t})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,t){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(t)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,t=!0){t&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: \nexplanation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={role:s.SYSTEM,content:c};function u(e,n,o){return t(this,void 0,void 0,(function*(){const t=n.querySelectorAll("img");if(!e.includeImages||!function(e){const t=e.match(/gpt-(\d+)/);return!!(null==t?void 0:t[1])&&Number(t[1])>=4}(e.model)||0===t.length)return o;const r=[],i=Array.from(t).map((e=>function(e,t=.75){return new Promise(((n,o)=>{const r=document.createElement("canvas"),i=r.getContext("2d");if(!i)return o("Can't get the canvas context, ensure your navigator support canvas"),void r.remove();const s=new Image;s.crossOrigin="Anonymous",s.onload=()=>{r.width=s.width,r.height=s.height,i.drawImage(s,0,0);const e=r.toDataURL("image/png",t);n(e),r.remove()},s.onerror=e=>{o(e),r.remove()},s.src=e.src}))}(e))),s=yield Promise.allSettled(i);for(const t of s)"fulfilled"===t.status?r.push({type:l.IMAGE,image_url:{url:t.value}}):e.logs&&console.error(t.reason);return r.push({type:l.TEXT,text:o}),r}))}function f(e,n,o){return t(this,void 0,void 0,(function*(){const t=yield u(e,n,o),r={role:s.USER,content:t};if(!e.history)return{messages:[a,r]};let i;const l=JSON.parse(null!==(c=sessionStorage.moodleGPTHistory)&&void 0!==c?c:"null");var c;const f=function(){var e,t;const n=new URLSearchParams(document.location.search);return{host:document.location.host,cmid:null!==(e=n.get("cmid"))&&void 0!==e?e:"",attempt:null!==(t=n.get("attempt"))&&void 0!==t?t:"",history:[]}}();return i=null!==l&&function(e,t){const n=["host","cmid","attempt"];for(const o of n)if(e[o]!==t[o])return!1;return!0}(l,f)?l:f,{messages:[a,...i.history,r],saveResponse(t){e.history&&(i.history.push(r),i.history.push({role:s.ASSISTANT,content:t}),sessionStorage.moodleGPTHistory=JSON.stringify(i))}}}))}function d(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,(null==r?void 0:r.length)||0),null!=r?r:""}));t.push(n)}));const r=o.reduce(((e,t)=>e+t))+3*t[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=t.map((e=>"| "+e.map(((e,t)=>e.padEnd(o[t]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function m(t,n){t.title&&e("Copied to clipboard"),navigator.clipboard.writeText(n.response)}function p(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 i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=n.response;return!0}function h(e,t,n){var o,r;const i=t[0];if(1!==t.length||"number"!==i.type)return!1;const s=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(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(t){t.preventDefault(),"Backspace"===t.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function g(e,t,n){const s=null==t?void 0:t[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),c=o(n.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function v(e,t,n){const s=null==t?void 0:t[0];if(!s||"checkbox"!==s.type)return!1;const l=n.normalizedResponse.split("\n"),c=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value));for(const t of l){const n=o(t,c);e.logs&&n.value&&r.bestAnswer(n.value,n.similarity);const i=n.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function y(e,t,n){if(0===t.length||"SELECT"!==t[0].tagName)return!1;const s=n.normalizedResponse.split("\n");e.logs&&r.array(s);for(let n=0;n{var t;return{element:e,value:i(null!==(t=e.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),a=o(s[n],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function w(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){t.preventDefault(),"Backspace"===t.key&&(e=n.response.length+1),e>n.response.length||(o.value=n.response.slice(0,++e))}))}else o.value=n.response;return!0}function A(e){return t(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const n=function(e){let t=e.innerText;const n=e.querySelectorAll(".accesshide");for(const e of n)t=t.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)t=t.replace(e.innerText,"\n"+d(e)+"\n");return i(t,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),s=yield function(e,n,o){return t(this,void 0,void 0,(function*(){const t=new AbortController,r=setTimeout((()=>t.abort()),2e4),s=yield f(e,n,o),l=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:s.messages,temperature:.1,top_p:1,presence_penalty:0,max_tokens:2e3})});clearTimeout(r);const c=(yield l.json()).choices[0].message.content;return"function"==typeof s.saveResponse&&s.saveResponse(c),{question:o,response:c,normalizedResponse:i(c)}}))}(e.config,e.questionElement,n).catch((e=>({error:e}))),l="object"==typeof s&&"error"in s;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||l?"pointer":"initial"),l)console.error(s.error);else switch(e.config.logs&&(r.question(n),r.response(s)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),m(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:s,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const t=e.questionElement;e.removeListener();const n=t.textContent;t.textContent=e.gptAnswer.response,t.style.whiteSpace="pre-wrap";let o=!0;t.addEventListener("click",(function(){t.style.whiteSpace=o?"":"pre-warp",t.textContent=o?n:e.gptAnswer.response,o=!o}))}({gptAnswer:s,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const t=[p,w,h,y,g,v];for(const n of t)if(n(e.config,e.inputList,e.gptAnswer))return;m(e.config,e.gptAnswer)}({config:e.config,gptAnswer:s,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const E=[],S=[];function x(e){const t=S.findIndex((t=>t.element===e));if(-1!==t){const e=S.splice(t,1)[0];e.element.removeEventListener("click",e.fn)}}function q(t){if(S.length>0){for(const e of S)t.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return t.title&&e("Removed"),void(S.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");if(null===o)continue;t.cursor&&(o.style.cursor="pointer");const r=A.bind(null,{config:t,questionElement:o,form:e,inputQuery:n,removeListener:()=>x(o)});S.push({element:o,fn:r}),o.addEventListener("click",r)}t.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const t=e.moodleGPT;if(!t)throw new Error("Please configure MoodleGPT into the extension");t.code?function(e){document.body.addEventListener("keydown",(function(t){E.push(t.key),E.length>e.code.length&&E.shift(),E.join("")===e.code&&(E.length=0,q(e))}))}(t):q(t)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index bb45dfb..718c086 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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/types/message.ts","../src/core/get-content-with-history.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/get-response.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","export enum ROLE {\r\n SYSTEM = 'system',\r\n USER = 'user',\r\n ASSISTANT = 'assistant'\r\n}\r\n\r\nexport enum CONTENT_TYPE {\r\n TEXT = 'text',\r\n IMAGE = 'image_url'\r\n}\r\n\r\nexport type MessageContent =\r\n | string\r\n | Array<\r\n | {\r\n type: CONTENT_TYPE.TEXT;\r\n text: string;\r\n }\r\n | {\r\n type: CONTENT_TYPE.IMAGE;\r\n image_url: { url: string };\r\n }\r\n >;\r\n\r\nexport type Message = {\r\n role: ROLE;\r\n content: MessageContent;\r\n};\r\n","import type Config from '@typing/config';\r\nimport { ROLE, CONTENT_TYPE, type MessageContent, type Message } from '@typing/message';\r\nimport imageToBase64 from '@utils/image-to-base64';\r\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\r\n\r\ntype History = {\r\n url: string | null;\r\n params: Record;\r\n history: { role: ROLE; content: MessageContent }[];\r\n};\r\n\r\nconst INSTRUCTION: string = `\r\nAct as a quiz solver for the best notation with the following rules:\r\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \r\n But for the calculation provide this format 'result: \\nexplanation: '\r\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\r\n- Always reply in the format: '\\n\\n...'.\r\n- Retain only the correct answer(s).\r\n- Maintain the same order for the answers as in the text.\r\n- Retain all text from the answer with its description, content or definition.\r\n- Only provide answers that exactly match the given answer in the text.\r\n- The question always has the correct answer(s), so you should always provide an answer.\r\n- Always respond in the same language as the user's question.\r\n`.trim();\r\n\r\nconst SYSTEM_INSTRUCTION_MESSAGE = {\r\n role: ROLE.SYSTEM,\r\n content: INSTRUCTION\r\n} as const;\r\n\r\n/**\r\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\r\n * @param config\r\n */\r\nasync function getContent(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise {\r\n const imagesElements = questionElement.querySelectorAll('img');\r\n\r\n if (\r\n config.includeImages &&\r\n isGPTModelGreaterOrEqualTo4(config.model) &&\r\n imagesElements.length === 0\r\n ) {\r\n return question;\r\n }\r\n\r\n let content: MessageContent = [];\r\n\r\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\r\n const results = await Promise.all(base64Images);\r\n const filteredResults = results.filter(value => value !== null) as string[];\r\n\r\n for (const result of filteredResults) {\r\n content.push({\r\n type: CONTENT_TYPE.IMAGE,\r\n image_url: { url: result }\r\n });\r\n }\r\n\r\n if (content.length > 0) {\r\n content.push({\r\n type: CONTENT_TYPE.TEXT,\r\n text: question\r\n });\r\n } else {\r\n content = question;\r\n }\r\n\r\n return content;\r\n}\r\n\r\n/**\r\n * Create a new history object from the current page\r\n * @returns\r\n */\r\nfunction createNewHistory(): History {\r\n const url_params = new URLSearchParams(document.location.search).entries();\r\n const params: Record = {};\r\n\r\n for (const [key, value] of url_params) {\r\n if (key === 'page') continue;\r\n params[key] = value;\r\n }\r\n\r\n return {\r\n url: document.location.host,\r\n params,\r\n history: []\r\n };\r\n}\r\n\r\n/**\r\n * Load the past history from the session storage otherwise return the default history object\r\n * @returns\r\n */\r\nfunction loadPastHistory(): History | null {\r\n return JSON.parse(sessionStorage.moodleGPTHistory ?? 'null');\r\n}\r\n\r\n/**\r\n * Check if two history are from the same origin\r\n * @param a\r\n * @param b\r\n * @returns\r\n */\r\nfunction areHistorySameOrigin(a: History, b: History): boolean {\r\n if (a.url !== b.url) return false;\r\n\r\n if (Object.keys(a.params).length !== Object.keys(b.params).length) return false;\r\n\r\n for (const [key, value] of Object.entries(a.params)) {\r\n if (!(key in b.params) || b.params[key] !== value) return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Return the content to send to chatgpt api with history if needed\r\n * @param config\r\n * @param questionElement\r\n * @param question\r\n * @returns\r\n */\r\nasync function getContentWithHistory(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise<{\r\n messages: [typeof SYSTEM_INSTRUCTION_MESSAGE, ...Message[]];\r\n saveResponse?: (response: string) => void;\r\n}> {\r\n const content = await getContent(config, questionElement, question);\r\n const message = { role: ROLE.USER, content };\r\n\r\n if (!config.history) return { messages: [SYSTEM_INSTRUCTION_MESSAGE, message] };\r\n\r\n let history: History;\r\n\r\n const pastHistory: History | null = loadPastHistory();\r\n const newHistory: History = createNewHistory();\r\n\r\n if (pastHistory === null || !areHistorySameOrigin(pastHistory, newHistory)) {\r\n history = newHistory;\r\n } else {\r\n history = pastHistory;\r\n }\r\n\r\n return {\r\n messages: [SYSTEM_INSTRUCTION_MESSAGE, ...history.history, message],\r\n saveResponse(response: string) {\r\n // Register the conversation\r\n if (config.history) {\r\n history.history.push(message);\r\n history.history.push({ role: ROLE.ASSISTANT, content: response });\r\n sessionStorage.moodleGPTHistory = JSON.stringify(history);\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default getContentWithHistory;\r\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @param quality (default: 0.75 -> 75%)\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise {\r\n return new Promise(resolve => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n resolve(null);\r\n canvas.remove();\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png', quality);\r\n resolve(base64);\r\n\r\n canvas.remove();\r\n };\r\n\r\n img.onerror = () => {\r\n resolve(null);\r\n canvas.remove();\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport normalizeText from '@utils/normalize-text';\nimport getContentWithHistory from './get-content-with-history';\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n const contentHandler = await getContentWithHistory(config, questionElement, question);\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: contentHandler.messages,\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 1, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Save the response into the history\n if (contentHandler.saveResponse) contentHandler.saveResponse(response);\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","SYSTEM_INSTRUCTION_MESSAGE","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","base64Images","Array","from","map","imgEl","imageElement","quality","canvas","createElement","ctx","getContext","remove","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","src","imageToBase64","filteredResults","all","filter","type","IMAGE","image_url","url","TEXT","getContentWithHistory","message","USER","history","messages","pastHistory","JSON","parse","_a","sessionStorage","moodleGPTHistory","newHistory","url_params","URLSearchParams","location","search","entries","params","key","host","createNewHistory","a","b","Object","keys","areHistorySameOrigin","saveResponse","ASSISTANT","stringify","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","textContent","max","lineSeparationSize","reduce","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","_b","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","controller","AbortController","timeoutControler","abort","contentHandler","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","getChatGPTResponse","catch","error","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"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","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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/types/message.ts","../src/core/get-content-with-history.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/get-response.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gpt-answer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","export enum ROLE {\r\n SYSTEM = 'system',\r\n USER = 'user',\r\n ASSISTANT = 'assistant'\r\n}\r\n\r\nexport enum CONTENT_TYPE {\r\n TEXT = 'text',\r\n IMAGE = 'image_url'\r\n}\r\n\r\nexport type MessageContent =\r\n | string\r\n | Array<\r\n | {\r\n type: CONTENT_TYPE.TEXT;\r\n text: string;\r\n }\r\n | {\r\n type: CONTENT_TYPE.IMAGE;\r\n image_url: { url: string };\r\n }\r\n >;\r\n\r\nexport type Message = {\r\n role: ROLE;\r\n content: MessageContent;\r\n};\r\n","import type Config from '@typing/config';\r\nimport { ROLE, CONTENT_TYPE, type MessageContent, type Message } from '@typing/message';\r\nimport imageToBase64 from '@utils/image-to-base64';\r\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\r\n\r\n// The attempt and the cmid allow us to identify a quiz\r\ntype History = {\r\n host: string;\r\n cmid: string; // The id of the quiz\r\n attempt: string; // The attempt of the current quiz\r\n history: { role: ROLE; content: MessageContent }[];\r\n};\r\n\r\nconst INSTRUCTION: string = `\r\nAct as a quiz solver for the best notation with the following rules:\r\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \r\n But for the calculation provide this format 'result: \\nexplanation: '\r\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\r\n- Always reply in the format: '\\n\\n...'.\r\n- Retain only the correct answer(s).\r\n- Maintain the same order for the answers as in the text.\r\n- Retain all text from the answer with its description, content or definition.\r\n- Only provide answers that exactly match the given answer in the text.\r\n- The question always has the correct answer(s), so you should always provide an answer.\r\n- Always respond in the same language as the user's question.\r\n`.trim();\r\n\r\nconst SYSTEM_INSTRUCTION_MESSAGE = {\r\n role: ROLE.SYSTEM,\r\n content: INSTRUCTION\r\n} as const satisfies Message;\r\n\r\n/**\r\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\r\n * @param config\r\n */\r\nasync function getContent(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise {\r\n const imagesElements = questionElement.querySelectorAll('img');\r\n\r\n if (\r\n !config.includeImages ||\r\n !isGPTModelGreaterOrEqualTo4(config.model) ||\r\n imagesElements.length === 0\r\n ) {\r\n return question;\r\n }\r\n\r\n const contentWithImages: MessageContent = [];\r\n\r\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\r\n const base64ImagesResolved = await Promise.allSettled(base64Images);\r\n\r\n for (const result of base64ImagesResolved) {\r\n if (result.status === 'fulfilled') {\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.IMAGE,\r\n image_url: { url: result.value }\r\n });\r\n } else if (config.logs) {\r\n console.error(result.reason);\r\n }\r\n }\r\n\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.TEXT,\r\n text: question\r\n });\r\n\r\n return contentWithImages;\r\n}\r\n\r\n/**\r\n * Create a new history object from the current page\r\n * @returns\r\n */\r\nfunction createNewHistory(): History {\r\n const urlParams = new URLSearchParams(document.location.search);\r\n\r\n return {\r\n host: document.location.host,\r\n cmid: urlParams.get('cmid') ?? '',\r\n attempt: urlParams.get('attempt') ?? '',\r\n history: []\r\n };\r\n}\r\n\r\n/**\r\n * Load the past history from the session storage otherwise return the default history object\r\n * @returns\r\n */\r\nfunction loadPastHistory(): History | null {\r\n return JSON.parse(sessionStorage.moodleGPTHistory ?? 'null');\r\n}\r\n\r\n/**\r\n * Check if two history are from the same origin\r\n * @param a\r\n * @param b\r\n * @returns\r\n */\r\nfunction areHistoryFromSameQuiz(a: History, b: History): boolean {\r\n const KEYS_TO_COMPARE: (keyof History)[] = ['host', 'cmid', 'attempt'];\r\n\r\n for (const key of KEYS_TO_COMPARE) {\r\n if (a[key] !== b[key]) return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Return the content to send to chatgpt api with history if needed\r\n * @param config\r\n * @param questionElement\r\n * @param question\r\n * @returns\r\n */\r\nasync function getContentWithHistory(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise<{\r\n messages: [typeof SYSTEM_INSTRUCTION_MESSAGE, ...Message[]];\r\n saveResponse?: (response: string) => void;\r\n}> {\r\n const content = await getContent(config, questionElement, question);\r\n const message = { role: ROLE.USER, content };\r\n\r\n if (!config.history) return { messages: [SYSTEM_INSTRUCTION_MESSAGE, message] };\r\n\r\n let history: History;\r\n\r\n const pastHistory: History | null = loadPastHistory();\r\n const newHistory: History = createNewHistory();\r\n\r\n if (pastHistory === null || !areHistoryFromSameQuiz(pastHistory, newHistory)) {\r\n history = newHistory;\r\n } else {\r\n history = pastHistory;\r\n }\r\n\r\n return {\r\n messages: [SYSTEM_INSTRUCTION_MESSAGE, ...history.history, message],\r\n saveResponse(response: string) {\r\n // Register the conversation\r\n if (config.history) {\r\n history.history.push(message);\r\n history.history.push({ role: ROLE.ASSISTANT, content: response });\r\n sessionStorage.moodleGPTHistory = JSON.stringify(history);\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default getContentWithHistory;\r\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @param quality (default: 0.75 -> 75%)\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n reject(\"Can't get the canvas context, ensure your navigator support canvas\");\r\n canvas.remove();\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png', quality);\r\n resolve(base64);\r\n\r\n canvas.remove();\r\n };\r\n\r\n img.onerror = err => {\r\n reject(err);\r\n canvas.remove();\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport normalizeText from '@utils/normalize-text';\nimport getContentWithHistory from './get-content-with-history';\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n // Get the content to send to chatgpt\n // Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true\n const contentHandler = await getContentWithHistory(config, questionElement, question);\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: contentHandler.messages,\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 1, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Save the response into the history\n if (typeof contentHandler.saveResponse === 'function') contentHandler.saveResponse(response);\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gpt-answer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gpt-answer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","SYSTEM_INSTRUCTION_MESSAGE","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","contentWithImages","base64Images","Array","from","map","imgEl","imageElement","quality","canvas","createElement","ctx","getContext","remove","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","err","src","imageToBase64","base64ImagesResolved","allSettled","status","type","IMAGE","image_url","url","logs","error","reason","TEXT","getContentWithHistory","message","USER","history","messages","pastHistory","JSON","parse","_a","sessionStorage","moodleGPTHistory","newHistory","urlParams","URLSearchParams","location","search","host","cmid","get","attempt","_b","createNewHistory","a","b","KEYS_TO_COMPARE","key","areHistoryFromSameQuiz","saveResponse","ASSISTANT","stringify","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","textContent","max","lineSeparationSize","reduce","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","filter","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","controller","AbortController","timeoutControler","abort","contentHandler","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file diff --git a/src/core/get-content-with-history.ts b/src/core/get-content-with-history.ts index e13408f..635c647 100644 --- a/src/core/get-content-with-history.ts +++ b/src/core/get-content-with-history.ts @@ -3,11 +3,11 @@ import { ROLE, CONTENT_TYPE, type MessageContent, type Message } from '@typing/m import imageToBase64 from '@utils/image-to-base64'; import isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images'; -// @TODO: implement cmid, attempt, effacer choix - +// The attempt and the cmid allow us to identify a quiz type History = { - url: string | null; - params: Record; + host: string; + cmid: string; // The id of the quiz + attempt: string; // The attempt of the current quiz history: { role: ROLE; content: MessageContent }[]; }; @@ -28,7 +28,7 @@ Act as a quiz solver for the best notation with the following rules: const SYSTEM_INSTRUCTION_MESSAGE = { role: ROLE.SYSTEM, content: INSTRUCTION -} as const; +} as const satisfies Message; /** * Get the content to send to ChatGPT API (it allows to includes images if supported) @@ -42,36 +42,35 @@ async function getContent( const imagesElements = questionElement.querySelectorAll('img'); if ( - config.includeImages && - isGPTModelGreaterOrEqualTo4(config.model) && + !config.includeImages || + !isGPTModelGreaterOrEqualTo4(config.model) || imagesElements.length === 0 ) { return question; } - let content: MessageContent = []; + const contentWithImages: MessageContent = []; const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl)); - const results = await Promise.all(base64Images); - const filteredResults = results.filter(value => value !== null) as string[]; + const base64ImagesResolved = await Promise.allSettled(base64Images); - for (const result of filteredResults) { - content.push({ - type: CONTENT_TYPE.IMAGE, - image_url: { url: result } - }); + for (const result of base64ImagesResolved) { + if (result.status === 'fulfilled') { + contentWithImages.push({ + type: CONTENT_TYPE.IMAGE, + image_url: { url: result.value } + }); + } else if (config.logs) { + console.error(result.reason); + } } - if (content.length > 0) { - content.push({ - type: CONTENT_TYPE.TEXT, - text: question - }); - } else { - content = question; - } + contentWithImages.push({ + type: CONTENT_TYPE.TEXT, + text: question + }); - return content; + return contentWithImages; } /** @@ -79,17 +78,12 @@ async function getContent( * @returns */ function createNewHistory(): History { - const url_params = new URLSearchParams(document.location.search).entries(); - const params: Record = {}; - - for (const [key, value] of url_params) { - if (key === 'page') continue; - params[key] = value; - } + const urlParams = new URLSearchParams(document.location.search); return { - url: document.location.host, - params, + host: document.location.host, + cmid: urlParams.get('cmid') ?? '', + attempt: urlParams.get('attempt') ?? '', history: [] }; } @@ -108,13 +102,11 @@ function loadPastHistory(): History | null { * @param b * @returns */ -function areHistorySameOrigin(a: History, b: History): boolean { - if (a.url !== b.url) return false; +function areHistoryFromSameQuiz(a: History, b: History): boolean { + const KEYS_TO_COMPARE: (keyof History)[] = ['host', 'cmid', 'attempt']; - if (Object.keys(a.params).length !== Object.keys(b.params).length) return false; - - for (const [key, value] of Object.entries(a.params)) { - if (!(key in b.params) || b.params[key] !== value) return false; + for (const key of KEYS_TO_COMPARE) { + if (a[key] !== b[key]) return false; } return true; @@ -145,7 +137,7 @@ async function getContentWithHistory( const pastHistory: History | null = loadPastHistory(); const newHistory: History = createNewHistory(); - if (pastHistory === null || !areHistorySameOrigin(pastHistory, newHistory)) { + if (pastHistory === null || !areHistoryFromSameQuiz(pastHistory, newHistory)) { history = newHistory; } else { history = pastHistory; diff --git a/src/core/get-response.ts b/src/core/get-response.ts index 9defdb5..4c54dc5 100644 --- a/src/core/get-response.ts +++ b/src/core/get-response.ts @@ -17,6 +17,8 @@ async function getChatGPTResponse( const controller = new AbortController(); const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000); + // Get the content to send to chatgpt + // Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true const contentHandler = await getContentWithHistory(config, questionElement, question); const req = await fetch('https://api.openai.com/v1/chat/completions', { @@ -43,7 +45,7 @@ async function getChatGPTResponse( const response = rep.choices[0].message.content; // Save the response into the history - if (contentHandler.saveResponse) contentHandler.saveResponse(response); + if (typeof contentHandler.saveResponse === 'function') contentHandler.saveResponse(response); return { question, From 9fe019e2504efb3819597bca7f6fdbe05e6b606e Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 20:58:27 -0400 Subject: [PATCH 60/87] fixed quiz endpoint --- extension/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/manifest.json b/extension/manifest.json index 5617c6d..cd82460 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -18,7 +18,7 @@ "content_scripts": [ { - "matches": ["*://*/**/mod/quiz/*", "*://*/mod/quiz/*", "file:///*"], + "matches": ["*://*/**/mod/quiz/attempt.php*", "*://*/mod/quiz/attempt.php*", "file:///*"], "js": ["MoodleGPT.js"], "run_at": "document_end" } From d24e5255f6aa801f677e66f3dcbb09a9cc918ff5 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 20:58:50 -0400 Subject: [PATCH 61/87] gpt versions are now displayed as a list --- extension/popup/index.html | 8 +----- extension/popup/js/gptVersion.js | 46 +++++++++++++++++--------------- extension/popup/style.css | 7 ++++- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/extension/popup/index.html b/extension/popup/index.html index 34b4612..36da2a1 100644 --- a/extension/popup/index.html +++ b/extension/popup/index.html @@ -47,13 +47,7 @@
- - +
diff --git a/extension/popup/js/gptVersion.js b/extension/popup/js/gptVersion.js index 917c55e..4f566d6 100644 --- a/extension/popup/js/gptVersion.js +++ b/extension/popup/js/gptVersion.js @@ -18,36 +18,22 @@ function checkCanIncludeImages() { modelInput.addEventListener('input', checkCanIncludeImages); /** - * Get the last ChatGPT version + * Get the list of chatgpt versions */ function getLastChatGPTVersion() { const apiKeySelector = document.querySelector('#apiKey'); - const reloadModel = document.querySelector('#reloadModel'); + const selectModel = document.querySelector('#model'); let apiKey = apiKeySelector.value?.trim(); // If the api key is set we enable the button to get the last chatgpt version - function checkFiledApiKey() { - if (apiKey) { - reloadModel.removeAttribute('disabled'); - reloadModel.setAttribute('title', 'Get last ChatGPT version'); + async function getGptVersions() { + if (!apiKey) { + selectModel.setAttribute('disabled', true); return; } - reloadModel.setAttribute('disabled', true); - reloadModel.setAttribute('title', 'Provide an api key first'); - } - checkFiledApiKey(); - - // Check if the api key is set - apiKeySelector.addEventListener('input', function () { - apiKey = apiKeySelector.value.trim(); - checkFiledApiKey(); - }); - - // Event listener to handle a click on the relaod icon button - reloadModel.addEventListener('click', async function () { - if (!apiKey) return; + selectModel.innerHTML = ''; try { const req = await fetch('https://api.openai.com/v1/models', { @@ -57,13 +43,29 @@ function getLastChatGPTVersion() { }); const rep = await req.json(); rep.data.sort((a, b) => b.id.localeCompare(a.id)); // we sort the model to get the best chatgpt version - const model = rep.data.find(model => model.id.startsWith('gpt')); - modelInput.value = model.id; + const models = rep.data.filter(model => model.id.startsWith('gpt')); + + for (const model of models) { + const opt = document.createElement('option'); + opt.value = model.id; + opt.textContent = model.id; + selectModel.appendChild(opt); + } checkCanIncludeImages(); } catch (err) { console.error(err); showMessage({ msg: 'Failed to fetch last ChatGPT version', error: true }); } + + selectModel.removeAttribute('disabled'); + } + + // Check if the api key is set + apiKeySelector.addEventListener('blur', function () { + apiKey = apiKeySelector.value.trim(); + getGptVersions(); }); + + getGptVersions(); } diff --git a/extension/popup/style.css b/extension/popup/style.css index 85b8c39..d44b084 100644 --- a/extension/popup/style.css +++ b/extension/popup/style.css @@ -68,7 +68,8 @@ a { } .line input[type='text'], -.line input[type='password'] { +.line input[type='password'], +.line select { flex: 1 1; border: thin solid var(--color); padding: 0.3rem 0.5rem; @@ -77,6 +78,10 @@ a { background-color: transparent; } +.line option { + color: #000; +} + .line input[type='checkbox'] { accent-color: var(--btn-color); } From c30111150b3a024c2599c20bcfdddc9eb5223f47 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 21:10:06 -0400 Subject: [PATCH 62/87] fixed "clear my choice" message not appearing --- extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- src/core/questions/checkbox.ts | 4 ++-- src/core/questions/radio.ts | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index c5b8e12..1f19ab7 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,2 +1,2 @@ -!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,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(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(s,l)}c((o=o.apply(e,t||[])).next())}))}function n(e,t){const n=e.length>t.length?e.length:t.length;return 0===n?1:(n-function(e,t){if(0===e.length)return t.length;if(0===t.length)return e.length;const n=[],o=e.replace(/\s+/,""),r=t.replace(/\s+/,"");for(let e=0;e<=o.length;++e){n.push([e]);for(let t=1;t<=r.length;++t)n[e][t]=0===e?t:Math.min(n[e-1][t]+1,n[e][t-1]+1,n[e-1][t-1]+(o[e-1]===r[t-1]?0:1))}return n[o.length][r.length]}(e,t))/n}function o(e,t){let o={element:null,similarity:0,value:null};for(const r of t){const t=n(r.value,e);if(1===t)return{element:r.element,value:r.value,similarity:t};t>o.similarity&&(o={element:r.element,value:r.value,similarity:t})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,t){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(t)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,t=!0){t&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: \nexplanation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={role:s.SYSTEM,content:c};function u(e,n,o){return t(this,void 0,void 0,(function*(){const t=n.querySelectorAll("img");if(!e.includeImages||!function(e){const t=e.match(/gpt-(\d+)/);return!!(null==t?void 0:t[1])&&Number(t[1])>=4}(e.model)||0===t.length)return o;const r=[],i=Array.from(t).map((e=>function(e,t=.75){return new Promise(((n,o)=>{const r=document.createElement("canvas"),i=r.getContext("2d");if(!i)return o("Can't get the canvas context, ensure your navigator support canvas"),void r.remove();const s=new Image;s.crossOrigin="Anonymous",s.onload=()=>{r.width=s.width,r.height=s.height,i.drawImage(s,0,0);const e=r.toDataURL("image/png",t);n(e),r.remove()},s.onerror=e=>{o(e),r.remove()},s.src=e.src}))}(e))),s=yield Promise.allSettled(i);for(const t of s)"fulfilled"===t.status?r.push({type:l.IMAGE,image_url:{url:t.value}}):e.logs&&console.error(t.reason);return r.push({type:l.TEXT,text:o}),r}))}function f(e,n,o){return t(this,void 0,void 0,(function*(){const t=yield u(e,n,o),r={role:s.USER,content:t};if(!e.history)return{messages:[a,r]};let i;const l=JSON.parse(null!==(c=sessionStorage.moodleGPTHistory)&&void 0!==c?c:"null");var c;const f=function(){var e,t;const n=new URLSearchParams(document.location.search);return{host:document.location.host,cmid:null!==(e=n.get("cmid"))&&void 0!==e?e:"",attempt:null!==(t=n.get("attempt"))&&void 0!==t?t:"",history:[]}}();return i=null!==l&&function(e,t){const n=["host","cmid","attempt"];for(const o of n)if(e[o]!==t[o])return!1;return!0}(l,f)?l:f,{messages:[a,...i.history,r],saveResponse(t){e.history&&(i.history.push(r),i.history.push({role:s.ASSISTANT,content:t}),sessionStorage.moodleGPTHistory=JSON.stringify(i))}}}))}function d(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,(null==r?void 0:r.length)||0),null!=r?r:""}));t.push(n)}));const r=o.reduce(((e,t)=>e+t))+3*t[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=t.map((e=>"| "+e.map(((e,t)=>e.padEnd(o[t]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function m(t,n){t.title&&e("Copied to clipboard"),navigator.clipboard.writeText(n.response)}function p(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 i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=n.response;return!0}function h(e,t,n){var o,r;const i=t[0];if(1!==t.length||"number"!==i.type)return!1;const s=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(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(t){t.preventDefault(),"Backspace"===t.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function g(e,t,n){const s=null==t?void 0:t[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),c=o(n.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function v(e,t,n){const s=null==t?void 0:t[0];if(!s||"checkbox"!==s.type)return!1;const l=n.normalizedResponse.split("\n"),c=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value));for(const t of l){const n=o(t,c);e.logs&&n.value&&r.bestAnswer(n.value,n.similarity);const i=n.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function y(e,t,n){if(0===t.length||"SELECT"!==t[0].tagName)return!1;const s=n.normalizedResponse.split("\n");e.logs&&r.array(s);for(let n=0;n{var t;return{element:e,value:i(null!==(t=e.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),a=o(s[n],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function w(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){t.preventDefault(),"Backspace"===t.key&&(e=n.response.length+1),e>n.response.length||(o.value=n.response.slice(0,++e))}))}else o.value=n.response;return!0}function A(e){return t(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const n=function(e){let t=e.innerText;const n=e.querySelectorAll(".accesshide");for(const e of n)t=t.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)t=t.replace(e.innerText,"\n"+d(e)+"\n");return i(t,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),s=yield function(e,n,o){return t(this,void 0,void 0,(function*(){const t=new AbortController,r=setTimeout((()=>t.abort()),2e4),s=yield f(e,n,o),l=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:s.messages,temperature:.1,top_p:1,presence_penalty:0,max_tokens:2e3})});clearTimeout(r);const c=(yield l.json()).choices[0].message.content;return"function"==typeof s.saveResponse&&s.saveResponse(c),{question:o,response:c,normalizedResponse:i(c)}}))}(e.config,e.questionElement,n).catch((e=>({error:e}))),l="object"==typeof s&&"error"in s;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||l?"pointer":"initial"),l)console.error(s.error);else switch(e.config.logs&&(r.question(n),r.response(s)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),m(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:s,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const t=e.questionElement;e.removeListener();const n=t.textContent;t.textContent=e.gptAnswer.response,t.style.whiteSpace="pre-wrap";let o=!0;t.addEventListener("click",(function(){t.style.whiteSpace=o?"":"pre-warp",t.textContent=o?n:e.gptAnswer.response,o=!o}))}({gptAnswer:s,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const t=[p,w,h,y,g,v];for(const n of t)if(n(e.config,e.inputList,e.gptAnswer))return;m(e.config,e.gptAnswer)}({config:e.config,gptAnswer:s,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const E=[],S=[];function x(e){const t=S.findIndex((t=>t.element===e));if(-1!==t){const e=S.splice(t,1)[0];e.element.removeEventListener("click",e.fn)}}function q(t){if(S.length>0){for(const e of S)t.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return t.title&&e("Removed"),void(S.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");if(null===o)continue;t.cursor&&(o.style.cursor="pointer");const r=A.bind(null,{config:t,questionElement:o,form:e,inputQuery:n,removeListener:()=>x(o)});S.push({element:o,fn:r}),o.addEventListener("click",r)}t.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const t=e.moodleGPT;if(!t)throw new Error("Please configure MoodleGPT into the extension");t.code?function(e){document.body.addEventListener("keydown",(function(t){E.push(t.key),E.length>e.code.length&&E.shift(),E.join("")===e.code&&(E.length=0,q(e))}))}(t):q(t)}))})); +!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,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(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(s,l)}c((o=o.apply(e,t||[])).next())}))}function n(e,t){const n=e.length>t.length?e.length:t.length;return 0===n?1:(n-function(e,t){if(0===e.length)return t.length;if(0===t.length)return e.length;const n=[],o=e.replace(/\s+/,""),r=t.replace(/\s+/,"");for(let e=0;e<=o.length;++e){n.push([e]);for(let t=1;t<=r.length;++t)n[e][t]=0===e?t:Math.min(n[e-1][t]+1,n[e][t-1]+1,n[e-1][t-1]+(o[e-1]===r[t-1]?0:1))}return n[o.length][r.length]}(e,t))/n}function o(e,t){let o={element:null,similarity:0,value:null};for(const r of t){const t=n(r.value,e);if(1===t)return{element:r.element,value:r.value,similarity:t};t>o.similarity&&(o={element:r.element,value:r.value,similarity:t})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,t){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(t)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,t=!0){t&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: \nexplanation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={role:s.SYSTEM,content:c};function u(e,n,o){return t(this,void 0,void 0,(function*(){const t=n.querySelectorAll("img");if(!e.includeImages||!function(e){const t=e.match(/gpt-(\d+)/);return!!(null==t?void 0:t[1])&&Number(t[1])>=4}(e.model)||0===t.length)return o;const r=[],i=Array.from(t).map((e=>function(e,t=.75){return new Promise(((n,o)=>{const r=document.createElement("canvas"),i=r.getContext("2d");if(!i)return o("Can't get the canvas context, ensure your navigator support canvas"),void r.remove();const s=new Image;s.crossOrigin="Anonymous",s.onload=()=>{r.width=s.width,r.height=s.height,i.drawImage(s,0,0);const e=r.toDataURL("image/png",t);n(e),r.remove()},s.onerror=e=>{o(e),r.remove()},s.src=e.src}))}(e))),s=yield Promise.allSettled(i);for(const t of s)"fulfilled"===t.status?r.push({type:l.IMAGE,image_url:{url:t.value}}):e.logs&&console.error(t.reason);return r.push({type:l.TEXT,text:o}),r}))}function f(e,n,o){return t(this,void 0,void 0,(function*(){const t=yield u(e,n,o),r={role:s.USER,content:t};if(!e.history)return{messages:[a,r]};let i;const l=JSON.parse(null!==(c=sessionStorage.moodleGPTHistory)&&void 0!==c?c:"null");var c;const f=function(){var e,t;const n=new URLSearchParams(document.location.search);return{host:document.location.host,cmid:null!==(e=n.get("cmid"))&&void 0!==e?e:"",attempt:null!==(t=n.get("attempt"))&&void 0!==t?t:"",history:[]}}();return i=null!==l&&function(e,t){const n=["host","cmid","attempt"];for(const o of n)if(e[o]!==t[o])return!1;return!0}(l,f)?l:f,{messages:[a,...i.history,r],saveResponse(t){e.history&&(i.history.push(r),i.history.push({role:s.ASSISTANT,content:t}),sessionStorage.moodleGPTHistory=JSON.stringify(i))}}}))}function m(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,(null==r?void 0:r.length)||0),null!=r?r:""}));t.push(n)}));const r=o.reduce(((e,t)=>e+t))+3*t[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=t.map((e=>"| "+e.map(((e,t)=>e.padEnd(o[t]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function d(t,n){t.title&&e("Copied to clipboard"),navigator.clipboard.writeText(n.response)}function p(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 i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=n.response;return!0}function g(e,t,n){var o,r;const i=t[0];if(1!==t.length||"number"!==i.type)return!1;const s=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(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(t){t.preventDefault(),"Backspace"===t.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function h(e,t,n){const s=null==t?void 0:t[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),c=o(n.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.click()),{once:!0}):a.click(),!0}function v(e,t,n){const s=null==t?void 0:t[0];if(!s||"checkbox"!==s.type)return!1;const l=n.normalizedResponse.split("\n"),c=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value));for(const t of l){const n=o(t,c);e.logs&&n.value&&r.bestAnswer(n.value,n.similarity);const i=n.element;e.mouseover?i.addEventListener("mouseover",(()=>i.click()),{once:!0}):i.click()}return!0}function y(e,t,n){if(0===t.length||"SELECT"!==t[0].tagName)return!1;const s=n.normalizedResponse.split("\n");e.logs&&r.array(s);for(let n=0;n{var t;return{element:e,value:i(null!==(t=e.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),a=o(s[n],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function w(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){t.preventDefault(),"Backspace"===t.key&&(e=n.response.length+1),e>n.response.length||(o.value=n.response.slice(0,++e))}))}else o.value=n.response;return!0}function A(e){return t(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const n=function(e){let t=e.innerText;const n=e.querySelectorAll(".accesshide");for(const e of n)t=t.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)t=t.replace(e.innerText,"\n"+m(e)+"\n");return i(t,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),s=yield function(e,n,o){return t(this,void 0,void 0,(function*(){const t=new AbortController,r=setTimeout((()=>t.abort()),2e4),s=yield f(e,n,o),l=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:s.messages,temperature:.1,top_p:1,presence_penalty:0,max_tokens:2e3})});clearTimeout(r);const c=(yield l.json()).choices[0].message.content;return"function"==typeof s.saveResponse&&s.saveResponse(c),{question:o,response:c,normalizedResponse:i(c)}}))}(e.config,e.questionElement,n).catch((e=>({error:e}))),l="object"==typeof s&&"error"in s;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||l?"pointer":"initial"),l)console.error(s.error);else switch(e.config.logs&&(r.question(n),r.response(s)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),d(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:s,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const t=e.questionElement;e.removeListener();const n=t.textContent;t.textContent=e.gptAnswer.response,t.style.whiteSpace="pre-wrap";let o=!0;t.addEventListener("click",(function(){t.style.whiteSpace=o?"":"pre-warp",t.textContent=o?n:e.gptAnswer.response,o=!o}))}({gptAnswer:s,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const t=[p,w,g,y,h,v];for(const n of t)if(n(e.config,e.inputList,e.gptAnswer))return;d(e.config,e.gptAnswer)}({config:e.config,gptAnswer:s,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const E=[],S=[];function x(e){const t=S.findIndex((t=>t.element===e));if(-1!==t){const e=S.splice(t,1)[0];e.element.removeEventListener("click",e.fn)}}function q(t){if(S.length>0){for(const e of S)t.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return t.title&&e("Removed"),void(S.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");if(null===o)continue;t.cursor&&(o.style.cursor="pointer");const r=A.bind(null,{config:t,questionElement:o,form:e,inputQuery:n,removeListener:()=>x(o)});S.push({element:o,fn:r}),o.addEventListener("click",r)}t.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const t=e.moodleGPT;if(!t)throw new Error("Please configure MoodleGPT into the extension");t.code?function(e){document.body.addEventListener("keydown",(function(t){E.push(t.key),E.length>e.code.length&&E.shift(),E.join("")===e.code&&(E.length=0,q(e))}))}(t):q(t)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index 718c086..e8a6916 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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/types/message.ts","../src/core/get-content-with-history.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/get-response.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gpt-answer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","export enum ROLE {\r\n SYSTEM = 'system',\r\n USER = 'user',\r\n ASSISTANT = 'assistant'\r\n}\r\n\r\nexport enum CONTENT_TYPE {\r\n TEXT = 'text',\r\n IMAGE = 'image_url'\r\n}\r\n\r\nexport type MessageContent =\r\n | string\r\n | Array<\r\n | {\r\n type: CONTENT_TYPE.TEXT;\r\n text: string;\r\n }\r\n | {\r\n type: CONTENT_TYPE.IMAGE;\r\n image_url: { url: string };\r\n }\r\n >;\r\n\r\nexport type Message = {\r\n role: ROLE;\r\n content: MessageContent;\r\n};\r\n","import type Config from '@typing/config';\r\nimport { ROLE, CONTENT_TYPE, type MessageContent, type Message } from '@typing/message';\r\nimport imageToBase64 from '@utils/image-to-base64';\r\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\r\n\r\n// The attempt and the cmid allow us to identify a quiz\r\ntype History = {\r\n host: string;\r\n cmid: string; // The id of the quiz\r\n attempt: string; // The attempt of the current quiz\r\n history: { role: ROLE; content: MessageContent }[];\r\n};\r\n\r\nconst INSTRUCTION: string = `\r\nAct as a quiz solver for the best notation with the following rules:\r\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \r\n But for the calculation provide this format 'result: \\nexplanation: '\r\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\r\n- Always reply in the format: '\\n\\n...'.\r\n- Retain only the correct answer(s).\r\n- Maintain the same order for the answers as in the text.\r\n- Retain all text from the answer with its description, content or definition.\r\n- Only provide answers that exactly match the given answer in the text.\r\n- The question always has the correct answer(s), so you should always provide an answer.\r\n- Always respond in the same language as the user's question.\r\n`.trim();\r\n\r\nconst SYSTEM_INSTRUCTION_MESSAGE = {\r\n role: ROLE.SYSTEM,\r\n content: INSTRUCTION\r\n} as const satisfies Message;\r\n\r\n/**\r\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\r\n * @param config\r\n */\r\nasync function getContent(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise {\r\n const imagesElements = questionElement.querySelectorAll('img');\r\n\r\n if (\r\n !config.includeImages ||\r\n !isGPTModelGreaterOrEqualTo4(config.model) ||\r\n imagesElements.length === 0\r\n ) {\r\n return question;\r\n }\r\n\r\n const contentWithImages: MessageContent = [];\r\n\r\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\r\n const base64ImagesResolved = await Promise.allSettled(base64Images);\r\n\r\n for (const result of base64ImagesResolved) {\r\n if (result.status === 'fulfilled') {\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.IMAGE,\r\n image_url: { url: result.value }\r\n });\r\n } else if (config.logs) {\r\n console.error(result.reason);\r\n }\r\n }\r\n\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.TEXT,\r\n text: question\r\n });\r\n\r\n return contentWithImages;\r\n}\r\n\r\n/**\r\n * Create a new history object from the current page\r\n * @returns\r\n */\r\nfunction createNewHistory(): History {\r\n const urlParams = new URLSearchParams(document.location.search);\r\n\r\n return {\r\n host: document.location.host,\r\n cmid: urlParams.get('cmid') ?? '',\r\n attempt: urlParams.get('attempt') ?? '',\r\n history: []\r\n };\r\n}\r\n\r\n/**\r\n * Load the past history from the session storage otherwise return the default history object\r\n * @returns\r\n */\r\nfunction loadPastHistory(): History | null {\r\n return JSON.parse(sessionStorage.moodleGPTHistory ?? 'null');\r\n}\r\n\r\n/**\r\n * Check if two history are from the same origin\r\n * @param a\r\n * @param b\r\n * @returns\r\n */\r\nfunction areHistoryFromSameQuiz(a: History, b: History): boolean {\r\n const KEYS_TO_COMPARE: (keyof History)[] = ['host', 'cmid', 'attempt'];\r\n\r\n for (const key of KEYS_TO_COMPARE) {\r\n if (a[key] !== b[key]) return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Return the content to send to chatgpt api with history if needed\r\n * @param config\r\n * @param questionElement\r\n * @param question\r\n * @returns\r\n */\r\nasync function getContentWithHistory(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise<{\r\n messages: [typeof SYSTEM_INSTRUCTION_MESSAGE, ...Message[]];\r\n saveResponse?: (response: string) => void;\r\n}> {\r\n const content = await getContent(config, questionElement, question);\r\n const message = { role: ROLE.USER, content };\r\n\r\n if (!config.history) return { messages: [SYSTEM_INSTRUCTION_MESSAGE, message] };\r\n\r\n let history: History;\r\n\r\n const pastHistory: History | null = loadPastHistory();\r\n const newHistory: History = createNewHistory();\r\n\r\n if (pastHistory === null || !areHistoryFromSameQuiz(pastHistory, newHistory)) {\r\n history = newHistory;\r\n } else {\r\n history = pastHistory;\r\n }\r\n\r\n return {\r\n messages: [SYSTEM_INSTRUCTION_MESSAGE, ...history.history, message],\r\n saveResponse(response: string) {\r\n // Register the conversation\r\n if (config.history) {\r\n history.history.push(message);\r\n history.history.push({ role: ROLE.ASSISTANT, content: response });\r\n sessionStorage.moodleGPTHistory = JSON.stringify(history);\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default getContentWithHistory;\r\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @param quality (default: 0.75 -> 75%)\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n reject(\"Can't get the canvas context, ensure your navigator support canvas\");\r\n canvas.remove();\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png', quality);\r\n resolve(base64);\r\n\r\n canvas.remove();\r\n };\r\n\r\n img.onerror = err => {\r\n reject(err);\r\n canvas.remove();\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport normalizeText from '@utils/normalize-text';\nimport getContentWithHistory from './get-content-with-history';\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n // Get the content to send to chatgpt\n // Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true\n const contentHandler = await getContentWithHistory(config, questionElement, question);\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: contentHandler.messages,\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 1, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Save the response into the history\n if (typeof contentHandler.saveResponse === 'function') contentHandler.saveResponse(response);\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gpt-answer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gpt-answer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","SYSTEM_INSTRUCTION_MESSAGE","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","contentWithImages","base64Images","Array","from","map","imgEl","imageElement","quality","canvas","createElement","ctx","getContext","remove","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","err","src","imageToBase64","base64ImagesResolved","allSettled","status","type","IMAGE","image_url","url","logs","error","reason","TEXT","getContentWithHistory","message","USER","history","messages","pastHistory","JSON","parse","_a","sessionStorage","moodleGPTHistory","newHistory","urlParams","URLSearchParams","location","search","host","cmid","get","attempt","_b","createNewHistory","a","b","KEYS_TO_COMPARE","key","areHistoryFromSameQuiz","saveResponse","ASSISTANT","stringify","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","textContent","max","lineSeparationSize","reduce","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","filter","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","controller","AbortController","timeoutControler","abort","contentHandler","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","moodleGPT","Error","code","codeListener"],"mappings":"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","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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/types/message.ts","../src/core/get-content-with-history.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/get-response.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gpt-answer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","export enum ROLE {\r\n SYSTEM = 'system',\r\n USER = 'user',\r\n ASSISTANT = 'assistant'\r\n}\r\n\r\nexport enum CONTENT_TYPE {\r\n TEXT = 'text',\r\n IMAGE = 'image_url'\r\n}\r\n\r\nexport type MessageContent =\r\n | string\r\n | Array<\r\n | {\r\n type: CONTENT_TYPE.TEXT;\r\n text: string;\r\n }\r\n | {\r\n type: CONTENT_TYPE.IMAGE;\r\n image_url: { url: string };\r\n }\r\n >;\r\n\r\nexport type Message = {\r\n role: ROLE;\r\n content: MessageContent;\r\n};\r\n","import type Config from '@typing/config';\r\nimport { ROLE, CONTENT_TYPE, type MessageContent, type Message } from '@typing/message';\r\nimport imageToBase64 from '@utils/image-to-base64';\r\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\r\n\r\n// The attempt and the cmid allow us to identify a quiz\r\ntype History = {\r\n host: string;\r\n cmid: string; // The id of the quiz\r\n attempt: string; // The attempt of the current quiz\r\n history: { role: ROLE; content: MessageContent }[];\r\n};\r\n\r\nconst INSTRUCTION: string = `\r\nAct as a quiz solver for the best notation with the following rules:\r\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \r\n But for the calculation provide this format 'result: \\nexplanation: '\r\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\r\n- Always reply in the format: '\\n\\n...'.\r\n- Retain only the correct answer(s).\r\n- Maintain the same order for the answers as in the text.\r\n- Retain all text from the answer with its description, content or definition.\r\n- Only provide answers that exactly match the given answer in the text.\r\n- The question always has the correct answer(s), so you should always provide an answer.\r\n- Always respond in the same language as the user's question.\r\n`.trim();\r\n\r\nconst SYSTEM_INSTRUCTION_MESSAGE = {\r\n role: ROLE.SYSTEM,\r\n content: INSTRUCTION\r\n} as const satisfies Message;\r\n\r\n/**\r\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\r\n * @param config\r\n */\r\nasync function getContent(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise {\r\n const imagesElements = questionElement.querySelectorAll('img');\r\n\r\n if (\r\n !config.includeImages ||\r\n !isGPTModelGreaterOrEqualTo4(config.model) ||\r\n imagesElements.length === 0\r\n ) {\r\n return question;\r\n }\r\n\r\n const contentWithImages: MessageContent = [];\r\n\r\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\r\n const base64ImagesResolved = await Promise.allSettled(base64Images);\r\n\r\n for (const result of base64ImagesResolved) {\r\n if (result.status === 'fulfilled') {\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.IMAGE,\r\n image_url: { url: result.value }\r\n });\r\n } else if (config.logs) {\r\n console.error(result.reason);\r\n }\r\n }\r\n\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.TEXT,\r\n text: question\r\n });\r\n\r\n return contentWithImages;\r\n}\r\n\r\n/**\r\n * Create a new history object from the current page\r\n * @returns\r\n */\r\nfunction createNewHistory(): History {\r\n const urlParams = new URLSearchParams(document.location.search);\r\n\r\n return {\r\n host: document.location.host,\r\n cmid: urlParams.get('cmid') ?? '',\r\n attempt: urlParams.get('attempt') ?? '',\r\n history: []\r\n };\r\n}\r\n\r\n/**\r\n * Load the past history from the session storage otherwise return the default history object\r\n * @returns\r\n */\r\nfunction loadPastHistory(): History | null {\r\n return JSON.parse(sessionStorage.moodleGPTHistory ?? 'null');\r\n}\r\n\r\n/**\r\n * Check if two history are from the same origin\r\n * @param a\r\n * @param b\r\n * @returns\r\n */\r\nfunction areHistoryFromSameQuiz(a: History, b: History): boolean {\r\n const KEYS_TO_COMPARE: (keyof History)[] = ['host', 'cmid', 'attempt'];\r\n\r\n for (const key of KEYS_TO_COMPARE) {\r\n if (a[key] !== b[key]) return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Return the content to send to chatgpt api with history if needed\r\n * @param config\r\n * @param questionElement\r\n * @param question\r\n * @returns\r\n */\r\nasync function getContentWithHistory(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise<{\r\n messages: [typeof SYSTEM_INSTRUCTION_MESSAGE, ...Message[]];\r\n saveResponse?: (response: string) => void;\r\n}> {\r\n const content = await getContent(config, questionElement, question);\r\n const message = { role: ROLE.USER, content };\r\n\r\n if (!config.history) return { messages: [SYSTEM_INSTRUCTION_MESSAGE, message] };\r\n\r\n let history: History;\r\n\r\n const pastHistory: History | null = loadPastHistory();\r\n const newHistory: History = createNewHistory();\r\n\r\n if (pastHistory === null || !areHistoryFromSameQuiz(pastHistory, newHistory)) {\r\n history = newHistory;\r\n } else {\r\n history = pastHistory;\r\n }\r\n\r\n return {\r\n messages: [SYSTEM_INSTRUCTION_MESSAGE, ...history.history, message],\r\n saveResponse(response: string) {\r\n // Register the conversation\r\n if (config.history) {\r\n history.history.push(message);\r\n history.history.push({ role: ROLE.ASSISTANT, content: response });\r\n sessionStorage.moodleGPTHistory = JSON.stringify(history);\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default getContentWithHistory;\r\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @param quality (default: 0.75 -> 75%)\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n reject(\"Can't get the canvas context, ensure your navigator support canvas\");\r\n canvas.remove();\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png', quality);\r\n resolve(base64);\r\n\r\n canvas.remove();\r\n };\r\n\r\n img.onerror = err => {\r\n reject(err);\r\n canvas.remove();\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport normalizeText from '@utils/normalize-text';\nimport getContentWithHistory from './get-content-with-history';\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n // Get the content to send to chatgpt\n // Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true\n const contentHandler = await getContentWithHistory(config, questionElement, question);\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: contentHandler.messages,\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 1, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Save the response into the history\n if (typeof contentHandler.saveResponse === 'function') contentHandler.saveResponse(response);\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gpt-answer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gpt-answer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","SYSTEM_INSTRUCTION_MESSAGE","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","contentWithImages","base64Images","Array","from","map","imgEl","imageElement","quality","canvas","createElement","ctx","getContext","remove","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","err","src","imageToBase64","base64ImagesResolved","allSettled","status","type","IMAGE","image_url","url","logs","error","reason","TEXT","getContentWithHistory","message","USER","history","messages","pastHistory","JSON","parse","_a","sessionStorage","moodleGPTHistory","newHistory","urlParams","URLSearchParams","location","search","host","cmid","get","attempt","_b","createNewHistory","a","b","KEYS_TO_COMPARE","key","areHistoryFromSameQuiz","saveResponse","ASSISTANT","stringify","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","textContent","max","lineSeparationSize","reduce","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","filter","correctInput","mouseover","click","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","controller","AbortController","timeoutControler","abort","contentHandler","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file diff --git a/src/core/questions/checkbox.ts b/src/core/questions/checkbox.ts index 7764191..f6c7ed3 100644 --- a/src/core/questions/checkbox.ts +++ b/src/core/questions/checkbox.ts @@ -40,11 +40,11 @@ function handleCheckbox( const correctInput = bestAnswer.element as HTMLInputElement; if (config.mouseover) { - correctInput.addEventListener('mouseover', () => (correctInput.checked = true), { + correctInput.addEventListener('mouseover', () => correctInput.click(), { once: true }); } else { - correctInput.checked = true; + correctInput.click(); } } diff --git a/src/core/questions/radio.ts b/src/core/questions/radio.ts index 9c31561..d27fef2 100644 --- a/src/core/questions/radio.ts +++ b/src/core/questions/radio.ts @@ -37,11 +37,11 @@ function handleRadio( const correctInput = bestAnswer.element as HTMLInputElement; if (config.mouseover) { - correctInput.addEventListener('mouseover', () => (correctInput.checked = true), { + correctInput.addEventListener('mouseover', () => correctInput.click(), { once: true }); } else { - correctInput.checked = true; + correctInput.click(); } return true; From 6e17d2cb35dbf366c16b26f64f576022fe34b445 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 21:17:12 -0400 Subject: [PATCH 63/87] Historic implemented and clear my choice message done --- TODO.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/TODO.md b/TODO.md index 86366e7..d8ccb5d 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,5 @@ # TODO -- Fixe select mouse hover and add "clean my choice" when selecting answer -- Historic for questions - Better prompt (Fixe put in order question, Fixe calculation question) - Better webstore assets - Do some tests From ecfae43d8a81985ae7b096e5d4bcca489b493b86 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 21:57:28 -0400 Subject: [PATCH 64/87] better prompt and removed useless option --- extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- src/core/get-content-with-history.ts | 4 ++-- src/core/get-response.ts | 2 +- src/core/questions/select.ts | 1 + 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index 1f19ab7..c918fba 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,2 +1,2 @@ -!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,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(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(s,l)}c((o=o.apply(e,t||[])).next())}))}function n(e,t){const n=e.length>t.length?e.length:t.length;return 0===n?1:(n-function(e,t){if(0===e.length)return t.length;if(0===t.length)return e.length;const n=[],o=e.replace(/\s+/,""),r=t.replace(/\s+/,"");for(let e=0;e<=o.length;++e){n.push([e]);for(let t=1;t<=r.length;++t)n[e][t]=0===e?t:Math.min(n[e-1][t]+1,n[e][t-1]+1,n[e-1][t-1]+(o[e-1]===r[t-1]?0:1))}return n[o.length][r.length]}(e,t))/n}function o(e,t){let o={element:null,similarity:0,value:null};for(const r of t){const t=n(r.value,e);if(1===t)return{element:r.element,value:r.value,similarity:t};t>o.similarity&&(o={element:r.element,value:r.value,similarity:t})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,t){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(t)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,t=!0){t&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: \nexplanation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={role:s.SYSTEM,content:c};function u(e,n,o){return t(this,void 0,void 0,(function*(){const t=n.querySelectorAll("img");if(!e.includeImages||!function(e){const t=e.match(/gpt-(\d+)/);return!!(null==t?void 0:t[1])&&Number(t[1])>=4}(e.model)||0===t.length)return o;const r=[],i=Array.from(t).map((e=>function(e,t=.75){return new Promise(((n,o)=>{const r=document.createElement("canvas"),i=r.getContext("2d");if(!i)return o("Can't get the canvas context, ensure your navigator support canvas"),void r.remove();const s=new Image;s.crossOrigin="Anonymous",s.onload=()=>{r.width=s.width,r.height=s.height,i.drawImage(s,0,0);const e=r.toDataURL("image/png",t);n(e),r.remove()},s.onerror=e=>{o(e),r.remove()},s.src=e.src}))}(e))),s=yield Promise.allSettled(i);for(const t of s)"fulfilled"===t.status?r.push({type:l.IMAGE,image_url:{url:t.value}}):e.logs&&console.error(t.reason);return r.push({type:l.TEXT,text:o}),r}))}function f(e,n,o){return t(this,void 0,void 0,(function*(){const t=yield u(e,n,o),r={role:s.USER,content:t};if(!e.history)return{messages:[a,r]};let i;const l=JSON.parse(null!==(c=sessionStorage.moodleGPTHistory)&&void 0!==c?c:"null");var c;const f=function(){var e,t;const n=new URLSearchParams(document.location.search);return{host:document.location.host,cmid:null!==(e=n.get("cmid"))&&void 0!==e?e:"",attempt:null!==(t=n.get("attempt"))&&void 0!==t?t:"",history:[]}}();return i=null!==l&&function(e,t){const n=["host","cmid","attempt"];for(const o of n)if(e[o]!==t[o])return!1;return!0}(l,f)?l:f,{messages:[a,...i.history,r],saveResponse(t){e.history&&(i.history.push(r),i.history.push({role:s.ASSISTANT,content:t}),sessionStorage.moodleGPTHistory=JSON.stringify(i))}}}))}function m(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,(null==r?void 0:r.length)||0),null!=r?r:""}));t.push(n)}));const r=o.reduce(((e,t)=>e+t))+3*t[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=t.map((e=>"| "+e.map(((e,t)=>e.padEnd(o[t]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function d(t,n){t.title&&e("Copied to clipboard"),navigator.clipboard.writeText(n.response)}function p(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 i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=n.response;return!0}function g(e,t,n){var o,r;const i=t[0];if(1!==t.length||"number"!==i.type)return!1;const s=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(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(t){t.preventDefault(),"Backspace"===t.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function h(e,t,n){const s=null==t?void 0:t[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),c=o(n.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.click()),{once:!0}):a.click(),!0}function v(e,t,n){const s=null==t?void 0:t[0];if(!s||"checkbox"!==s.type)return!1;const l=n.normalizedResponse.split("\n"),c=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value));for(const t of l){const n=o(t,c);e.logs&&n.value&&r.bestAnswer(n.value,n.similarity);const i=n.element;e.mouseover?i.addEventListener("mouseover",(()=>i.click()),{once:!0}):i.click()}return!0}function y(e,t,n){if(0===t.length||"SELECT"!==t[0].tagName)return!1;const s=n.normalizedResponse.split("\n");e.logs&&r.array(s);for(let n=0;n{var t;return{element:e,value:i(null!==(t=e.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),a=o(s[n],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function w(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){t.preventDefault(),"Backspace"===t.key&&(e=n.response.length+1),e>n.response.length||(o.value=n.response.slice(0,++e))}))}else o.value=n.response;return!0}function A(e){return t(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const n=function(e){let t=e.innerText;const n=e.querySelectorAll(".accesshide");for(const e of n)t=t.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)t=t.replace(e.innerText,"\n"+m(e)+"\n");return i(t,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),s=yield function(e,n,o){return t(this,void 0,void 0,(function*(){const t=new AbortController,r=setTimeout((()=>t.abort()),2e4),s=yield f(e,n,o),l=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:s.messages,temperature:.1,top_p:1,presence_penalty:0,max_tokens:2e3})});clearTimeout(r);const c=(yield l.json()).choices[0].message.content;return"function"==typeof s.saveResponse&&s.saveResponse(c),{question:o,response:c,normalizedResponse:i(c)}}))}(e.config,e.questionElement,n).catch((e=>({error:e}))),l="object"==typeof s&&"error"in s;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||l?"pointer":"initial"),l)console.error(s.error);else switch(e.config.logs&&(r.question(n),r.response(s)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),d(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:s,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const t=e.questionElement;e.removeListener();const n=t.textContent;t.textContent=e.gptAnswer.response,t.style.whiteSpace="pre-wrap";let o=!0;t.addEventListener("click",(function(){t.style.whiteSpace=o?"":"pre-warp",t.textContent=o?n:e.gptAnswer.response,o=!o}))}({gptAnswer:s,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const t=[p,w,g,y,h,v];for(const n of t)if(n(e.config,e.inputList,e.gptAnswer))return;d(e.config,e.gptAnswer)}({config:e.config,gptAnswer:s,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const E=[],S=[];function x(e){const t=S.findIndex((t=>t.element===e));if(-1!==t){const e=S.splice(t,1)[0];e.element.removeEventListener("click",e.fn)}}function q(t){if(S.length>0){for(const e of S)t.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return t.title&&e("Removed"),void(S.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");if(null===o)continue;t.cursor&&(o.style.cursor="pointer");const r=A.bind(null,{config:t,questionElement:o,form:e,inputQuery:n,removeListener:()=>x(o)});S.push({element:o,fn:r}),o.addEventListener("click",r)}t.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const t=e.moodleGPT;if(!t)throw new Error("Please configure MoodleGPT into the extension");t.code?function(e){document.body.addEventListener("keydown",(function(t){E.push(t.key),E.length>e.code.length&&E.shift(),E.join("")===e.code&&(E.length=0,q(e))}))}(t):q(t)}))})); +!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,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(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(s,l)}c((o=o.apply(e,t||[])).next())}))}function n(e,t){const n=e.length>t.length?e.length:t.length;return 0===n?1:(n-function(e,t){if(0===e.length)return t.length;if(0===t.length)return e.length;const n=[],o=e.replace(/\s+/,""),r=t.replace(/\s+/,"");for(let e=0;e<=o.length;++e){n.push([e]);for(let t=1;t<=r.length;++t)n[e][t]=0===e?t:Math.min(n[e-1][t]+1,n[e][t-1]+1,n[e-1][t-1]+(o[e-1]===r[t-1]?0:1))}return n[o.length][r.length]}(e,t))/n}function o(e,t){let o={element:null,similarity:0,value:null};for(const r of t){const t=n(r.value,e);if(1===t)return{element:r.element,value:r.value,similarity:t};t>o.similarity&&(o={element:r.element,value:r.value,similarity:t})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,t){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(t)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,t=!0){t&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n- But for the calculation provide this format 'result: '\n- For 'put in order' questions, maintain the answer in the order as presented in the question but assocy the correct order to it by usin this format ':\n:', ignore other rules.\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={role:s.SYSTEM,content:c};function u(e,n,o){return t(this,void 0,void 0,(function*(){const t=n.querySelectorAll("img");if(!e.includeImages||!function(e){const t=e.match(/gpt-(\d+)/);return!!(null==t?void 0:t[1])&&Number(t[1])>=4}(e.model)||0===t.length)return o;const r=[],i=Array.from(t).map((e=>function(e,t=.75){return new Promise(((n,o)=>{const r=document.createElement("canvas"),i=r.getContext("2d");if(!i)return o("Can't get the canvas context, ensure your navigator support canvas"),void r.remove();const s=new Image;s.crossOrigin="Anonymous",s.onload=()=>{r.width=s.width,r.height=s.height,i.drawImage(s,0,0);const e=r.toDataURL("image/png",t);n(e),r.remove()},s.onerror=e=>{o(e),r.remove()},s.src=e.src}))}(e))),s=yield Promise.allSettled(i);for(const t of s)"fulfilled"===t.status?r.push({type:l.IMAGE,image_url:{url:t.value}}):e.logs&&console.error(t.reason);return r.push({type:l.TEXT,text:o}),r}))}function f(e,n,o){return t(this,void 0,void 0,(function*(){const t=yield u(e,n,o),r={role:s.USER,content:t};if(!e.history)return{messages:[a,r]};let i;const l=JSON.parse(null!==(c=sessionStorage.moodleGPTHistory)&&void 0!==c?c:"null");var c;const f=function(){var e,t;const n=new URLSearchParams(document.location.search);return{host:document.location.host,cmid:null!==(e=n.get("cmid"))&&void 0!==e?e:"",attempt:null!==(t=n.get("attempt"))&&void 0!==t?t:"",history:[]}}();return i=null!==l&&function(e,t){const n=["host","cmid","attempt"];for(const o of n)if(e[o]!==t[o])return!1;return!0}(l,f)?l:f,{messages:[a,...i.history,r],saveResponse(t){e.history&&(i.history.push(r),i.history.push({role:s.ASSISTANT,content:t}),sessionStorage.moodleGPTHistory=JSON.stringify(i))}}}))}function m(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,(null==r?void 0:r.length)||0),null!=r?r:""}));t.push(n)}));const r=o.reduce(((e,t)=>e+t))+3*t[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=t.map((e=>"| "+e.map(((e,t)=>e.padEnd(o[t]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function d(t,n){t.title&&e("Copied to clipboard"),navigator.clipboard.writeText(n.response)}function p(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 i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=n.response;return!0}function h(e,t,n){var o,r;const i=t[0];if(1!==t.length||"number"!==i.type)return!1;const s=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(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(t){t.preventDefault(),"Backspace"===t.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function g(e,t,n){const s=null==t?void 0:t[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),c=o(n.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.click()),{once:!0}):a.click(),!0}function v(e,t,n){const s=null==t?void 0:t[0];if(!s||"checkbox"!==s.type)return!1;const l=n.normalizedResponse.split("\n"),c=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value));for(const t of l){const n=o(t,c);e.logs&&n.value&&r.bestAnswer(n.value,n.similarity);const i=n.element;e.mouseover?i.addEventListener("mouseover",(()=>i.click()),{once:!0}):i.click()}return!0}function y(e,t,n){if(0===t.length||"SELECT"!==t[0].tagName)return!1;const s=n.normalizedResponse.split("\n");e.logs&&r.array(s);for(let n=0;n{var t;return{element:e,value:i(null!==(t=e.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),a=o(s[n],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function w(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){t.preventDefault(),"Backspace"===t.key&&(e=n.response.length+1),e>n.response.length||(o.value=n.response.slice(0,++e))}))}else o.value=n.response;return!0}function E(e){return t(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const n=function(e){let t=e.innerText;const n=e.querySelectorAll(".accesshide");for(const e of n)t=t.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)t=t.replace(e.innerText,"\n"+m(e)+"\n");return i(t,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),s=yield function(e,n,o){return t(this,void 0,void 0,(function*(){const t=new AbortController,r=setTimeout((()=>t.abort()),2e4),s=yield f(e,n,o),l=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:s.messages,temperature:.1,top_p:.6,presence_penalty:0,max_tokens:2e3})});clearTimeout(r);const c=(yield l.json()).choices[0].message.content;return"function"==typeof s.saveResponse&&s.saveResponse(c),{question:o,response:c,normalizedResponse:i(c)}}))}(e.config,e.questionElement,n).catch((e=>({error:e}))),l="object"==typeof s&&"error"in s;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||l?"pointer":"initial"),l)console.error(s.error);else switch(e.config.logs&&(r.question(n),r.response(s)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),d(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:s,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const t=e.questionElement;e.removeListener();const n=t.textContent;t.textContent=e.gptAnswer.response,t.style.whiteSpace="pre-wrap";let o=!0;t.addEventListener("click",(function(){t.style.whiteSpace=o?"":"pre-warp",t.textContent=o?n:e.gptAnswer.response,o=!o}))}({gptAnswer:s,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const t=[p,w,h,y,g,v];for(const n of t)if(n(e.config,e.inputList,e.gptAnswer))return;d(e.config,e.gptAnswer)}({config:e.config,gptAnswer:s,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const A=[],S=[];function x(e){const t=S.findIndex((t=>t.element===e));if(-1!==t){const e=S.splice(t,1)[0];e.element.removeEventListener("click",e.fn)}}function q(t){if(S.length>0){for(const e of S)t.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return t.title&&e("Removed"),void(S.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");if(null===o)continue;t.cursor&&(o.style.cursor="pointer");const r=E.bind(null,{config:t,questionElement:o,form:e,inputQuery:n,removeListener:()=>x(o)});S.push({element:o,fn:r}),o.addEventListener("click",r)}t.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const t=e.moodleGPT;if(!t)throw new Error("Please configure MoodleGPT into the extension");t.code?function(e){document.body.addEventListener("keydown",(function(t){A.push(t.key),A.length>e.code.length&&A.shift(),A.join("")===e.code&&(A.length=0,q(e))}))}(t):q(t)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index e8a6916..5750f20 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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/types/message.ts","../src/core/get-content-with-history.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/get-response.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gpt-answer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","export enum ROLE {\r\n SYSTEM = 'system',\r\n USER = 'user',\r\n ASSISTANT = 'assistant'\r\n}\r\n\r\nexport enum CONTENT_TYPE {\r\n TEXT = 'text',\r\n IMAGE = 'image_url'\r\n}\r\n\r\nexport type MessageContent =\r\n | string\r\n | Array<\r\n | {\r\n type: CONTENT_TYPE.TEXT;\r\n text: string;\r\n }\r\n | {\r\n type: CONTENT_TYPE.IMAGE;\r\n image_url: { url: string };\r\n }\r\n >;\r\n\r\nexport type Message = {\r\n role: ROLE;\r\n content: MessageContent;\r\n};\r\n","import type Config from '@typing/config';\r\nimport { ROLE, CONTENT_TYPE, type MessageContent, type Message } from '@typing/message';\r\nimport imageToBase64 from '@utils/image-to-base64';\r\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\r\n\r\n// The attempt and the cmid allow us to identify a quiz\r\ntype History = {\r\n host: string;\r\n cmid: string; // The id of the quiz\r\n attempt: string; // The attempt of the current quiz\r\n history: { role: ROLE; content: MessageContent }[];\r\n};\r\n\r\nconst INSTRUCTION: string = `\r\nAct as a quiz solver for the best notation with the following rules:\r\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \r\n But for the calculation provide this format 'result: \\nexplanation: '\r\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\r\n- Always reply in the format: '\\n\\n...'.\r\n- Retain only the correct answer(s).\r\n- Maintain the same order for the answers as in the text.\r\n- Retain all text from the answer with its description, content or definition.\r\n- Only provide answers that exactly match the given answer in the text.\r\n- The question always has the correct answer(s), so you should always provide an answer.\r\n- Always respond in the same language as the user's question.\r\n`.trim();\r\n\r\nconst SYSTEM_INSTRUCTION_MESSAGE = {\r\n role: ROLE.SYSTEM,\r\n content: INSTRUCTION\r\n} as const satisfies Message;\r\n\r\n/**\r\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\r\n * @param config\r\n */\r\nasync function getContent(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise {\r\n const imagesElements = questionElement.querySelectorAll('img');\r\n\r\n if (\r\n !config.includeImages ||\r\n !isGPTModelGreaterOrEqualTo4(config.model) ||\r\n imagesElements.length === 0\r\n ) {\r\n return question;\r\n }\r\n\r\n const contentWithImages: MessageContent = [];\r\n\r\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\r\n const base64ImagesResolved = await Promise.allSettled(base64Images);\r\n\r\n for (const result of base64ImagesResolved) {\r\n if (result.status === 'fulfilled') {\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.IMAGE,\r\n image_url: { url: result.value }\r\n });\r\n } else if (config.logs) {\r\n console.error(result.reason);\r\n }\r\n }\r\n\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.TEXT,\r\n text: question\r\n });\r\n\r\n return contentWithImages;\r\n}\r\n\r\n/**\r\n * Create a new history object from the current page\r\n * @returns\r\n */\r\nfunction createNewHistory(): History {\r\n const urlParams = new URLSearchParams(document.location.search);\r\n\r\n return {\r\n host: document.location.host,\r\n cmid: urlParams.get('cmid') ?? '',\r\n attempt: urlParams.get('attempt') ?? '',\r\n history: []\r\n };\r\n}\r\n\r\n/**\r\n * Load the past history from the session storage otherwise return the default history object\r\n * @returns\r\n */\r\nfunction loadPastHistory(): History | null {\r\n return JSON.parse(sessionStorage.moodleGPTHistory ?? 'null');\r\n}\r\n\r\n/**\r\n * Check if two history are from the same origin\r\n * @param a\r\n * @param b\r\n * @returns\r\n */\r\nfunction areHistoryFromSameQuiz(a: History, b: History): boolean {\r\n const KEYS_TO_COMPARE: (keyof History)[] = ['host', 'cmid', 'attempt'];\r\n\r\n for (const key of KEYS_TO_COMPARE) {\r\n if (a[key] !== b[key]) return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Return the content to send to chatgpt api with history if needed\r\n * @param config\r\n * @param questionElement\r\n * @param question\r\n * @returns\r\n */\r\nasync function getContentWithHistory(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise<{\r\n messages: [typeof SYSTEM_INSTRUCTION_MESSAGE, ...Message[]];\r\n saveResponse?: (response: string) => void;\r\n}> {\r\n const content = await getContent(config, questionElement, question);\r\n const message = { role: ROLE.USER, content };\r\n\r\n if (!config.history) return { messages: [SYSTEM_INSTRUCTION_MESSAGE, message] };\r\n\r\n let history: History;\r\n\r\n const pastHistory: History | null = loadPastHistory();\r\n const newHistory: History = createNewHistory();\r\n\r\n if (pastHistory === null || !areHistoryFromSameQuiz(pastHistory, newHistory)) {\r\n history = newHistory;\r\n } else {\r\n history = pastHistory;\r\n }\r\n\r\n return {\r\n messages: [SYSTEM_INSTRUCTION_MESSAGE, ...history.history, message],\r\n saveResponse(response: string) {\r\n // Register the conversation\r\n if (config.history) {\r\n history.history.push(message);\r\n history.history.push({ role: ROLE.ASSISTANT, content: response });\r\n sessionStorage.moodleGPTHistory = JSON.stringify(history);\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default getContentWithHistory;\r\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @param quality (default: 0.75 -> 75%)\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n reject(\"Can't get the canvas context, ensure your navigator support canvas\");\r\n canvas.remove();\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png', quality);\r\n resolve(base64);\r\n\r\n canvas.remove();\r\n };\r\n\r\n img.onerror = err => {\r\n reject(err);\r\n canvas.remove();\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport normalizeText from '@utils/normalize-text';\nimport getContentWithHistory from './get-content-with-history';\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n // Get the content to send to chatgpt\n // Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true\n const contentHandler = await getContentWithHistory(config, questionElement, question);\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: contentHandler.messages,\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 1, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Save the response into the history\n if (typeof contentHandler.saveResponse === 'function') contentHandler.saveResponse(response);\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gpt-answer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gpt-answer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","SYSTEM_INSTRUCTION_MESSAGE","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","contentWithImages","base64Images","Array","from","map","imgEl","imageElement","quality","canvas","createElement","ctx","getContext","remove","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","err","src","imageToBase64","base64ImagesResolved","allSettled","status","type","IMAGE","image_url","url","logs","error","reason","TEXT","getContentWithHistory","message","USER","history","messages","pastHistory","JSON","parse","_a","sessionStorage","moodleGPTHistory","newHistory","urlParams","URLSearchParams","location","search","host","cmid","get","attempt","_b","createNewHistory","a","b","KEYS_TO_COMPARE","key","areHistoryFromSameQuiz","saveResponse","ASSISTANT","stringify","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","textContent","max","lineSeparationSize","reduce","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","filter","correctInput","mouseover","click","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","controller","AbortController","timeoutControler","abort","contentHandler","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","moodleGPT","Error","code","codeListener"],"mappings":"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","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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/types/message.ts","../src/core/get-content-with-history.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/get-response.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gpt-answer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","export enum ROLE {\r\n SYSTEM = 'system',\r\n USER = 'user',\r\n ASSISTANT = 'assistant'\r\n}\r\n\r\nexport enum CONTENT_TYPE {\r\n TEXT = 'text',\r\n IMAGE = 'image_url'\r\n}\r\n\r\nexport type MessageContent =\r\n | string\r\n | Array<\r\n | {\r\n type: CONTENT_TYPE.TEXT;\r\n text: string;\r\n }\r\n | {\r\n type: CONTENT_TYPE.IMAGE;\r\n image_url: { url: string };\r\n }\r\n >;\r\n\r\nexport type Message = {\r\n role: ROLE;\r\n content: MessageContent;\r\n};\r\n","import type Config from '@typing/config';\r\nimport { ROLE, CONTENT_TYPE, type MessageContent, type Message } from '@typing/message';\r\nimport imageToBase64 from '@utils/image-to-base64';\r\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\r\n\r\n// The attempt and the cmid allow us to identify a quiz\r\ntype History = {\r\n host: string;\r\n cmid: string; // The id of the quiz\r\n attempt: string; // The attempt of the current quiz\r\n history: { role: ROLE; content: MessageContent }[];\r\n};\r\n\r\nconst INSTRUCTION: string = `\r\nAct as a quiz solver for the best notation with the following rules:\r\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \r\n- But for the calculation provide this format 'result: '\r\n- For 'put in order' questions, maintain the answer in the order as presented in the question but assocy the correct order to it by usin this format ':\\n:', ignore other rules.\r\n- Always reply in the format: '\\n\\n...'.\r\n- Retain only the correct answer(s).\r\n- Maintain the same order for the answers as in the text.\r\n- Retain all text from the answer with its description, content or definition.\r\n- Only provide answers that exactly match the given answer in the text.\r\n- The question always has the correct answer(s), so you should always provide an answer.\r\n- Always respond in the same language as the user's question.\r\n`.trim();\r\n\r\nconst SYSTEM_INSTRUCTION_MESSAGE = {\r\n role: ROLE.SYSTEM,\r\n content: INSTRUCTION\r\n} as const satisfies Message;\r\n\r\n/**\r\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\r\n * @param config\r\n */\r\nasync function getContent(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise {\r\n const imagesElements = questionElement.querySelectorAll('img');\r\n\r\n if (\r\n !config.includeImages ||\r\n !isGPTModelGreaterOrEqualTo4(config.model) ||\r\n imagesElements.length === 0\r\n ) {\r\n return question;\r\n }\r\n\r\n const contentWithImages: MessageContent = [];\r\n\r\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\r\n const base64ImagesResolved = await Promise.allSettled(base64Images);\r\n\r\n for (const result of base64ImagesResolved) {\r\n if (result.status === 'fulfilled') {\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.IMAGE,\r\n image_url: { url: result.value }\r\n });\r\n } else if (config.logs) {\r\n console.error(result.reason);\r\n }\r\n }\r\n\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.TEXT,\r\n text: question\r\n });\r\n\r\n return contentWithImages;\r\n}\r\n\r\n/**\r\n * Create a new history object from the current page\r\n * @returns\r\n */\r\nfunction createNewHistory(): History {\r\n const urlParams = new URLSearchParams(document.location.search);\r\n\r\n return {\r\n host: document.location.host,\r\n cmid: urlParams.get('cmid') ?? '',\r\n attempt: urlParams.get('attempt') ?? '',\r\n history: []\r\n };\r\n}\r\n\r\n/**\r\n * Load the past history from the session storage otherwise return the default history object\r\n * @returns\r\n */\r\nfunction loadPastHistory(): History | null {\r\n return JSON.parse(sessionStorage.moodleGPTHistory ?? 'null');\r\n}\r\n\r\n/**\r\n * Check if two history are from the same origin\r\n * @param a\r\n * @param b\r\n * @returns\r\n */\r\nfunction areHistoryFromSameQuiz(a: History, b: History): boolean {\r\n const KEYS_TO_COMPARE: (keyof History)[] = ['host', 'cmid', 'attempt'];\r\n\r\n for (const key of KEYS_TO_COMPARE) {\r\n if (a[key] !== b[key]) return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Return the content to send to chatgpt api with history if needed\r\n * @param config\r\n * @param questionElement\r\n * @param question\r\n * @returns\r\n */\r\nasync function getContentWithHistory(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise<{\r\n messages: [typeof SYSTEM_INSTRUCTION_MESSAGE, ...Message[]];\r\n saveResponse?: (response: string) => void;\r\n}> {\r\n const content = await getContent(config, questionElement, question);\r\n const message = { role: ROLE.USER, content };\r\n\r\n if (!config.history) return { messages: [SYSTEM_INSTRUCTION_MESSAGE, message] };\r\n\r\n let history: History;\r\n\r\n const pastHistory: History | null = loadPastHistory();\r\n const newHistory: History = createNewHistory();\r\n\r\n if (pastHistory === null || !areHistoryFromSameQuiz(pastHistory, newHistory)) {\r\n history = newHistory;\r\n } else {\r\n history = pastHistory;\r\n }\r\n\r\n return {\r\n messages: [SYSTEM_INSTRUCTION_MESSAGE, ...history.history, message],\r\n saveResponse(response: string) {\r\n // Register the conversation\r\n if (config.history) {\r\n history.history.push(message);\r\n history.history.push({ role: ROLE.ASSISTANT, content: response });\r\n sessionStorage.moodleGPTHistory = JSON.stringify(history);\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default getContentWithHistory;\r\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @param quality (default: 0.75 -> 75%)\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n reject(\"Can't get the canvas context, ensure your navigator support canvas\");\r\n canvas.remove();\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png', quality);\r\n resolve(base64);\r\n\r\n canvas.remove();\r\n };\r\n\r\n img.onerror = err => {\r\n reject(err);\r\n canvas.remove();\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .slice(1) // We remove the first option which correspond to \"Choose...\"\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport normalizeText from '@utils/normalize-text';\nimport getContentWithHistory from './get-content-with-history';\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n // Get the content to send to chatgpt\n // Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true\n const contentHandler = await getContentWithHistory(config, questionElement, question);\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: contentHandler.messages,\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 0.6, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Save the response into the history\n if (typeof contentHandler.saveResponse === 'function') contentHandler.saveResponse(response);\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gpt-answer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gpt-answer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","SYSTEM_INSTRUCTION_MESSAGE","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","contentWithImages","base64Images","Array","from","map","imgEl","imageElement","quality","canvas","createElement","ctx","getContext","remove","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","err","src","imageToBase64","base64ImagesResolved","allSettled","status","type","IMAGE","image_url","url","logs","error","reason","TEXT","getContentWithHistory","message","USER","history","messages","pastHistory","JSON","parse","_a","sessionStorage","moodleGPTHistory","newHistory","urlParams","URLSearchParams","location","search","host","cmid","get","attempt","_b","createNewHistory","a","b","KEYS_TO_COMPARE","key","areHistoryFromSameQuiz","saveResponse","ASSISTANT","stringify","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","textContent","max","lineSeparationSize","reduce","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","filter","correctInput","mouseover","click","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","controller","AbortController","timeoutControler","abort","contentHandler","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file diff --git a/src/core/get-content-with-history.ts b/src/core/get-content-with-history.ts index 635c647..b636838 100644 --- a/src/core/get-content-with-history.ts +++ b/src/core/get-content-with-history.ts @@ -14,8 +14,8 @@ type History = { const INSTRUCTION: string = ` Act as a quiz solver for the best notation with the following rules: - If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. - But for the calculation provide this format 'result: \nexplanation: ' -- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...' +- But for the calculation provide this format 'result: ' +- For 'put in order' questions, maintain the answer in the order as presented in the question but assocy the correct order to it by usin this format ':\n:', ignore other rules. - Always reply in the format: '\n\n...'. - Retain only the correct answer(s). - Maintain the same order for the answers as in the text. diff --git a/src/core/get-response.ts b/src/core/get-response.ts index 4c54dc5..f1f19b1 100644 --- a/src/core/get-response.ts +++ b/src/core/get-response.ts @@ -33,7 +33,7 @@ async function getChatGPTResponse( messages: contentHandler.messages, temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity. - top_p: 1, // Determines the diversity of the generated responses + top_p: 0.6, // Determines the diversity of the generated responses presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text. max_tokens: 2000 // Maximum length of the response }) diff --git a/src/core/questions/select.ts b/src/core/questions/select.ts index e6e35c5..6f9f902 100644 --- a/src/core/questions/select.ts +++ b/src/core/questions/select.ts @@ -28,6 +28,7 @@ function handleSelect( const options = inputList[i].querySelectorAll('option'); const possibleAnswers = Array.from(options) + .slice(1) // We remove the first option which correspond to "Choose..." .map(opt => ({ element: opt, value: normalizeText(opt.textContent ?? '') From 56c2332628f30884091ea6d8fd3bfa5a5098852f Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 21:57:43 -0400 Subject: [PATCH 65/87] Update TODO.md --- TODO.md | 1 - 1 file changed, 1 deletion(-) diff --git a/TODO.md b/TODO.md index d8ccb5d..77e7caf 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,4 @@ # TODO -- Better prompt (Fixe put in order question, Fixe calculation question) - Better webstore assets - Do some tests From c251819521a4bbc44ffd203632b85604993c53d6 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 21:57:57 -0400 Subject: [PATCH 66/87] fixed selected model --- extension/popup/js/gptVersion.js | 3 ++- extension/popup/js/index.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/extension/popup/js/gptVersion.js b/extension/popup/js/gptVersion.js index 4f566d6..8fff3d2 100644 --- a/extension/popup/js/gptVersion.js +++ b/extension/popup/js/gptVersion.js @@ -20,7 +20,7 @@ modelInput.addEventListener('input', checkCanIncludeImages); /** * Get the list of chatgpt versions */ -function getLastChatGPTVersion() { +function getLastChatGPTVersion(selectedModel) { const apiKeySelector = document.querySelector('#apiKey'); const selectModel = document.querySelector('#model'); @@ -49,6 +49,7 @@ function getLastChatGPTVersion() { const opt = document.createElement('option'); opt.value = model.id; opt.textContent = model.id; + opt.selected = selectedModel && model.id === selectedModel; selectModel.appendChild(opt); } diff --git a/extension/popup/js/index.js b/extension/popup/js/index.js index d7c2515..5efa82a 100644 --- a/extension/popup/js/index.js +++ b/extension/popup/js/index.js @@ -84,6 +84,6 @@ chrome.storage.sync.get(['moodleGPT']).then(function (storage) { } handleModeChange(); - getLastChatGPTVersion(); + getLastChatGPTVersion(config?.model); checkCanIncludeImages(); }); From 18e626a6e5bfa696a6ddbe98e93d8d17693ae184 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 21:59:08 -0400 Subject: [PATCH 67/87] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 52a3fe0..ffcb381 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ See the [changelog](./CHANGELOG.md) to see every updates ! Popup

-Go to "Manage my extensions" on your browser, then click on "Load unpacked extension" and select the "extension" folder. Afterwards, click on the extension icon and enter the ApiKey obtained from [openai api](https://platform.openai.com/api-keys). Finally, click on the reload button next to model (it should give you the last ChatGPT version, otherwise enter it by your self) and click on the save button (The extension need to be configured before entering the moodle quiz). +Go to "Manage my extensions" on your browser, then click on "Load unpacked extension" and select the "extension" folder. Afterwards, click on the extension icon and enter the ApiKey obtained from [openai api](https://platform.openai.com/api-keys). Finally, select a gpt model (ensure it work with completion api). ## Mode From 957f1e6b3c48a82f3beb0e230773c05870cd2d06 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:00:51 -0400 Subject: [PATCH 68/87] Update setup.png --- assets/setup.png | Bin 8424 -> 8501 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/setup.png b/assets/setup.png index a60034085f68efdc0583976a57dc19e2621e6914..6e68157cd670d195720506f3638219ef99223b38 100644 GIT binary patch literal 8501 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 F`X7>-L)`!X From 2c3a417c59b450ec58bdd0932efe4327d04172dd Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:35:36 -0400 Subject: [PATCH 69/87] webstore assets --- webstore-assets/v2/banner3.jpg | Bin 0 -> 241330 bytes webstore-assets/v2/banner4.jpg | Bin 0 -> 221498 bytes webstore-assets/v2/little_promotion.jpg | Bin 0 -> 50509 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 webstore-assets/v2/banner3.jpg create mode 100644 webstore-assets/v2/banner4.jpg create mode 100644 webstore-assets/v2/little_promotion.jpg diff --git a/webstore-assets/v2/banner3.jpg b/webstore-assets/v2/banner3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b04c1308a8a60b6efb67ca1c3cb7bde73ba83730 GIT binary patch literal 241330 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
n9)Q?;+OPWzL^w)|LD~y)9)g89{ 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 z z6>*TanLg-u?lqx354=+=jD?kSNjeIU$ADR%g{JWc^q7Di5^I_SN>5Ngdh^ep82yqu zQeS|6Dd~^@x&Fec>`|+i|LsBCv0}Te1*jP*_%^gvKC#8jcH(jmfmam1U`!Q5mjbR{s~Jtc#Vh02jb|%#3l4( zo2#A|R>0|HH{kB8u@m-TFDmL0`d6l*Y@G%g)}JiJn22Vg9(Wy|O`b?%W(%u?R?Wu- zCo#S9UIl)o)Ck2MV@6NMJbgohOb5{whct9WY}Y4cf6ljrF|R@GZg9PZu?Y8tV39r}QP_dmG!w@-4`uk2a5-953xhhK}UU8}(BLf>{j+KI3ngPweREqd6^ z57vnL>;JFXm01ZLb=KOhu}-kmcF?z{wWxb<(=3SMiE;(DJH4k5m?J;>z7c473&eY~ z=mxyR^{Mq0%ZUV+e!vO_Zf9nO?PZ88UAK3f9~b{w4XEA@0IkaDf2_lkc8xV7?HZdU zBs#wT#}yr=wU&jt&R;7v{`%to|KI0GqIy2CN9X4{0*rM1%cB-+?v7j?fq^%d|M5;x zVchrLFe7~O-aBszKX7y@N5-hP7GQ$QlgpVrMdm25G6WC3ujkI?5pd7aR(yeqgVN4= z=9%tHbI?Z{`>T4Lau

+U@Zsj@*5WHWfB7nCY&( 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

U6TV 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

IoC2OnO36xKI zom{)RK4PEb08dSvn_AeE_nv-<4cpK$=`H|UM!<<`BoAUDuJ4Cq7fm4akEl=FhjYMfQc+~u6pDA=D5zW=SW%;$J}~& zJwxJ|-zKj$ZGBzTb1gg<5XO6YjmayX{dCvHme|Q3);n%Q?(y>*>Tx=M*5H?-YMI7dd8w+?O}Mqq`hws}9c6u{o>_ej=Z`RO`Sh{Vo! z5(O;*n%iZsiprm%j{ejsJ;7u)8=`nV!!dVh+#!q#h!firmvo zEq54eG-XT2d#rI|{6em~_y216{y&bWet6dj44GzT|3szLX}1BobM}ydt&9CH9?7J& zqdFV@T8hB$E8mEnWfK(F6?wzatc#|sCq@q|me82`v~{Pnt#T? z7MG$e+fjOAuB58pS1z)hNn;I-RJ)P*zpL#EXJ{&5AyFk^e@CB7<(M-s4k5`n!N~;D z$cmVg-{H2Wo*jJVw8w|W9d5)M94lZiF6`3KhtFxXrNZW%`8QgVGUd?kQPK3@h10Qi zi53!3JBRHmyT=09#@Z2~qc-QuprW2rpB~@;MMnI2@c#rEvFOj;I*xxf%J?*l`mITA zIJ*htekA*T1M$U{pX11qscr4{v*zja9Yh@-9Z8KwgXY7zD||A(9^=jSn9Byw;uZ%$D!t(* z&Gp>YG&!)^S!!D6$qYd}vre?XJ;+$$fY}8oYq!*%DHP6*Ez1f02dJmFW|wTyK7R;SD2iv|ZH6HnKFwBJ>!s}kEjR8i z6gYRqC`yE@tNqXG(3T9I&-6GADbmH;{=>5eSY6qM<(vsTN zx&p&O918B~r{*`%@4ty0*?T8wGsRxqNv)FQ%#VG^B)Nhy~iEt z#pj=>?Ce-YM(j#54}i|-2d6Yh-O$i!It#y-({PD^kI1;z09_T^H>`l-+K%S+p4MZ> z9e?giaA~CB(kz~&-y6>|-CVeVc0f#C}TIhpTEK6%W`B|8SzQy$RxKxSGG^0qa2@sh& z!zZwF`Vtgcn5=4DwdgdzjIx{dKQi+3X5wC~4nlLSxvUF=mVZupJ7#u4rbaJ%o1;S} z2UwT)bMUCMzQ}W>rWysD+87S>D-+gWmqzR#oirApYAuAZ)E8hz>aVZy!s9D|QmVwm zqUP1IcLzr(mc3!5L!&=YKdsj@so+8!C#@FJCBsS>%NtsoYA7h`8jRPHT8_?K6&w$? z#S2%o$E)Hq`rpk78hfyx1sLOaks(PX>p;GHsv3>k>nZaa>bc6PqUd z`h9?IH3P7x)rQBi_&qj@C%UfgQkNVzxV;?K$H@kxHFb|%lLXV6R8e8wkJnkEJyqkL z#~7iUBLlR28O4kWU`TE8kqt;XXEBdk`omf)A<^t!0$oyN9%?TV{-@PHG3ycgOwpFx&E#4eS-vuo6eg(HzLksn?*Un ztZ`0NK?{_&`BMEVXgM}P{kd5lvG6Fkj})4s2@rXgRP`aJJl!;9Olq^Q!yf3Lk_9VY zl;#T^m^_=FP5&=aT{T{wZzRZ@-^P_WcmRj%x5D)B^Y?boJF4^^ z)?~vfli!-93w4>fV`Uyx>p5*%lcm+ZPk?&1V;8ddq@4^B8}p(t#*8ue?HQa^jRVqf zY_lAEYh9vhS+mBo5W8Qc=XEE;e@K$kCnxam55kW)ju0C4D5G^ zB-3bWzWvSGU+`|E&ys;h{@!S*6)wHzmwUrA6iPFE;33kjCX@B*(Cz;GJWH{C2elkd zZu5#5?wk*>mWr8&%SFSruKX^$Z&#op?dzsa9#hq!se27a#FI&FhH2luSY^E)k5+Nh zkVJ+8H0SU**eQ$o_fAJH2vuBeH98PWWjjN8lxE>WOIodsoi{ z7Qup^^@nY^wT7@xq|{)|1<5`s?FMp1ZPX+rxJhhZ>UQO`jULAKdgvjkma$E&q7d9&;7#p>&4=bk zZ*HLylTYw6q~gkpvFYe`QQ?OBBjYD#;dPN&3mcb}vl$U(uK&q?3izWcp1?^wU>J^t zVSIIs@QGCSn`e~Mven})CvOqTuK*`sXxfx{HmB*t+b{%5k1ulQk#rhWny0MrD517j5y_xDG4)4!5`zBRa#x7;B$;dxmBi z`s^C}KMKnK>Hb>e!oN|gaJhfUMRGfl3reLljuBRlq6lpd`12Mz@a+qhK6nNj;bUPO z4`#RS*pBmdf~W9Im1c-jyaP`HXrb4}#x6UC$4>3^8=ceVSaA(E%IlLUkUBjq0l+3u z3GAk2t_|wb+4yXR&z8}H%;|N9J@o#(;6U9&9$u=RidDyZGE7veWtluQUJRr7x(tZ3 z9chhq#*=Xly?Ee^V8av!z~DsxZ%=6MIPyPJo94K>>{&HFfA0=z$9Z-KS4$mYwL}0r zk`?5uqW_H-J8AJsBfo#((!)3K%Q;uiaF35b)9kO-DzT&kL+7UB(AKSNI@d^B<_lEL)wj}GLr%oF}W z?w||0{sj09fd}K`WyU$4_q{XV3+DOm;bQ8zHU2y?%}*E7YNQ=q$;{3vV7^ zd-JtYz#QM?@;#Sajn(oqOvPBXo3^u+P7i$igvS;Ag6h!o`etrpA1%<<%6&#>i8Ry5 z&ELIykE}xO-+S|Dv9-d~>f~D;?~DOljz8k5J{K*`_k(3(`_JfR+Gtq}{X;{7G>@L* zmvjN=hc2n%AFWIaqjKw<#*ay$vI)==*G`tHPJB<}Ct4z!-TkW9kuMPwit_C%Yf3U* z+>b3zq-{v|%;WY$r=-84OXGRsWfWJNb@X}lWi&7jJg5~paeB^B$A8m;BNNB}D>s<7 z@cDPWJ}8M-7t-Hth?n-5=tTjrwOmCeAj8Vy#-QBOqF2xohs3g=CHr+s8%mz_&#vn@ zFu4~c4`88k(X7`@ZtJe5qZ_JkehP8_{Xgw7|Cwn87p;s6{yF$)QP=Tkd!mBou-bII zV3{co_d2@JmN+yWDJyjvIvp>o`YN-MgEY4-vF6f70F1(vt<%TPG?QZ>Em{P zV8(kW;l=TajG453Q7K%lbVpSMg^aDn2Y2EfvR`=%p7&6|q&MHm-R8cJx|YSa5Q}-B z!F7>0%}0v**ay(OHma{_IT?2TnF1~y)EMWBqNB1Jjk-!R? zE<7clQ#&DLnR3@4v4)}pX9dt^)C<&%6*<~Bt^hV~kJ4uJ;bo|wBszxwYHB{gfj}NA zx+L@5vmQ3_9^oO07r9YGJ;KolZW^4T%r9QCI|}}E1OlKKAz*8F(~ebp}9z5_1o(!O#9SksyrWwC*11v%Odf7FjJt*(I+BdR>KO9IaLcM z+AABhmYWPsf)5MvO0=Z3Bb$no8U_XdwTRbMYIeB|!aD_lEL+jgv9AP79zuhFoE20n z8|4>?2TGt-IXZYeAJX?bo=m^Mq#AW|-0Y9Janfy&{Or%PKJFQazoG=}j~tpB=xddMecF-=(%TdxK0PS~N2aO3`E37UibcX@h~ z0Prw|dcjVs2ph#!sx$@iG(RN*_SjOFGvE@eIKM@lYjS-rxmciFn%@sk_{YzdN6e4) zCQURDJpqwXlTf?3HyN!u!&K54?To-yHu!Sn1n9b>mEKCppvMv!GTL)n3_7vQEiDgH zxz(mii@P@SIKT`1cpft@TU8$2a7}h@wxWM@E*O=?M$ZFv44iu{gtG!6J;SmhM^fhs z(gEmlGWtV^a~LazB0W}Qb`GysM3{!T%>H;E?zS&LYJMV-uXP;{PZupS2u-kp8V$Sf zvpE}~?iHLV-m5L_1+F*)MhM-@8Zp+!rVV^xp&B^2UxLT(hYw1bdzs%H%b}*7|e{EgC)~#$m7cU^LNml{CzxSK=a08 zRn1mi4Rvjm9++`^r(#)~mbfjqR9{533ofJj73l7*QG>-}Hs=rSJ?w9M*8$_c2%l?d z3x&QnalyPUBx3=79P8IUd#UWluTR>T9tyf3sSyj|mbjnS1$pxzWNy&^jAv2l`#X7& z{HDWLdvT1IIRl%$x@9qPXtp8n=p9M*)gNg-8~g#GWt(7B1%x76n)-#+;#VcL~7LS%b?av*&J z+UdwL!YbF+YzK<_z?2El` z{iBkw%*4p)coWlux@Fj5JXi@^tN4Sm9b2sQDLYSXyg+1iLSLcO2G3#s8Y?%Z>(Q3d zNzcbBgJ0H@tccU^|Lfwfz28?Nk|0FFuEGvDvklcJtBsc2a5IvWFhLl4q-}*)wX0cs z(CzKNm88ciXr`=s>dmMz3U6l>M#u_h0Irs+JKkk$i0hN!+tN?0k%;n?*ehYT3h}kF zf5h?f2y+SQePWC0=49y}WaT#TI0ffBOnQGBcSrMl0!ZFJeXA2^h7RB|5b;5}liB$kCJpb7x2-VXIn)%hA!AvPl#u9ejDJ!+$s#;|gN6{nvm zp1J+@e@wo+IMe&|48e5}J ztW?$!hBaX;r`R#t8wQVWJ+HJsy`f2I@T`^@!(zK%oTAsN@&i@B#Ep+kgns!sTzmOV z8Toa_7E3x!!uNVUNo&`(*t9!-Fz}LL{dtI6ddmJ_iHDjb?==ap>Q{=sCqfPfZPvMI zT0^ehJeYOr(#I0$fTjWK;o58wYD+lNcT`wdBu9cwOY-21{)~K@F+#$LNtmo_Z{u-g}_JD}QBUub^#*;aE&(SL)*03JETo-rwV( zZZWa}oJ{w^$O|v*R_)6Y;wRO|+|Z8j(sjkZ&XQaV7D^>v_MPn{Y3)_uLr@X^WCnJ!5n0Rf=+6@w$_EIId3xI^kKT%NKJ-ys*nigL+@PBQnMEp z^hw`>8}O)0UUXt)q{pU4X$}h|M}(zB1+Dx5lm%{7&igQ-{%0lu1v1xIIVgGK*A()zY< zV#VR2jic!NQd;3`HIMzxcw;MTJzG!PM5v~u{(YyQ!fl1>c%vLdI-mcLPD2G6Q}0b!EO?SVD@DAx2wy(C(R@+uFSN{ zJF`2amJF9r@-{w4heqfZ_{(*xXst>mfX!9#(;Aq33~tnMw4jp#G4En*<38Hb^tQ1w zW`n@BZe~&JUU2E()xsK23%O`AFOsF#ex@WCr$d~GMi>qYizJIB_L5DLDh9qkC$fSb z*D)8lZHws)89yzqkRBRn9ZMVP5)S?4oTXuK+l<|7_2T$bnyuAHcmu3F9p)lBhx*n6>eESP`9}G^goqza@YBQ48N20av!gl0lmQMs-6!O6oo=S@9ui z5s*f%s;KQZ(HR@kEnV&!*!uBR=K$4aAB85CR=*p8vK$ozwX&)Y&VWcoVK#wI;>|P6 z5{)IuQWYXgQr1G*`247ad0VFpT+g-Glg*~=GqJUYFC)P5X6*Y1C5X84$8<8cV5lbk-e4F=m+InLGzR_`%SSLt(iFCMC8G!#m+_YC~ikWvua z|NW4Dzu%x9w0kJhc=RALQ`~LUpy|f1hQtD&USq6Wr%tr|2*IltrN9*NZRLgS&&n5l z@{;V%?4SF;3$^xmSQ8V-&_wqKUm!@`i?!Wh5N4~uQ_imlqn9m>54DW*0SdZiG ztQP(`X3V0;!pl#aljV#Jg257Tr;$b7zv8)TsUOQoNgvQM1uoN!lTMn9yTErFy%TR# zWo++p>z_t4THHvj^Azr_`p+4nA~`=?r%f1+h2)QhEPiP1Ib}4&u_JqJzxOWLMA?`? z_~ZM+c)MT4Cl&e><`zBhp{;x&j7ZxPYxkFBmfD7MB{T<0;Rzk%4eMmeTwTTp)g3hvASM}`AUiY{WugXW}M^m`3w6#Nl2-iXr9GjE~sW?-YF>W@k>-QMKx5e2PMF7e+4& zYVvd}ekZ*;`9;6yZlZ|Utk%-%kB{06QL>5;dA($R=5hXDjBOKm1qRI7iMO@2tg$>X-MpNpKkr*f_nzJvA2C6*#mym?FzdIkUnIHWW z?pM)$)Isk;vfznVq^WNrY1*b^fIbeP4+81a$r@xZd9S_6cMq#3g$?Kw>Z^A7VVNKE z>5j`68dap~6c=TD$A~0&^Yk6?1AyyvXHHVOywxVburk$^`3YD=MO}bm4Xw!pA=Nrf zNo)=KgbfJ;|5-K@R3wzzN7PsFL^~)Fu#X?|#Pu5a8ke*#3j*k1#RbnA_j`iR+Aw8! z)7-()z5Mh;iBFkPP_x~AmXFi5noo~V51*B;+>V_7^7R9+ zGzJZdk>B9?0V|+2y&JkTF8k`n_n-3um2?@JQn4Q@!(H&4GwzLrOAuD``oqd!*{F>{ zxOH39;OM6S9=FI9Iu6On&*2$?h>tE&$mT{0PPi{u)W=FZWw#X4UlWp*7J;WGmG^5jq-10z1WHPZ z@T_@ONW@nl(Y~Bq7YhlPA5$G=RA^6;D80Tl_3b*wHKSd|?~o@R$djN&+v4zk@fycM zS*OpIXaY9?$aDn&qWtSdEd|V8^eZso~1T@}Qip89g zI)ToBSDd4r;AOZ#`1zwkaB=+SVpBLk!qN7IIN@KDapX$%d-*a8p(t=;h}x2>!=Wo9 zZ$O*Om077%M*hT*t8%lCGnOLAu>PicR8Rk#6=aQsweC zLdM5cvK4BLQoc0|_1g8BoF(>Rd#>}+YWyguy-~983=cHT))s@R+b<^8XnAW)QeGt3_NYo9ifg4 zr?&qn(g`nAxKD@Ho8B?^*yZBu9Myz_W~Oq5(niz@*X!_i-L~QTQr@uAV;V%#F0$Uw zQ6qkM?}Y5d&OJy;#m10X0X6Zmf~vyZr_V|qK9H=;!~BJO)f+YXA|m1IdC$KrU8vTF z5!X8c!IEvo~SN4lf z%m}-g@sBlgEq6i3dIsd0EFug0%|}a;j8n@4LGPjaeI%rO@~SqBMymJd3tO*-dl9GP zfWyLzO&pHtbwLYH`<-K$Dfce1%@Plm_*Kbt5ZNc5sum*VlVa$7COal;vvW*9`axaV z=gZeIJkx^38Oc_*YPB-huRZoFviq~545|Up44{LoH`~mR$RIBm;PIRTY!Nos;Pj)8 zgQq`1AJbTG`}7;(GgSul##Z^YADmYfFV}CmB3GM{Yu5%GRyM4RAf_uo@VyhevbdKc z`wC`_x!1Ga#PHN3e|YlLhC!k>X93~~)!mz+7vGx%g?K=dvV7;hf}2sQC{@0~@mpOk zTkc(c&~~LLn}Tny*@qL|7lcTEL(iWVdQ5?DtN8_3M5Sh2(KEj?TpK_Nbuzpb+DI{3 zr`j&`%isXbx@a|Gd};6928-OSd4x3k=n`mX4&kfa^z58!klPu(u26U;e@P~Os(3eE zqjYb<{M9oWbUDLnsoD7Lgn+MSzaN~I@DcxRX7^)6HoAe~;V(0id=Zn8RH1q07T?bD zpjUmHs*&EXpkv`-_<6rF&zRmvt6^g{6Vo_6qaG~_7fjk9q6bG!P}1*zUwJWVsc2Zn z*B!1?>a}BK{QFARFdgtt#pK$`4&LRul>I0={SE;8W!AE)p$H z7BXuK6gO+Iul1PYuFb3f$mo_;LOi0W!*i+b-4_Q4(oNFfQ~J3cbtoz|mF}^Mx+7tv zh>;Q#wyO{YG7arwes-?;Qgyfcf$~l3BCBVt%ewDtN^HPMZAs&OQzGYnx=!jBe@v24vGr92GXCgU#g)IqD`8ht7g2X=vv0S z4ZYG+t&!A92a@B^w*|W&oM;mX3@HhxETF(0&z^_k(d6c+k4$z-K}&EL47^9Z$+g z=W<*oKgkSx+)QF?oxrDdRgkfDrp1jF0|BoeajShYE-dM4SJpRoG#$oo2o#P~C^9mC z^^4H@l^Ggt+o4cXfR769LlgQqt`o$!N*=_%sx{WE6?mQ{nbnn>`k3GEY(M*sc+heG zXuq@Z;BuDlBd8-#cux$eY2_AU0WduTO}uQKv)X?Iu_PGROMB?I!i(qEhyizN&SDMA zM$M{GZ_MI4TDKCyreErsR}12yhY3pc3wty%n)c=HgDzt7;N0kjq_8;1ytwP!({nuJplO|6nY1c)=)b28ann=4j$G!NR!nbHj;Z-7awQm~V3uw! zQRqEZS7VFhf$2<2(vQa1m>T^A61xk6>G>X-t|%5&W_cPJ!%lp}vOj&aDW|1KVg8|Z z_2n&Pb~T690=!@`aVBixV+tRq+&P3UH6Ch_?=%yoyJd>85zw6riF`SQ3FaSyOI)*!b;G5~BgSG|W!Je;0QIO_BsAGZ*?aovlmD*l+Zm-q6`z_Tgr zPg)Y=-(Ip=Uq_iTOZ`;UwZv4|9Eyf7<~=B66qdvt{+vj49IO>OT_dm-E0HREhQ;~ZW^NB6`E z7$+b1q%v$;DS-AdGzH|Efms1`({2!V5NPAyt2xP>BpYj4?O=3MS(5Pdj3y5SI-LiI zl}uF^`vs)&Y?4MNAiiUDbz4Im)V0$Y^#(X-Rr)M>-OI1-r_R1ygYpiL&`^^Xo!R(W zmB&}cLL}h>K|CY2Y?M2j$8hDkfR=l_O-UHd6aeWIc0L4bO@eYg;Rx*tjO>1qAlFaQ z4AN2v4U%;Qb&lmq(-98&4N4CC_Z8e1_DwS#qV6HPHEq>b#+Ky;cpSQW)x2rJ^c^g{ zr{3YGa!y_C1l7k%dunaIX_rq~w2h$0g)>wZkCc%e;a^-oZW)AXgw+^cH#ge@CVG^> zWPDa07|TlZXT69}=U2tLCpF*wp2~-k^Rtc|gK&gnG7J|*TEL3ODh}NTh^!@qdGYvE z>#?ACca#H0ddji!#}bq2JV0^)Mohea5b=y(XoDQrmg%MWDd4sf})2jAIMA_weMr$|iMY^&=l*eu zcTc{5_Stn!PmVR{g-wwz8Y>fhXSB_PRSHwW8dO)w(3_Fc@`NXnld*Dmbh!JBXcTO^2mLqxgVpI^Ovcym-^t&`;o{X4S2e@Y)t z?@2-JNY50VyPZPkH@~$SkPupfMpb19JC!#|kttW>M&%#=Tu!HhehIGIM!G*mXUW*N(hC(n*EPZCb1=$|w6|y1 z^=xtJY?=idO=v4eCVpkssyq~@J}>w_F&3Xeed3hySCQRfdtVhfv^vjGb!2d(6XW;o zHTT_OdbO1S=Wq|7bQa$SagE%TG!NBZJX5{nB~^344d$68ojH?x=Jkn*c?FKIwEc&& z60zDFtZxwK^u&5J^t9H#V3qjJ>=vuf`_%vmXDCH|Ow>1MpS0z4lpf)C)SaHI72oGH zU3X>b@r5sHmQaQP1ZO0~?R(h_NHZYPmgVoHTM}~%B!df+uF=#W*Gg0RLjdgo)p6(e z^IBsD*{W=oqSTq!$rpFeEV@HDeJDcNzP53J9KWy7+glu3oR|9)?R_yr)y|wMjM$Zo z_ANkGGa5=M0AKSslAYMeROm%R{~=8qTgx(&$9mz+XFj*%a_Da{bRoL1EaSkl_DEH4 zShR;)oxZpI%eG>7y}rlSAGmdRtWbBFMa4FjWUB1XFNYlUQ?oywH(gd>m5uzl7DZ$h zv(<`F=()qHzxKog%zPH!Iv=(?QmidSNMOlJ^p`v z`p8fZ9(9oF<$RXYl6(SmT<_$*ho0!=jf>3hX1kDMPsi7tI!B5|AJO%^c8&{ zGy_wK{=eomYaQPOU!JJ#XpLzqVG~8#^aZg|34KPcrc^E=Q<@kow79s~A$^p4{7h~0 zv8inJ9ah;-^|VMo)Fi(kPxsAnR4OF?fq)njl&{=X_rZ*DagmJ{`vRWELs3t)nk^Xi z=}35rtMH4?c2IRHu25#Lm0`V|PVOsPGSVp6H>L`z9qxtWKkWxIsf4_Jmzj{r;g^+x=6pcv;fLb!0C|%5DQa9`@3ye5~=7eT+Q@Ch(*}Is)y3 z#9D=-hyV@N`|xq^&=sdq`FmCV?9U@SolKwCYJIH`%2$01<$e6NKwmPk;hLiNhSsX% z8=fcP9)1Rd!3IotF%5A-i?-9(_tY&=)t%&kxp+I8BO{rGm0o8Va#)w}`c?|JAWM5u z+;M|?*XCF!X*d*h>F#Jm+9C)M2ex30{QF8k#7Su&NAV5d8PBQr=l5@hu>%&#v$Xhx z3;I+4{neAUTy3VRtn8jiWtILx_}+y@$3dHzo?xS=Mb8kgxTk~njLLhf_{{u+KhCZs z(o|OmiWTC@Phy6DUrFZbxeW6cTYPQEgh%f5EGQfIJ1!`jD7NwZUq}r9tI36177F;K zHKe93V)!Jq?Oazmrfr>36KI})>Ji#{QgQuX8)?qew!j}yAIBZ_(nQK!?q?JY0UoEx z8!=Y0;=CT{{a>!rxgVDR`npxf(sI0UgNdgS?JPy3^&GOYaM|?p9#3J}mfjm@!{YGk ziL?l_yK4X4SI20c4)D9IFof9hm#oKWW}CYl?*6{QzuTD~PoqU|7w!2aMw%W`lwW>W zoM9T^75Ayy79;IVM+-lO9tiC1YkcnSh#9_Ap1w-Um%!4H9)sLWicv9ZfjTfB_njHN zjS170#6`L+=(9RQ>Ml7(rpC)WnyWR8dtqrTx{kf0kdT&4 zkT$D)v8d{sTmAlJWpVU(MEb33Od%?oR*1>PQ`W`5&qqv?UJGX>FFyHW6X?yvsXF;f z;fY0jJg?gaNK;YywrY4#qs(O1J!Ye<76S(Zd9>#DET$>?jMBuOw(RZ()W!UYe7NY6 z;S0Z%<*ulp6XN*icGvNegc~}+?YCbi1`D{%85JA0kA-L69T>q~V`Y2$jTH`ujjXRb z@U7Qj$dnlhicG7G(U8TeqEVj&n9Uwb4A@q}=L;Z_C{lO&l0+_pWqE@by76d=#sUI1 zJ|Dzm^~W2w53krhbg;6D_Wr&iz7&{)Z)yNN?(_Tl{J~rbF2+7quHEaVTt1we=iuRu@)dINP}R+}MN+AcHa51;Yx}+0o4z87CVw9Lb*8U)|Gpw}^uoH% zyy*Qx^7A7B1Hkk~LsR?sf}q->;fwP6S9=V^4B_wH$s+0Oi}d!u&qGEV^7~T13UxTz zX5@N(fH`~A8c1{q<3 z;jrGylnLWG9^8tk{dCsDwg3k{0#vvU@3UWxhK+9=e3A7O#C4foZE*1kfutBL#Dx&SvWGLAO^Dj zMV@x5a3hk)BL^FV`r+W;_)$Im*5fV=_;WPX%`3+K(c+TCE%T|u zCQwl?{txP9-jK;nuFdxB>lJtBj@pCaRo-F+y z%2pv0O*$hxc64cfgGKC{MGM^fayq6M5|UkG zks}HGNDQoT;Yrw-cKsYh?B~8;&qu}}1ycD9UEZDz@jSv54R2)Lm*wEBLU*Le2qDtP z$jfC7gZIc2z9JR!G-Ei|vw@{Uvpts7C-?3^BSfpExs)2sP~rP7pp1?`8%CTQjAs<1 zp3^%c+#1(aU8*hO%MSmjdt%}}OoeHQdO9Ozh9-A!rjOnWsBwPRYKjO;$EAZeddn8m zxlreqfi@JW_c&*la3jgBzOPIVwC2SOpFqj%c6Iw)5B~$~Z*SBXB2BY{sRS{Gi(3sx zWz*$mm6>S~42aS(u4Me~C0edQQNcH*(utbb_kd%|r^F=xn@a6fL+XseX~T_<2cxC@ z-slh3HC0u;@Jg;@9h==54^~ysiZ$-xwIcrQbDN{&|DHF{;wc5lS75VIIHMu{Tu)MlP6l=i67Diwp%12%Q2$)AI zm}zfmUw;sV+oW@OG?>>?1!^-7n1GGnrZh#ooZYP+H5qq)%Ny9zDL3|qM}+J%8KoSe4GXZ8kvHC%h?^4WYi7~a6i}bme-E*J zR4@tqgGk|;zMDxtvvo~dy3@YVb}i-R$EAm*3){5|vu)GJDw~~8u)zlwz5!LHn~ror z`Ug6j=oYxGCUnbgYF$WU(<{?~WH4u?1(?74{bA$IuzHEP!v{ibT}k0k5aAgD)>PGF zEMrbd)}IG$NgLrOV$5i#?4Hi|scfMxgz7b=O%NV4-YhrgMnzBeW< zfkBnn2ZuN&UmAutqaY24^dd?B4w1HJ%09Bl%Run zhfv4Gzvio)ba;D@a>Z?b`Dd$wY}-_)zcXfy&EKM*L2@-=_)=9MZ~$L$Ui_X~+I`Xw zY*hU>FQtpcWW&E4R}N#9&L(Ql zuvGux$2(@#`UucDKo|qi4-F5kLvEd2Tvyf26T2y11~-$OjYe_hL7OvP(Au+P_S&r} z6_p8}YQq}rqzDj)s_n5+ebYLZ`+f?VqFhS$*~@b;uJ8`uciNC4YbZ8Y`u4Q=_IUbgA3`yX(b6qC@H==rFrT*1Qb@XV^Z-Yxgs zB4>Pw46oB}CyOV$r5zafk-^TOz;m+FN$Y6pX1Bof&4#4$Jt*F&wC;iTo#JX2dh$Kr zP(h!47o8$-bSClJv)7810*eI;h>vSZw)Z~iQ8rhWI}O@_LMfBO)&ld+*6Tk;J6Cj5 z*`~cVq&~#S+-mU@Cb>js-SaH&uvEx(bs=#q3RbvWt6d1gi<9v4VNJhCoV z#2Y+!+(Y!qCaKN%f*Gko&@T}|iP{71%w&P;ffD>x&Du35AGVoLH1y`(OCg4r!xCz$ zu0ja~aDGt*b}sQ=qVuCjq%3E;Wi8)ZY;oltb}50cb3(NpC)!*ELKIRY#Vko)vu%W% z$`8+^m%B~Ew&A%QCQZJCl!?5RY>x}JN`2M7dA#-w$7{3=R)h(*ucz zuzE)QJOKQXOlMQkX7L~6I|SoQ?(dlBNMy&yX0?eIP`)-FMAnOVxAJ6W-Nwbmzvr1a zU2m73FqJ-^u_2=gsnqXfuN2JK3$-eigoZoCi=%@aZM4SjDS|V0js3O=!42$_Bge&6 z_@#}edkF2(npN~!6L8U8iF2TnDs4YcJaXGwuVT4G8t;5_sP`b(%qP{YPT_<^KGFvzC@dUGQ_^>l?}0Ga4Z*-nS6yV8_CJf2Is)v z6@*tB(dV6depnNrTQffCp|i$22r{6dd}(c}iDcm|k=-Ce< zz4+L8#X)^Ew*WLQ_brJBVl2k^&;Q%be&1n#qac|X@Czg_yS{F8k@u`9W32jyYMu;u zOmHy;Xm^@mEyfA|=exo_2piK1%WDuukViUu8;Y3GZxWHDAPnvNEaf?3PCq3_c# zp0I79dBbK%@IigH4B&)UP2E&nAdl<|)6m6&Y+Z}Bacvwz0)}{TYTG(tJPH>2qcsLm zVjAI&a0Iy_9hto+Ug4`;f^!L|9aGkk0&OG8gEbw9vs8-tgWrx7iFzg2igS` zFVNynfg(XGxLXpOmLP>7CBb#oaA|O76(=Fk1Sd#~Bm@b?9f}jQxU+87-rw2h+t0br zx%-~y%6{(M`C|adWXzE{#~gFM@B5S7?TkMC2lp%xeepeBa&vuS-R%$Jp^Gc0I1e-r ze`2A5W9i01wu?Y9q2sq|N+1|==K^QrK#BH(aSryY4PKWLi)YV?d@;+-_osF)7Y}2P zNYaN@({IWeh5bzJ{}Ga^ynUHS8vC<#?6|9wQu8{q8~pX}0)*)>4+Dh_w|D**mEqOA z3wbnV)twS2ilIhh)+7qm?$evMSSVdprWI@cEn#$bLWmMck}q0pUr{2-P~WhG6E&DF z^WS0c9HpO@IlGg;sA6x6o!vhTC^Ysklpf-f3DRAYz^e;%o`o$i5%p}c|Akq=!>~wF z6`^e0&4JbZZ*_c1$h+SWI>47xWSG`d8h@==e9KU=^zxr7EbiptnANTIzo@)~{${|1 zNJ)k$-O$UQa533 z8jqEq2R35GGEL{!WVhNTC7KKqb@SZeI$dY(LJmfa8kP%9e*2RUzK15_`<&d)tleTU zNpfl(lDOn`R>AWRc`q+l4Fjx7mQwVT3aK(g)JAj1>>!fpxKw{bFJBe zzS7SvjcMdbNV%vEbrr89wL8;xwPZQP7d;W7Uypm9vS%6L0@b}A|2Zzsp>we)+`@t{ zh(R|o3}BH6cXLaKtSgHm1{_DLW_*G_+%jds1KToGBRX?Wg&hw05t36ZLJUG$CdoxY zZ%h_hwzGXDxS}e$(z6GbtWgy z?sax{bIPM6Ck4?TENz4KyAI+Kg30s) z4&_LEi>?$!q7$+Nx5O133@&~MyYG*x@NV}l^pw776P3~^3>I$O@9B%UyNnipj79V8 zFKG+TJH?rb+{nFwMzj%;8{!=DhpC^2cFA!vQSFjVQlRqq>L#r##iY<6muao80b{2i zM2j)=Tl4}L7qz`hNR&(I$*$iUscg`!k^q=WXQa|F05U`lLI80FZ{NMOPwgzJRU?4k zX&+;FKplzYdX+b2EZP5}0$@#8Iv*tybs(>#9MS<4mY@71*yl(+mI=a#20)j=DIv0x z5WEOc&}+NL1PB=cdrtKI((LbbufU#Tbkivu>uf#!Mw^;#a_Z$IE1TB7qWh4JLg3{7 zJ+x0ptT!%*!Di|FWtWA_;k%OS8ri}>OibYI$Z6T~_eoW|p*KEDsEt;;(AIpZya=7x z$*`92RmOaIP3(Z?_*u*_`t|f_eb+DY+d0Jq^m*I6U%r3fIM%Wq6T2p zu8~`2m3T_}>!O7LQQx8Ob-ruk_AcbN0P}{Ku~!VLnCc%iG}Pf@zG|kluj4DRZi0M{ z;Occlcp5{{uk1n34EtK*%9x!1$?3?E&#z+?@*?Bgs!V=Q@^F3Xz@W2dn1i!>3fo;7 zUi^r9=Bd!(acULY_h(HKR0r|hiX{h>`ODquP_BlG!Tk^&DWR>e zc^$5264|aJh8vPbeeAj zjuJj1Hx_HQGFSNo?D+wqNdfKg6 zT*jE`Ue7O}8fT%i%4q<^YT(#F)admjgsEI@I^gCbWUY`$?x?Fb=qRJd#z$(0*-gi$ z%D(-Kk%@IPhA3tw^$y1L;YiP96O8!Pa4NWJ{Zzd{y%Fhk2lqu7pE$8D!UZfCAJt@h zBCD?=V%wqWy8p^a2kfF;{MB+=!_u^2qwi(7uM`Y?2hUQ(c(BEv)~BjazVVmfnDnPX0RR_pbdXuZxslmYTMP?__t?=P1ePf9>jm>$#I z8h48f`(c{TR8+S^hr?kFP<-3$XDO^Y_RG77Zp_OnbE`nPufZq-N;#x%gSlB z*s*1Jp*OH95r76s!ZKUwHvd-BjJk3S;||t9 zhdiTHT4aCrkL6H+ZW$?<0|A7?{8Fp704%59Qz*nx0G99<6$gCoAevG;r?pGVHah$7 z!C$`WOZr_pu38h+^jpLU@{&+oBl5J0i*^k+sD4Re$98 zDN>P?JEnO8?zz1gRn^h#QcvN=gz-ct%27aj>QkXb`;1DYDwlV@2KeT9{UZbZozanf zW7E3Y%c3n|pM1oW1-plGKSwo+cJ@5S=&%p@))K3l5JVTVG;`Lc{l${^GYe79^>W6f ze$IM~Ma?|bBZhTCC}98D>5>(15f>57jsUJlN0zl^o#K$fm7j+pFgT{qK@ys-#DjxXbFFJ9{=9DvJcJyT=tDi8>dpolE5?>sLt%mw5abfFm}r!1kLi ztJIH^Upn5p;@8GRZp-RdX>Q%u@9|C+6?=9qX?{m62=v;fj6ur3HwC~!J8cW06AiGI zwM<5vnQt#(tI12k%6?EcP@L^pRTPSg*~ja6!)ooYLW9t#_(bA)&l4##H;uEg-3&G? zHv!6#R3sD4dMB}Fz_P^NpATAq=&FCS;Ky8iN(3Ag8&Oq=HsMLXf*@*sQG zuNIl%%t3J3;qGg&)WlO1F;%LdYy$}TNBayS!fx~izS=%cj<7MFAq55?c~jYcpJme^ zcDbU0Gd5{3LZ-aNNs+GGqZr>W^CTW*GK_WHS`*NG;OQQ6Cw)t<*Mb09C_nRhLN*(2 ztokLRYss!8=@F`dwa$?rUNNwAZZJdIbEjS}$gs!3`aaWcy>j&@ds_w02_*F$0Z^X# zwKK96gqiHNg?@nsa+&#LnJJ;bYbT~g@F+#s`!dgF!*zDxvt?sMpXMl;!E6R0T4iw> zQ;TlsG}@NQ3jW~CF>PO@Nd3}8MZ0P0&`X|-kxM)bc#Lq(htatWXYD76BQ27-g8~_Y__jlI6}yGO&}Y zr3p6$Csh^+g56?={f7Fq4uh62jIABSNNI61R$67Sc3-e$*qgrI8CAy`M`hIZ-~j4E8Lz3M zJycM{VfWfOHZmc>9U9ra{B|58=H$z2Uu^0$6O!c-kOqkF!TOE2fs#Hi{Tx~BcNPJE zT{32B(&kh(FxVW;$}9M;n+X=~c|1_$`apxT#OY1oJG3jDPjjhq!MfwUq|)6gQ!&Vw z^nlgAuPbP>_4(-;IdWK%FJ=%p%(7}0`aJMRDuDf7$LixT$4p#>_np)N%p$MM+{4r5 zKFdOf*qoB^?5>7fUBSv&W0@Wi5j>UHyeR`z?GW)juMJC?^~uPlyWQHv(3D{XAh!1e5{mi;qdWt?Sv)5H{uS#Q z2S^-ll)_FqB1f~bSPA#8laY-MTRB~>0-$o%0(L%tB$CSdUg=fHSqpk za)svIdpzBw4{a_%e)OHLBh^k4N%5A*S5oj7GXA22PNBN2Vgbo0WkHVtqHB4MBAtQ` zu{rv+KC05Ash2!ce;~~%?i!NN;_G`-2@^1MiRSyZ!{aJZD35NH)nSXt4*ny|Td&rt z2(}NZBsyEV#aUR_)K-l-h~5V{3fB-#iJS7lHnF~n7TYSp zn54mbx-S^vT*_%Gv@enh>$V3&L-!#2DM*_drb7HMCexc{5m+cSf`dx+ezZ=#mvSlh ztfE_w;QFLvN%|~{I<>*JiN4&t{B95@S=8iP$7cL>woTZ)2Ps|4IsVB1W-eWGrLm2h zk}E;kJh6CYzbkew9;rH$`hut@k@>ycf0ES|&?kZ}BvAh1^n2-tx*#Q|CjPa4$gC|3)m$}NcFR{v3dnBUettdOq=PT z9{JO%#-vt!R-=y3x}nt^gv9bPK?wy8d0N2!15Iq=$`WiNxjq)|!yqZWFp~in>M60V z``)ex6_-8~SK`=bs5St5bk1FcrCm1Wzkl zf{1liaZeS(*wh=SJ`p$oq@jWPjh}mQC87FeYUrI7eTP5kyqdKhO6RR@%*qO;TvAP2 z0<7A%mb4#zjLaYL$=}Nox~aXKRW22&o?z|DsrS<&9@Z&)#J`cnU9cgeAez`P?e0C& zm>C(rpl%M5(P$3L`P$)$ZFscj4l5ycn|8ViCE1eG9g&35-aY}Rb(3(JcUqX!oEeeq zwT1?^-uGe{=eHG__*$_Rcf$amfrK0-HIRWN++1mrjhvWZW(aZpkUhDe%}GQ!n1#vw zKEmZDGd$$H$_gvYc45sg4-UU|=u6}#6Lg&cD#QK;01jhMGyCR1;C=5tt?|fhfW6vk zz5%1nNjh2`dV#H>Bb`|h{Sr426{cCBLW>m__h*Vw%($4r8fLF?cqdrfHsx3qb38-B zly*e>_8#@wfNp5>upJe)@&YrWs~W!C}K9>~2x4A@*p01|~st^m2Csm+U zYbkC^Q{zY(i4NlIq@c@?HGO6<;ru@ZI>Bsq z&cgQY*d2(F!-V*9DxVo(L7mrc&J@EO9{F`ZuWoYTj(w!1!w%U{yl>j zYyGL7*!+Sg_N!CXJ+0mJo-{@voz4Aw=2MLrTq95|t~7g*vAe>6so}v^*68cTv6Kq^ z0D0uO<)Rh2Pj-CKI~%VlWT}Yd;i=*=VG~1)@dcNew7+zC0~pd}n2(7!`yoUd@kyqB zU+@EioT+Qtjc?XjIDT`L$HmmyjwX(6MZ2%0omsS%Sfy97>40FK>Nia>&f>hV75A}D zwQXjFrXZ`jHWYjI7~Df=xAo(oT&S-tD@zu}5|_)ethjFwAUXuI`b@0N?S*c9FC2K0 zS{pxf<})Ny#}jWpI_%jq{Z=5lu)_0Me$p^@Il2R`Q7-r~$=jy<8W8KLO+&P!gUyOI zXq)nS3S09Rv^$H_Ch%AOai!OV(EAiYRC2_7O{I(L9^}$l2oG+i)V{$LE&=(~0(o^i zIYJU|ga)uRN0$f3uJYPzmD}Dwo$78)sv`c@9pho-QKU~-g5JmAs0%DFAWJBoO3cHC z^uSqN4O&ejpZi~4{9XQgeOYpD`X0+sTb3A}6^v7FWp2O< zqWhFD)5V(N^|J%~n-@o+#5GW);=_eS|E`<(RH^m`*sVc#c7RXsU;CvoixIP>LOr%| za1A`tzX%UQU2&mKZ7#z^i=z|;JW-wlsR}sg!D;~RFl2Fhw{lHT(ay9j*ZG~jU*P3E z&AxTLPH)bN=T;7<2o9C8d#u>3g^?%<$3*)_3c7onA`5X{g*xSy6IRR$@CYI0`h(1T z-Kd_3$#V$cLaEEpsu8U^Mu~4z=zP}`nV0#Zx+r+M@*vA4%Jn}P9k8E5lhSK*0gN^& zXVBMGRp0SgLxFifH6jRMo?5s-nbLPHirCmd*GdC2+C8QmwAYfgmF?WVHWvfvC#+JK zbo&tn{QC7_AuHT|ijfi8-_AS=4L@&rt{ww*%0=mESSU!dN(r{3W=)gsO<|56(1dTW zUhn&2%+Vd67KBL%J4GTr>zhioA#ua1;8>UctW|2yhXXVjKhaUpxap4duzds*zqX8O z99cuR-t4-DWLy79G4x&wwS}?#-1p4?R6rU$DGP#{C@H1PvLp>1>K3)J4V70&Z1h0O z5?lxTfP--XzPvnsRe$Onb2bNq3(RNQN$c@yuL_usl#s6{`|f&l?RN0pK-IG;MWLQ; zTJUjzmaC@^@Eskv2`!?0hifGg3taMmeK(S#(!+1S383@qeXe#E?#LQ(cH6n_THWQc z?GlHrg2|esc*zm}(#$6s-8mSQk2qiehh-BVJf{!DCX}zYP8N{%mLdIS_tvP!(_CC` zOWG|hu4d(;WW*=8awf}XYjz$yR#Z75tU&)9rm*K)#a1y;WBou&xX5z2njxUEn*Lr= zMXUNy=`qQkmH1ZMIdErJO4UxnKcRS=Tj%*WdY7pg>W;<(Yt3}UJRi}wofQJz3p8MWxs+`*$|-f! zJ1#XvtSx4{O&62x5RWez<}c#4XES-|KIjo5>EQ_ckXzmP)>3|G#7bkY>XZ8csHWWV zk*P*rbs@j|)D1t|ucf(NBl~PB3ShI*_1{4o)?1m+_=7%9C!zA9g%e~)%QEz}Wop-9 z30uG~Qh)rT*vO~baFJuHM@gpjwu&r%a!L3ZgW%tB4OAvA9Q!?=Zq@b6n!GaGX3^PT z+PFz3c9|TXOuOX80Cv{rCaVB{QGIfGfRs^r>2q^S^2$CGWwgyLQR@~+8+KAfH=L*G zi97t*vcBp1O4EuZ&NG%Wclqs5dEoDVQNb@%xloG)Qg*d=e`}fCf}M2T)V?33Q{@=- zFo6EioTp-a+053V?nf$6@~u{Gezhb`tfhS&H#*?6X*i z`u}3CO|jv1<}9b^asIL88!LSX{ozbkdy}T&V^fK@BS-D*$h7lZ7U=UA6y`&@g_ZSM zU|ZlK)s_Axllejby&k9lwpBRjIpEzdk@=v=;Mr>GC|p6;(8+>l2O`qwsHs@kHk$y6 z@ebX1qI5TOeRwV*rp!901Q)u#v_br(n{x81Mk91Kf}4YbY#!J|whB999!%D1S>hpk zLiV@lVl%o)@t=^&pIUvq=|q(93x1EH#*-xdRe~U_Ht%w|>|hW;H?^}eCf4zVpKwF} z_fP5KFo>XSDREExx0AeRB9Z=RigtWZ;|OPcV0~AAgrSb@umS9?re^2=y0VY9`{^gp z*d!-S{6s+!jnAkGe?Qp4H|Gr;jyosZ0II( zeMLyx8uTtL&L-V>eOi#eTKA!EIv)d{V*u7TCFb>{MUu*!=Z zb-x~gR3_3?XbAI+U>drz1(CiE{gwN>SC8W5D6)A)yFx6joT{o^d+{8UvTxX@#Llgf zlD(tIg>OPJI8)NPDrIYV3Xh8d1!}r2W?M*6iMZO6gipy|?7EQ0T78sTQ#*<)x^tr* z80pxbdaBD(%H9463AU1_;}3*AqH_lSQ6vZKe#-b3Z~v)&XO5pl9UEBnx1UR_FM*JU ze(R2CQJ;tn8mq^n($KyJh3d9*;DTW=A94h;SY>~wSO21EUz1t^VclY>DWi}XjT#${ zL^f-cm>dmR#rN;IZJJu2wR{Bkb$i-MQ|^AtQXUgq>-`=R{V3L*Y??l0nNo>M&2XYY zPN+oRx^h|rxCX`4hJ%Yv?>Z`Cy_G%!7Um|xtdOyUn{D?vv`bC0Fs#zx>ylq=m&F<39~ek9o}Y=) zke3aIs~kALDIu6HY8z!E6PUgt-i7iQVqBZ$)0B|25LNUx6piz{M=xQrGaRr1ym}2r z4C(Ke;~n?U@V)wBG=V|ao#eTMpC)#YGO~R6ug7cRGQ7W+lkdmD8sc5K(W*&HQkPA? z*BlIOE#MgwVUE%#`AZFZVqbD4r&~l>TC9|-vYl^`By-PO6cKD&6BE|MSRek~fwvg` z3l$3hF%@X0c~~<&=`mXb1^O9EK)L!fdbJ5mZo`Defy{|8>rb6~6dg2PUs>q`^Sv3Y zXFgsMF)rU?;2kbxeu9y-%!rPjz~1#Cc*HNNuPo1A166dzYazOZ)n-gXF2X9BGC8&S zf_r2tVIMzzgKWt_(l`ns2?ozGjhyycsUz1s^ar~8W<(8J)^fN}193LBB`EQ#_sg2p z!j0iXtRs`rIu}3^OL>%3foCt_N&4BxhgpB~7`tY8q6N(n?d;qTW42KZJcc6LDf6$w zouzSV6va-8Zs&{MG|yS0dE)HzWz=YKaH6i$(%wX_Hh;>#&T)@)?y-V)VIsJ}8cF6n z#`yt&uc$vf{m06zK#p}7pdf-3mj?PN?CRiUY&~Ap@ZlXQs_D^Y{z=>SW{LI{%#M7( zx1j?j&KY;)C0JbFShuZ`Xuh#S z^SMq{fFeOUkFuu~!CvS7!y$WHkGkn4y~XXfNMfx2>}L zBH<{V;4CDPMbZbwh1Zo?mzRk}=Hj-aBS&y-!tQ4dwiSb?=PB#`Q_RkeAa&(Z##wun zc5Xyj?W`*(Fn?!70&EAGP)Ky7(I(;rKfgh(bcxU1=y%KR)oU@+%5AmSOG*-%$4lq^ zDj*m9vSDY9JmjsuEu4QAHnWu@`RnGg!MabN)#b9CQDwd)Z!P`Lx@hx>dq>0r@dn#1 z9(7I2hBw={oeMmQHpD zu$<|b$eBXrPXXxxcMh6j*f=Z-$mX{p<%Q)Bl4^Ig>qGAG7o^?%6ziQ|p3C7AyL_Fd zZ11J2#6fOGiYc{@t1^VQ;tt|5>WmS%kj{PQYsK3)essd@ZP6pHZA9i)hmne>rFt)S z=}tXvt~hJCKv`3jBaGHh7Xg(uW%W<`ek~JpTrYPr!eGkLX#*n5mgkDpprO832}zoA z8Ezl)#UfAdj|nndvu*nGIoF-%17*8+7;!5fO~k9HIbqdFHtl8nK~cElQ>D%-(+!%M}mm+jB#KX?xB7DuJWVbonO{a9ayJ9BZ|Q{>V?OQlCAL_yZ- zYbCMn1q^|m*>28f9GnwK^25G_JsueU+|Mu9)&6mj++TdH^O?)SxQt{i!N1&ii=lO3 z37x7v*}cfIoA;}~`V*3;?PJFzyw~(NNxUtqHB6EYJhFbivCdR%lTnwsZ0O==*Swy7 zcSAoI^2;~s9QUEZAwTR+V@uBcDB}B4@{&7V@l|=EU3e0&lvlMT>2C2YiXZ^LA+JPA zTiGGSlE!xtoi8P++!c>gW*f-g!sYfzPMhhEp`6TuQhaR-&88~7rvOS7r-%9iHH;?Z zppwAiOMUOV<1Dr|qLZ{!esoK_LSc;f9$He&1_7ifD=EJ+scM_WNdX z7>0a!IVll7M5wlpE2UC(FjlKt(0@_vS@D9U;qa_#L)>e3aU`!Y!KkPgGUQxSX;3uL zNAVHFQQVr#hD)P!1DQW#l%4leRx@wQnk|NFc3ftUK$D{4p|x;pwAq}aD^kLwY(~0j zJl&zeS%x>9dalg`XGUD?Ok7p{n2k3a`ynnp-O8k-8b$KT){j$tU)MS4#X<&7d90d! zOnkOmS?8c9iG}zpK zDReRezxva@_#7@}{!wA7EvwK3!|XBX5wqMl2FGG%bz6B2BoiDS6fHYz{@iZ3V;-9{ z)h?m11lfVC2GOfuY;_UjUbiYHWVuW+c-m0ME{bR5QFJ^Or0)kUQaGy#ECl;S`9ohq z#J7aQ_iWp`)$dang)Hp(XMuIjQx5vIKro=E@eqlsPYHt788?jW`37+RX^-*YXYx~w z16dr9`0P54cTt(+^YKhSOIF<=_7p{D{ep!(!oYTq*O@pz4zHiP+@BFh950mk&>DV3 zgeRs?eEaFPM37aorMX{(ZAvEdnN70yP4((l+MEaNbc}4+oV(Oc31p2rEbfJ#J~EGv zC%Oax{mj5*WLX=ITi}j5Zzxa}2*O1HfquR-Pp2};$$NT2EPAUfgcK1PM?K$@{RH}A z0eFbrpCrkv5|(RAC0hC0YvRocXE|Qy0dvpsmEeN0m2EG%q+=o-53s!3C6dvYj*BU) zVl^M>c4!b7V6i-grZX?&I_0%5UTv$GY%0t4P388-!`HP7?0<~+N7PDZ7ejmro*=Jm z_O-Y<0Kv`P%{ue-T3To)Jm+<5?!=d+8M%FWHFfnlG%{OR8_S(J`hwW7glHLYh0eZ< z9+M6ZWxi+AH6|?Vc5H%JTM-Vhpqt+AE?sS4hLnNrZBqN;<4a!I&YdTgA9Oh`Z7Ybs zr~f>|OgA?H&g#3mpXFB3_lwP(w#CGU5QEAGYohrt>+zZ z7bNpO{SXKjUNYqzQMbphhuG@xZyrfI`rQC$Q=5Dt@yH~R+720ws~a36ot(kGIypU zXO09Wh>rdAs^iHb+CUnrK~=uyRXpIgNVGFJ#T6;%U=xq~7eNZ;eToo8UIO6kltJI& z->nqC?ZFtIb4V{X7?}P(ezq(tWxaT?oBfB_@)W$XcLqS@L`!wTZ+S zbS^|w1nYrxS0Kt{^Y#dmQ-dKrs*37H?)e%EpL?2E{+^5K|5FnKi;YX>eC!|f1?&Zj zqs<0HXGO!`S0~5#s!dnHG6sz@_;n!XdF-D`(hF|9;F1;{#*+B8Mhu?~bdBuwB4Th3 zacl7qgt5_{%{o{zb-4s4_s!|1+X?{exNmu+SbZ{^1xRp3S&yizi+4+hbk#kL>Ta(| zGW+-~c>bnSJY_a{766rG{nHZUcNW@s)iOvy$sh1afKN3kV3hZMW7_bB`k|kodkJ@d zQ$f>#Emu>iZ`eCpiLT0xouBfH`M8#&B)l*=400S6t$K~k4q-Po_v6i4#ZGhKZiMbR z7w*FN2`-N-?#46a0U(PKge7ljh1U@`Id7vPI+i_8PHF!nXrjYSN zZ#`+{Zmn$nIzM1D7o@#-H|+Xr1onPGLV4OLw&VBrU|F8?0 zAG|dpveQDf@@vEB3!)$mx}4=#LcEKU>9Z{phoW{M=>*i=HDrtHVL(^Z)^=;xo7%Bn zd+yWixycFDZE1Acp&zLxf#h$r+WLNL<{vLM_(4wP5rm{W%J(quQyd<$e` z1Wd4O-!{Id0dp@B=ok&@89+(c{s6`iai}qmjRzuAlbXo#BpK$ifLdkwd=r9O>YB2% z8fIoQX1<(5=Y|GM+jhAv!<}tHll9rJ>78vAGb|rmi8SmT^MhUadaUZyZ&%O!aTZNA zqK^FgsaU4@vR~bhk*B$F3!y|DB#zMmF;gsA39nUK-)09x7cfVamSNZKqk8NeXXJiF zHMx#%M@AnbWe|0>lvWPxmifWjZBGvBp1=CoKGSl_J`+n^%8=D2-<}YV@>F6~fqC9| zpkR7!*BL;uGH?iC#v4U2#($1QH-ZT!C=J>Hx&Y)Ssaqqy>oXQ?!dolb{%wa1o-=iU zKI)mv8C$xw=kQd%;L53xF%N-?smj-7hp8FPw>qUE^2Ta=KTi5l%G2z^X{>}{qNyZx zb_ne3GNfZrXzt&w%>NhvL38>OHNgyrzEg4>%{Cpj#KkZv2OuvSf^0L!4{~ZG-~n5U zFD;Lh>WUqp>@A;fEcUI6?YTpm@Hmd8{7?4p^A!D)B1oRt_VHm?9w0+V9pxqq3?>Np z)j!MpAl*f_B^#5byrG#<%a(Ea2y@h=+8jEtr{u)?Qmdsc_|X;qeDS#ZPNP}QhO(xA zXG`bU&dOo$1xy`en98}njf@k?pABb-kPjy>F5`{~JIQxb z1OoewXCH6cgkE`C_kTDi(h{HJ%B;%H#}ZiM~D@qXY+C{3_mrx)hC!kQe=0cGveOKVb)H8<}1x~)_rxZ`NiiNF}36| zY)L-!4Nu1ZbUnUf`-xe1w4J^Ony$(s>VUH&T$3HxX~G^&~BTUkn=9v zA?c*de0j(l|19a9f1*tzIgeKo9)Cho{6Wkv*4JZvo?gGJyJ6KinOfAvhjJ~i4DSq> zJXsFc5GO%0DU3b|Xl-!Zz%8Gj0xp4# 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 bT9^%4pHLM2&ocj!{r&$<{jWOkuZ8~t7h5LF literal 0 HcmV?d00001 diff --git a/webstore-assets/v2/banner4.jpg b/webstore-assets/v2/banner4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..571649d67b4539c9d8cf774ce4f7c8436a187ce7 GIT binary patch literal 221498 zcmeFZcT`i`w?7*DQ4mE0q$^drfb@2h-lc{B0U`7dN+5LbDAFNFCsd`A&_k~xC4^9< zhtQ-;l^Q@mALsYI?{|M={NBCqjd6ef+&9kLBYV%RIrmzh^~suZubr%&-^AbF0QWUj zHBETRTt4rNi#!ixYm?_$Anfm-<78f9X&E z)@}Z!%l)nUc)5FB`n>vEhZ`9vUFx=%`csGhMYs81bcj3rZ~vG}A32x{;_tTpmcJ2G z+PNAVULOCrd@%z&0R{jyz{|h;fBF7W+;RZ`sUra3+J}EHvq1p>^`QX3BhtT@aef2< z?!5;9>W2Qk?B6+Yw}xB)kLs>p?yuV00|5I)0Ki=k06_B<0JvlRKWvw~{{Y+LOB3@Y zF1O3g0pJ3#13U(309*kOfY7BT3U~$(0Z9Cw1}I&Aoc}fXyORG}4VP#C{tTf0bf_i(y?_1cyHyR(;^-@JAE&JBty*REf^bcnnU0NlKKIXCrX`kGoV`LYhf5agALf;r@nwVNVI!WZlcxmzxPz#F(d)?rK_iR;Svh#-|=$mvMc|N^?yRSb7}XWzU<1CE7z~x zzIm78-tAjgZvP7^_00z~Pi{RFp=E!eZ(x`(Jo1ONM||Qa-6IZBG2^$%pK|l6$DSLR zz&+n3rBv08-==5a6qkIdWD^qFF|n`Fa9P0 zC@+b-N_~wQpa>ZGI|lxde;D|OfqxkI|1AUddX@ofmQ_qz<_6oDYVT1MHCtiHGw(hz z=zbn)Iul7W8nHBE^E7k0n;PSirq}P37+ijROH(|w#lc1c6D<-CoMxxN0y^OBB zn(;4c1M+b3LQ2%^&kjorvYq7|he_rmoa%l~u#`u3H6=JpzizI&bQqs`w85+Q=`j(X z8>hq7w&xU923|8YTiVIg%X+eX>|^N^Gs6{Eqc<#aTbs>zcB)RZbtl3sHr7z7-!qCU z1@lBV)kG;hJ+8kto;Ww1e<RV%zC)tCHW<1mF_r$q<|kLi4@c<p4%qB+Kz{X`wskqT?XRP{4%QLMu723eVzkzyQkt;uxso^yCLW`fhPxX$RIPW z-AUAGR}A;`l_ejEXL7#*H@m%lxs^?aU%6lP%g%M^R<{Po zYQ5Sveb6`0QH15w@et$ek}o&1yD!2c&&B?8YDlm7WlJtw*2!aVw-R+iFN6Cu^Xu=t z(Fo!Cb-p3W`iI(`c2>$A5cm+?axjV4BA67wL|5AQd3T1#aCwSK59#1LAoyc2k!2quQf$!S$@qx;c{pzX6$n4!zQ#Rs>GA@m5z~sUFR208q=& z?e-((lCO@1%adu@K+k*NMblMjH6K(pSu92azvafYM7)?yN^_8r{bsb~WwQVjke2-% zgu_XjtEud2p?=c4y3K}{2)M-w5J_fgEbL0Uy^}-*Xp-WG>3N{-$m$n+d}xFO0RC@e5sjKN0vNd6GpJzZt$u0mB&*_I}e2Rma$a2G}2;yTzPxt?a*0L zl13R;ti&H?U&d2V*ZDL3$I*c==-_DAmB&+qr6ubwPNI*6<~eGA1Jv4b{5OkUR_kU; z$|cUt6fVuh%rwHr+Q9ov`b$y*jiOGB*k0)7I;=WOlxc=Me%7sBtcCEMdp4k=HE!Hr zsN8G#XIxvKxx^Ugp1v1EN+SLw+eJ{sE_Ka28CKQPFD%hBGU*sl=n@~TyPG3Y<;n7S)t z*xM8h&->8Kggj%wgG?l?`Pywq9BFNz%Q(or8{cP8agkRE%3|lDsF|ERv1r(ze9%Sd zZS3A$l&agt1EVrMfW)0$%L3hm3}kI~3CVn)kkkd@W^7VfmsULzAPn~Sp*q$w{kaqk zSyF3=$G7f^=E9)KO=}e#L`>9GU;BDSf0NuUO^RH|I&HZ7JmZuMMD0LL)vfL24if{a zJ4~x#i1rJ&A^1hdCNSG_<>ZDXEJoh3%;9gEwwpLZMAcg z1jd?Jhgj$G2cP>yHUvX?ELQYPMse>hTvDnwOcTMxNW4(hbdAN^f>kG=m0H?LQmqKw z(HOxXegt-r8>vdS=-~Uk%06$ef zN}b?PZzStohlNOlF%W1YQm%2Al!#{bprV7r_oH7)3p!0gjkbhrJ$dX7*pQ8W9%|_= zcIAsmEwq=bp|M|8Eq8fWNvipKvG8Svca>%>ZF3Cma-{-AeVvgs0`Z6ke2GTm4|k>4 zXI1?@<-2q|M*~6`eUeQ>fw+0xKzodf(4Xz4Zg8EqbgWuP*_8RMGiD}1n<9Gr=gpy6TsklV#STc%^`yee;CHE;8$#gL7Go3+>zXuQW zP`pzj+^|&4f6aIDv44hJW;RZGvH$!*5quL?5O1{HeEV#R5$i0?aXkYGR;y_2DEls) z?a?%2zxTjtXe8;V{P}gM+RgU&&I+KtI|q@>zD@bxitZqEp}Eh%v^Aopv0JgVZ(+ry zxM`FszSjwupg*$4U|t0+{4@4Oe|dE}%&SNs*T5mn zvYW7oT#nI{eIU9QK`D0+*;FKD{Qex7s%^Mw9#idVpl=06a8b%fQ*RP?*}pWRDmhz0 z646{&sS%IX1`Aj6&H*Tl2Q1R$n5F@PK1}gpQ!MW(VQlZ;<)_uFN{v*&QQzM0>zhj&V-MA3e__s3u~`frr*QekPT~G?yY5s-wvf#e*?NDjRY;s$TyHI z(MylWPs?N-LTn|bI2+VmZ!C&3FqAr0kjnZ>jw*{2P|2z{zyk$#(e_Rl?B4mB)LsvF3lCr`o@=#uhrby9$UM8|-U}8_!b7BTMm?Kt9`un9t2k zi5NBJU7=Fuoi)22`ljU#1-%VjmDi?JvgXLw6)w)vv5h*hlMuM)ok(+bRxvB{+duvI zTKrRmd%0AddT6h*B#bRGUVXL)DYh(G`l0hn*+XITkN*9#My#}T&)|y%B#W-ZuY&kE zCxJwU_LiQ5XeU4Az;x#3v0?c;0?wsEKPkg(}E=rpdZRXDTB`iX@#(24`-< zVsR@jE@ZHT#1>@&+(oom#wC#!;T@lP<1VN<)>ix*5d5mKBj%8>tf;D8uj)u>k+{d~ zn^9G~@5%-{&&|F$ST@3>s$$Qh66R{osA8|XFij(jb6m9p3Zun;d^(V@vRA8<_-Lk* zbd%2Sc9Z{&u8w+FwQeM*XR63thM8cD#WlL+ww}+sNcp{{o}+a`%f8xC872u!+@M8Q zHUhl`y*o7lG?Fl0cbfLwn~f+w_?#5Tv!OP87FDqkdlBx;S~O$5+{O@X&`Ba$MP^16 z1VpsN_qmrO7LI650|T_I+ZzgPK>17IP6-S57mMh+29=}G=@uo$am4wze<5|wFNlQC~!6AwHCWfEBu@snf?AHGs@x5r|Q181>j4!2pVEE-6< zV)OaGS?>QEZcuHV$@7V4f*U*o=sI);U0?Y~o#Czv)a7;COtIlNov0-P>w$2t!hDrv zmWg@f8LWj6;c;94is6<{VwD8h&ZnxbCn(+JA~aE!_B>IRh|*bwqHOPVynTSCne?uXy|782>iIb%+TrW03 zlpzqY%)R#&UcCy1tiZj>i9-n6m~45`)n?tEm*l%|lvhT@bwQ?$X5$I@xp&qEER1SO z^fLZ3pE*z*lE}7tQ(5N?OLYl6ktwYYfQJw)Wz5=8GI8+whERyHNTI6Gh(N0H&bCYqMIc z$_mlH+yml~8ST1*Zb1pp6~9fe{F^=gAM-!7{4*T>34?#K!#`Ou=$|n7Ck*}xgMY%{ zpSj|Hw>k3H(KMN8rln&+KebPlQhCI~|K`#rQD1 z&MR|Tn1ZN_nskzX+PxvTQsw4jHFFQMYJU#P)gp*RaXR^XR7wAU@=?OmxhD2D33+{4 zaZi1qjxkUNn1XJ<&2qiq&;Rs>6hrYpHHEewOi?fB;3HGs~y^gJk2* z7G3)KXOtD@D^dAXa4qBG8^~4T=aaX9(nL5Z{PnBz5yN=fPvI$rESzs${teqLe!8%I zgmLX5Bh)F$iwYD$;>6GbUP($U%KSOEjZTmAswaV0@>11^kpByte6;3RU zBwm{oWo}wez-+POLlh`e7Y0H^!fpD)h4|4n+93TLP1ZPW*S1A`U2mM%dsb( z95@v*bD!TW?xmvJNB(%!+|W~P7N8x#fh!Yu`s2GW|H|0x@a!1D|3;a7w-FgKSXxt> z#d2aodtho~!RsQ=s3q7!`uc%y25YcwLGkFbXW%Btg;|(_G+qakX%-?p>yKmZkF9b+6C_J@l6R0inz5Elw(&9XTd`KT z^4mx?aWr~DTA#5g#K$M24IMi!nOq#T?AkJ3jE=w*HnF4GE1Zj*;(VEB@ecNxnq3*A zG4k}@Jd)+}C`#?^651B`zA7k)aU+M>y|w&_UrT1QA8=+N*c=mt}ckf-r+Q_dHs27Vni(-FEW^rZJov(m?SCo z0QAXhpo^_{Xh!cH276OCO73aauJE5&P68 zy|($u9)||}LfJ9i`}Dls)`za@6XKPGFS*Ip!i@%*&$9%`qSHRnFm>9AYWl2d)ZOHs z;b4jP+FB+By@a%OQR4!-mm06V1z!hPo-#epYgo1~&Fx?KW+IC9nkRK6O1#sCsnxrP zFqiZ;1f>M7NU&96cAd`tX&;FMX>a_u#o^7gYGC%v${fMKfz>DJ$n}MU|{m z_{)43t3-ie=GZ-7)9?Ao{ZP(c1uQLRBi8gHTYnvJ-eog)NPDZ zpA`ZMhV&T4`hdA2_fMPB{12JCk}=5I;PJ50GW(wrcXX?)_?;Q{%0?VtLxP=`oH`Al zG%^8*3`?eGU$+^^e3{ju3cR-Q)YrF;rtf*l#Cs=$*QtQx*^L7%pkheD7J zBKBTJ1pyqxR!nY77`u|TF2TTR1Ff{_WZ? zA5+14kiqQwLU_3@_+ji;UQ+LNER&ABeFxR6PE@Vs2UfU_Q_#%SA{vlJ| z8T=9sAT(L;jsj0D0klP>?6hqc@eMR*oGR#BH`4O4=cpUWgS5-IJF|Ge{|Sq)^53$- zTIt)-O$sk3jnmkE&3r0U>w1iu{0vu#O?J`nk@TsWQh%1po=sUBE$!^_%Iu&CXVzf@ zZ|tuT6_uL%(1sMgom9)GU6p&J_JXmk|3fEN0liv0PElCX`Cy3y6VtRgfW5{qs6A*% zAKFbsf;b^|$W<-z=n9(L`C-92pB)pVQ{Iwmqhz5-Uu zhH^G2HC77T*!##i5=)Mz8_$K!1L-GfhC4K85=3IlB-XAU3mqmolcpI&CGvqg+X8$Z zTh4kce$;FV_?eP$)-R-?hZ952H7?9Wk4i#?n4`6EtUWGOGOMed()HTR4P9GkT%P2K zK{G-?!CsV?O!J5Jg)4^NhfM~ie&R%@cW&^`GP)n&^W+T^aAAa-Pm-%j#bPMD9K;nTOnBbdUVoe{4haOLsFFbRa9Q}o{A1_I<02( z!>=U!7x7xig!iSrD)I09b@5727D0N`s0$5`m_%*@f=%230!e(FP$o4m>wvtSpU|&C zvy_lgrUsWL)#m7$87kB^luO`lI}ex-a8Ejf2TD9`n&U2nQx$tIh>`4(mUHUDu>i1oh9uhL$Yz0pmEG%qjSA7 z$pUwyYa6o)hI~s{)rjY-@)&m6adTYFrmxm*NV6ahxh$Wg3Dyo_ko9+4KW@^ynA?RG zaWOVH6-$tZ7wuuPJNAk+@+FJ4ESu7lmK+c9j{}})zz?yLo2yoovB{@q1^JZMg}o@@GPfR=u0gkW zKF53bKYcW-0!?r~X3pN4jgIY2De-vv1Rw6>WVq&HW!#8}C!xl9$4NWLXVTIuvAe1> z!BeZQW4+T+%fkhxoH)qdzJ{)o@6q;jy04%n0HI;VW!4;puV! zO?1mlXuq?Gm%$O)qClsSiPj-EzMxm&1v0>uz&yTWGC7y3)6-~PIt%%_4!MG8W?YdWOUPF5{m7?#NVC(G% zlheK#qPG)$Q2@053-dtNb;7D-9kF$h{I)idE+C{iUTa{_!k0mZiHaARD*wJOb#^!xTctVXVWm(T zv1wi_AgXegNt~CsSPMxlv+5>fe7a6M-)u9J>TzEqv6vLEH{rzL(%JqnzHxj`3=bAd zThrZaap0}0Yf~ZXMB=cJ+e7A`VV;z{K7#h9;G5&|F=Ci~xlx(`Cj2A3`%lU*1g^X{ z%)O>qOw%EmoCiuCC2xPYvTX2iK* z)Eq|Z6jlgXiW+z)(&~T}ZE;{umcfob`?%^y7Kt$bCMBOlN>;572c_ALd9J*yEdJ2t zz}Sd3>idv8cnV?^9s^nb2#l!wf-%Fo>OA!9j|qd`2Jf}WRN}c%IUG;Ic)0^0W}2W4hKjjW!SKZ$*%st$Bp5beB zrY6$+dM8-i*(J}iNZU;g@_Gqzjv{GqYO7gGzXv;4xY7|b%DV`*5IS1l^Qf}$ghjEV z9u5yNsZ^>0AL2|htxto2Ch3$Vl}I?VbIm*=X8INcNr?=^JE(J% zXg%%k|Dg?&HK_IxFAaHitUf{Pd2OB(Mej(g81pu0X7)EMDV}YLN*^})xX(ZYEW~}l$iZApKgM0!6shrH)Pf{J z!;af)CO}Ia^QJX=ADeXLHV3!gy-S*4*Z7tgduMs_{uIPEE_M=?l6phdlw4)@b8NqM z%c$3u5fg`#X^nItPge6^UNr=vPhr^T_4vbQLn4>EYf; z6^a5QcYh2c9+?|?Tmydi`9HkH`9Eb?-`;RK$?m&tjJ(yq-md?`aZQdTQ@}~MWxKAazaQ=3D zM>!M(0x>1~!U8v$oeyZGjkd56vO*FnDar-Gd(op)&64@z{X zcv~CxQ1B2I1;wM=9|vdVPIq8&YvihuQfK!$4d5Dz%i`QnsJm=sr6K6%>SVtIz47>c z*i=9+Lp)PZ2XMIgi$yzsqW|HHzKMyl%ixKVQRJ?TeqLv(kDlWrb zr2E>H_RU-^vI4H2Jk(_D&qDt^3#^y#g$HIyoh6NlzBV*4(XEa;e$<2V*)%1EtKT&oh2|=6uNQxsbuc6g-GQ!3p+ysV{qcjI-b4qhOxYe z(?K7c&1B89eKWoZPAvBUb7_B%X-C#Sh!c9#YC&FG=INY zxgI>ga*4@xpj^bz`O#0Sm=mE6X9{1K)qr}Y`D zeo0Tq)5yZ6WFS>DOJ4!uuqFnH<~QJc`-Xh`5UU6&Y0^{8%Nf{+i(}lX_4jUW@eZ)g z;Y|EXL$}q^zvV@WNcHf}crpZ)VY*M7T_x{H%=cIJUh4JwgJsJ~f!&IW>E=nnxzVqu zti$A6T|km>t+3Nv4jJ{~%=M)B=bK*x{%j1 z*F7GI`a-#eRGqbD#@?@P+IX#L>Ad)2SpcRz<-!5|z({9Z-E9kG6HfQQ$7s$o|_8#zQ=hO~iGf?~QLk!3lQbAPT;ZS3kq3GA{&9$9sdl)~VR` z1CqR1ly;%9YfaNxH6l6z;4YT&q*r!8l=>zeQWvQAM{H z0WmQbVVr1;_Kn59?x&C%-g;91L}aycEM*q<*!}-G%U)~#Y=2kob8Ui@gQr?Q-$lTf z*4@ssMvm0Q#+{<}l30)%N6eJ2a9aP2MpZX^f0LGUqIbsH<9>;n?{xfmq3o(U9JGFs zw6D^|ZD8&$3!w1kc&|8f;J2K|Z>P)F99y?+cwk50=p^6g)ha z*~|L`;ecF<183P^(UKAUTbA$vb3f=bPcT{2&jrfdhygK~^LqE!agG>QaALQ<;Q5E^ zBkec(h`e8DIASpmE zvv&r7avY0`&80-3gDPyJYj7w-H@(~NwDT1N_ z6V6$0)G9oJHCNB}ft=#g$qXv6*#KXH_MQ)U4MFv9>N$V)j zE)*#q;w+;;+753w^D<7hO-}JHJ8f{Og+R>pJ>t;IRV*7Rle-L<8Ue`k%NY-gkUt1_ zPRzwddTznI-$2m>a|F9-Ub-Bcr+^Y45#H1()FCHW!NsqC@L}fp;^bpd$42st?7e77 zJjS!EIeubtUkNFd!*NvRE!M=3$hXKYm$>pK)h1ST04*S{D{CFS<$LTg8_Eb?5u6kM zU^v|u)2u1!?V5pUMaevn=C@l1qc$dqDQ#*lb%`!~ZAn-e6G-Wj1IZ=yX5*ekk?XA{ zb1yal(?guSprRs&5YWtIA#6M=tC_{VFdk8sGbIp=uN7!4bvYPszVWd6xp7gRERQ-9 zODoYHfs(GOw&b^sZ`h8*w$!dNfN+9Yp<9|Ve8gH0ejb%Cl@`r6OS*H%CK~mCu_j{l zJj%s(;M+uTjgsh_ELtwS$=$uP)0B5(OM14&OOJqNd2Uc4Ey{`IY%Tbz)3eF!@S zJZ!x4otXN>Bl4k%Z<|V6nW)RV&c`1o+~lBRUdbo+Vj8gq-K7QXn7%^ei8I!W20S4i7nzosin=OuXq+S|=O(qY0VBjYdZ?;a+eGHf8BYokqe) z=?6hw$w23eEBKZ-CW?4g%RL&uEkXW-Wg7R$0MDoflYl~35xK&I8(iD2JtGXfAnFHc85E z$XV(?Ylw6tcK$HJdXr%zN{M(Qd_4!n_v#qP6b$nYv$xf=ea%U9Q0O9vHKtj93#>iP z-7aP?vlYT)GQ&V%vClFyt@Ch(l)d1j!zgs^D{)K(K8M6TqWjR(D3*Vezim(k@vIPK z)}zCDoJ-OZj^t;#^^pA`B~@$1d&D%C3_drJ>JHv5XULglRhEviCrEJsmZ#_7kewm#jyfRYXIWm2-F z4ApS=&H(b^GyLx$@=9mdRvr&@aJg0!&ZT)*Hb#1t1m8DujvCv{1=XYvF?K@CDc+m5 z4Sw;-?pdqL$JgJm+{GW4_cfPSkn7E!5p%6)(8b1CGjP`o8vU&5f?GD`;9JRx$9LcCjKx8^LT5Mf7jCL~!7|kuQ3FX)Q=Ry4m+NBQC7j zHCX)uqiTpD3(n1>n8ASf~F)Y zSem_7rSak|i2>@=8SvxqO$L5dWLSd4Kb-8QmeFo0Z{xI|o2U*Q~Au@!VUhw8&i%QVkWTvBSm>%DMrbAH_w)G0LHU5@6);gK9qC4D= zg-^YAKJ{>P2u^z7G(Z~n?jDe^ht!dOt%np1-W-d~Se5GG3Zb2+hc|(fbsTy?X>ILa z9K{D^;C8T+Iw@`AF5;_$nFLt2zQV7Vq+*K>4NHkSB!$OTD5o;smdybwu$}#N3~w8s z$z-a7AxxQK(|`~I>|S#5Xzov4^fXnU88)%;#>CLQ2hjT_B?b)aUJcH)-)-0;dhk?2 z4tTL@sj>7q6Qo*`KnnAO7LSwZ&lFT#NW#(&EqM=H(jT2(A$@*T;|R?1U`Me+R;iE~<2UkdZZGGrr6Br~nyXez)m-wAwAg&X}U;uqJUgpU^E6}8uP~{eHR~njB zcftc&NvXwT`n2^!;gk@MY7(yJq6??^q@jLaz?m3(N&&hx3S&$e$rR-~Kr$tf!#tB- zXS|)^uz;oH4o&&0b&bdmI)Z|{?@|CllcDmtF-@73YId()E#3tKEf<)sq_XvZP%-V1 zrcU7n-~7Ps{nX^RkxY2emU zCW$f{k}d5BvXg9bcFUh)uZ+!Mb1u`)oMM0k=`wM_GD@?xgCZwpl1Gq>YASWalwRt% zL+|DilVv<7tn?*a-_*XZUZRPu6c5wFYtv-QzHdFNeaEV;LkF1(RO8r2k_qUddqpL9 z%(&b~1L57RJ+^epDh3v2E9&x=l6X6YUdY9Ds>Tq@%1PkjnRkLSz*{cf>|vi_Hy?zF zltcCo3%;l%C9;TBSY#uWcvu=uHrM&g3zJs@Qe;1XdkuqoSIC;djm}Q+l!e~;qU4gK z#^hlZ3C%DiHeCmeaTH7MN6ir&vv7PxTCJS&j8VWFXIPV9ZQLRamOL@Wcuud$s$iIv z9P~~v@q;Tj&sOufp4*!7qaM0n&0ny^C-zr9KpI?M$j~Omq}w_ksA8{M+{`l%R;?1F zY^qsYz{Oa29z-Yi8r$(msD$t*=dUgPSluK>a(Tt!k7X-%dZ(7{BF$!h3I^iC&2;O? z>UEQx{h~`7V2un8ed31n4ec@)@i5bc9Wmya5GR4y1gQUm`R{=hWjX!70h_;m1N!M( zOk3*C?b?m7tDJ{M|7K0|u-Tv9LzX!7YkV&`z?Wy;y}n#r@r;zBlQ8q5fE&y8G(qj4 zKOs*zTiKo)N?aK(R{@I;(|7y^+)+Q_j-(z@C9{`DlP_!{mF)n3{b2astwGjMbp0`C=v?tL``(PrdC!OU>L&krD`NFHm+AZ> z{sx_Qd*Nw*S}byn(w{{6&n(1HKc{0w>$#{-I;!~{;n`i1DI%EHN>iu0P|dE$%Bp5r zEl01TXBZohWMb*ERwwscpE}%gDgG~m3{ZtX+_8RJb6!Gf!nHXf^{l@EeF*WL(23d| zXmbQ|6na;qOzbpn?GWhpvitiCVXI7zobpBGJw~QK8w6^MUVLnKjea%mC8->f%wkb^ z0Cm#qm%xf}gZBD{qBAV{nf-=@Y8ESF5+w$_Ei9aWN?7UKY-&7*)A69!MWM>}(sE7% zE1s2(WP@*S9rA24>6e9-GZAv-%Sd34+%@rycsyme);@cx2%0MpEY!|Gn*I7XEvUEDW~4!CP)#_)fVni zN*jmOH+b?nnR=VIRkwyjklOqE;25=sLQ);5Sj54L)0%t(cTw4r&1+Yxd8^`c3Ktr7dj#g3E4}`Y@at zmdJc1)Ya6COIqZ1OW`US;xVGklAIYy%f6~fS*yqtkWbi4!Y;ELhxWr(51Z(~rnb^# z@g}riT@eML<+}J+i?D?hw_%ZQav3@y@ce#X!{C3|;yIXi*NG z_>gSFZ2r%W<{nxQSnPpDRb^Y=3GRl3P)}B4%{Ez7t9FdanUEPg>ab}J3rI9yse%ez z@WzVW(JpRWWlAU~?e8Q29`M^9f!E6@q`x1~Fsvarmvz)`H@?WS{E;=?+fV<&k7^3< z0gYk(dB?jyvM&AS;K&&RwmoUqTQ;f(WtX#b7&qF1#px8&Y-L=1^er>@`#}d7*O#4_ z`Fh22cKLE46rD&t+DrH@oaILLH~qsMyXHbuI-P*(dc>irX>iY%r>wyinI7rf#rxhO zm^&vX;|z3~C@khr$LwkgtHpDnD9IxqltM3%;baznagPvac;mSbvn6KO|gL;$c(l& zvXxqmTtcvfKdm84M{sa~OOzl9sJ4ri)*f$iYw@RGA;skJZ%HTiFOmm%z@b-Z!KESj zS2ex9txaB+dK0-W@EZU^6t4D!PCk5;6_7zFTqQ3dhIko!tM5=iwE~MCjsys0P{!qX z4T@Kn(G@wm?loy{;f=jxn=@97Oboa>K3y{r0>WYx1NI?-J3&DqxQPaZ;c13JcP z>7gu-TB$TX=wiz-aCx^2WE^k9$o*yF(S`*bx73+Fi}&Rt-LKXD{@bztU9QZ26T6v> z*xPhL)Z{8IDhC%1tpwBTk~P?V1FV9(%6|i-JkJawhC^<@=mWrKyBhK!bTZcjq& z+pl`_bP%lWIV_BR<0jLpk__;E97hkd&v+&mpHt_+w>P&p*@foY#5YAZ@${C#Y~5?b zh{%fYMd93NupHyQRY<*6fbnSe;-t=P9;H_yFaO98PE)pIv+Da9H-4af;jnQ!8}`7@ z7>J#;h1sjBFf#D$%NUq6GX z<`vh@M~;rSr&j|BJndHZW+!pqR(8*Ce5nsm-u0!WNk7B?1}y0g+{a{>xe)cq9HPS8 zTJ3P5wS%}{dLiw>i>m6F>8Yt7>q{#`zhpICmDL<`HkaEkAA$aH^2aH#mqp9EsTwII z>3tYfq!iPQr>X`A7LQL1=TBmxqD=`?J$DdUmn05RSGSLrL|&)OIO6k8O;Jk^u6ZeBBPq-FnW!fr+Mj_)aV`onAEyg@}H)%p)wmGk3|IiBZ~ zHuK)vWqb3!+5f^yk@-}1Oxbc)dNcP#ae<~jB^|}DzcEWI=aftKKBp-9d3thW?tus? z)Amz!DG<%mKrv2i1o#NQ?|Vr%6(6|hSwDCbNdHPP(J6PeRIKbh%x2m+4b5F^%=1V)qD9#P&+4=O!gyhj(s<3w$f%F&Ya?A6g`}M z=IO9!+GJ_;yyNmPjk1cadOF{M(P(;6M}?Rb*5crn>YG0slpjiXyLYgMe?1_q@IWks}% zb(x}~GK!AsV`Xt2Q zo0LOcMxl`&z=`J!iVVVObc*zM_f5+B8GI>kZ+$Dx6Y_1BIocTr{!}yo{0(p@a(nAL zSv#uRwRT=oWLHP9S{}HAq&I)!cBx^7p+oso~OQ zt~28?DEP!Z9}%k|4AML@f?h6xES}_JC-dd<e% z`0i0JyU9~UbV^%0$$o?z&*hUVBTY-= zC%)3OtgNz(!F!F)TaLG$CvM!x_Y!^7#p}A@(z=}>#L3L0z4)V9n5#C+e%aod2riVp zM<VEs zQE}k+a-(937gaQp|~oy3NK&RgF_7#o(>q7p0tHm;S0WESI(PhVH!@U8CQB-4Syh6w#diA%-HtG z2|SdkcaLsg5BkUzynw4F9T_i+{|X=6+sb}_@#KakWN_TXGuLOo(zeGp^7Hke|4*E- z%w2otv>NWedMzmL?8{NQ@h<&mb%pMOvv?F)7{qYCbcA$(oloj^>4+b<-Fv|9w6sgk zLUQlx$ORv}2@TH5J#D%8HEWb^>T*31#unb*F+WHCRX<^ss|p^P01q{K3tfaY+x-Su zqFb|BEm^JbxdAS#3;G;Zv9wxpHPqUaq9rr z;*PCae7M~K*}Roi;)}Rn-rQ`LRfwN{pv5q~Wni>}UDfb$tFt(~JZs|zPl)cRv~&7q zdHcP;Dk`a7I&D{WuDr89Jib>MVie(wcvYyz{+x4wh`ry5=P-<5SGhUsb# z$CPN7sffd#j2`x>_8SHxMaH*Llxpm{9P+8i5? z-lnA9Zq<7NQ zzOOjQ8|zC1#r4h-ELxq%GbD_i#qBj%kKR@jLDhAu=ZCoTFded){03yH($h`-S`CtvdV1u2R+Bt<}A|d-ZzOv(_rn z+8jibL_!sPOor)8CX`P`0oAqz?LkSSq%cvv@>H0rx+GNTG{~pz7NEMAT+-)Knj)6$ zh(HgrbjlgudA(Ev$-Oy#W+V&E>i(o1=DUsL@8Z*RG%gv=Y$?$SapMI2U|>{)!Jyv5 zxXA7=l%Te16vk7~E@+~QII`)B!Ml?xhO4QC)gq;>l+YgxkxEz55t()y^=bXTj_)PD zcRo#Urm>b;7&ebH;yW^W=##2--R#C!tUlevs&s45-U(5dw{M7^QY}*rShuvDROjZtZ_Ey-CW8EWi^x z`kB)cI!OIr38=h8c=!*7%7MzUOt$ROnqQlrtk7&y9lnt&+e#rMTSum$h~Lq74RB@L zq?uabVcR8$p0+bRHo|G_)w-}6 z?6X4MoK4p_atVZB=?gYMv{OhX3OrTrg9csoM?Pl zPU+p*;LRM#vck|0h5;KpYxyXr#$RZqKou=$?Rr`{#gY%U0^el7-`QG|{aaShn%z*=Y8bGt3TYI%fl5@(&a&!ejL5stt z+w18x*m6etAUiwoWTXybZrUwcxwXNJ7>VRG^Kc$(DBO`E?f7HLHr$}E3(8A7MYIa@ z|8nNX#c#B&f2!HXPU;3!fgKErU0&SpdO73cpzC(i;l&DjImfHSU{$STDd82Qw1@_UY7e`ejlCVJtwH)}R>zWj0Nr6-U~cn82o7sGloYe6&f% zS|)}(l`x18Qa4X&Lw4+pr*}MC_;XpzZy5@CViUHp)jM%rXTCAIp2-#Ss?00_UxSHF zm3qhRW!eOR_PV2{?*!qf?}lNVEmWj48UL`tWYAcP3N)}Fo-_*WiZn(vp8KD5zmH*flRB412v?yvHqPeXL4E#R&+ zyTY2~QmhX5NguUtLPHC}?nC7?L(xP1?&~y^0|kTdOVd;fVtOSN<_)v1X}qS02vwg+ zb(bW9vqqN5Bkj38CBmA8osyrXEcD+m+2;SWNfKS?inFwJ=yk1Vu}_c9bE%M>0mUk< zx(J3&{T?b32V_hI)|}(p#W!fdP>^z|fAVR+`LwF5T?83Pl9w#yrrZg!p%mQ-?JoHf zCusWOFcm99PT*hBX>q)*158`vnXVy5!{LIT-cWy=>q^&(1;)O5)^|sS)n(8&Y360- z{uVq%u2Va_dV|VZy59bq@ZZW;TgRnbeVz>$b(WKo-o4%YMHq6JEDedbPpT=(=Xva5 zVh%-ajcrzez((%+5@h0G5W#Cuypc|nmpiPE?U5j^ufh4mcCO(3>FFyi%PNWNv&J!r zpk|$IX)ZgoM=9RbaYz$1PKx5VxQPjG6f2KOj(?Vl%3yX&S`Q9na$|SpVod{fyWfB$ zxg4)=I3`Fb+k;d1niR|Q_f@xsmeps>oCvxiv#}Y!X6x!bkL$h8xh^D#*aRI4$cR40pOAcQ_M80UsFk0Ov{CDfg;vw~^WUtCpc9 z{}`T^em834Un}Ojj!923*`!(DdY75W?|dQ#A*>fr)@St6FI41BOtz@1Z`Pky_D43}@2?RAHf?hTtL;Cf&_!um~lHweAFvV!Jb|yIL zc6KEJu@j2GX^@$Ecl=l+muf^ip?ae_0TY8@kq03-OO@7%Q4@G4!%VTg!6Mm2Yc-e1 zw(O=H8zx3Ed8gNWK#>K1w&G4xX6w%4l%}>9tABs zUHb|aE?-%|UlDaFHe0*F^H&0=cb?klIm%v#mHuGJs=W4iVnw|WY;tN!ALdEAGU%U9 zJHv7eSbwBv-v1xGm@{Ycvap~L&LaT726?{f>a^$Z&}k!;{c?$?dWR{MR* zWhk;u6KJeRO$Cb5OVvRgi(!GH zXdCTS1gkP53wI>_8+(J0E{&Oz>;aF%wRKHbm0kN!@9i%Oh5U zNWqVNzqkjzid7)U`EY6zowK3x1{NYV`*OzZ4nwl}$@)Fm(RdSKwf{qO4pcJJMEXqhYL(&wCKYuEJKXwb;mS;S`*lDjCZM=W^4H zPl2Q`c5IcDhl+G+5x}`l#_r-xQC(PU-jxGbj#DgBf{b!1hJl8)tcy37#wcO}A|Ga! z!?22IwWF=w)j~3<#6zBz5|t$c2{uZJPI)@rRXVy{oTT#F2^ZO}r}-Y8uZ?X*CI5oE z5R0=oaO=?|=kh~Q_8a#k28jY30<)kPs2?<{--Kp*u(+)ki(pAl(HiVXD>~2SF=1r&ud0F9w54>sGWMcXS6b6H_b0Sm%gcA~WK-39wL_f&- zHo@yO_(?$qhT`A#6Ei|Ai0OsT$JN+=obS)tgaC-HUzfs#m?cILEX(Z)NWnR5n%)19 zU4W~`Ucn!`ux(JyAiTs82vmO17%L)VSZttAT*u&@f1M&yw(~NX0}mhpUQ}c3K5Wm0 zcr3M;*=8n|J;5F{ti2LY(Q&Xb-gc0Fi`R2`Q@zzG-L2%TCakTe^`XArngOVQxS@$dDY%kKh= za=shs3_!xf1L$fMtJ@J>cS_wEavbY#!K$wdn%T;3izyTb&;l)X8+<^pU{_jmHv+h| ziFC=UAE7un3UNg8ZAhTp2?Bao)0|&>C+p9Aojbh;zBxWU_u80_SVPXIGL7mvR-hkVtq5hA@Q%9rJa=`+*RsA zNe%oaZD-OMz3*h@mM_p7oP|dK1wcW}uU38>m!e=RKUD%=KE;n$h_yfDi>XBoiG^6{ zQ*%P7l!ve)SI)@Gp`>E0V)qmd?WCuZx)aUVn%&Tz{$3K(%gj}{+y^)E7hxce=E&-_UHDS zwwZr;&trFPx*yxTjmN5)swAP#6Q3^pk1s6eao@kUucrWFsd^U(46F^~lmKXVP5)mV02t_{0zm2Vf`jXJ>u&>bOCh zC_GUl3SnGs&@y-j2HLW|x1ad2@uxFF;ZN9}rcbVKR<_=xb#VeiJ9Z|dSLEB4G>pqn z9IoxcDma(_tpd>h-1T#Qbz%Nug3paB%c+v98M#4B;wCn9dNw_eYJH^osHXKS=JBub zMgK*BzirunSft==%Qiox%%{W^jqTk;;7m!pF{rPV|D8(&3DrH!~wqoPr-xe!?X?lca-yc z&KHlQw;%uSww@)NwFN?s;+{{3+^V>WOF6m!y?Z(5kZ+w=_i{l^_`LnE?Z$T#q3zul z5r5bp7zHvPF#|$9GZRB>|5L7KvS)>Aw*o(~YCP))HBv^Rl0vY&&w4&lKHMd zGxAZoW6rGkAs=lZ$Z+iJjVJTnMwH?6nNR=f$iKeGzoypzWsSi1JKrgAzUzP76}hB} zH0-mbv?uNQ2Z!Dhd+&eAFMnFEcBu|H*_x{BT2{k*0DEZ&MSLMSgMx}Au`QSPAw>3Cp+@F>NBFSCP zIeX;fsI+=`$ZoYyCp^dc7>wGY2kLI72kCf$+y zLpfFN^uhXeS_HYvml;;L_)zJP>0iMqZ{P_jp2g<1f-rAedC;H_)n_GNjh(Z6J6L(u zs#GP&8=-z<>-5m%G<5!;MaO8z_PAYiJIB2d=qPO)6xxbEtscYKy78CX>4?c^lA2}D zrRxRKHuUZw*XVSdlH;!9y!_iP*FtuLs{ubz}7s=s_Ux7e_m>^K8L7=ui; zmx*h0I$jV?{Av`^!k2$~REDfIoJMCr2ovj1LUz93#hi2`x?}3=<|>ONmpg}4?%eTI zxPRXiSJ9`}HnPAvRQ9?Do1yUFF8TRmT}y*;HVkGxbKmY;r@QNe<9BybgHrV$Bh8#B z+HvMf^go=Ag|ycOweA$mqHHpU{*_1&diuWvoCn(yrzyu;D~O)i1xu!KaQS8okf+KxSCO4x%W6m za-&Q(1z`9=c)!o(rSgU>Ys-hfbY8I9FWrBsZ4$cmWD+Wy?c9P_@sGw$fm9!!zf7)Sm+QE13o$ydJ@-GTt##SujTDfSzv6X z0iaX);q6c4X|0!)9_O-`fn$5lr*Cda%8>z5|6pKf-}y}l(p|pdVl&Pv<~;ZG8|(YD zNRvbnX7Fk7r{L^vg`R=8M)fz5>g{7in}S*7b)s+t{&?e*&f@ZrMoisv;VN-SHv2l3 zUT0>|fBVYsi!CR%riW65ExLR!TukG>`w_hq01)_E#rLG_FL{HnxUZDSP%b9kvX@#V z9b$T_`1q>I@$}Uql2yjR2`{E;PPmS&Mdig58w8d}wfeche4juQVIUApdk1Ji9ril4|!RIRq zNZSyDrlPZVr%S+7cARLY>PK-#A0f&U(8bY-d_cXMuaM*u`3kK#HsaoI9i7PR$9R&M z9@Q@l2r({&s*3JNziaKc=AJKVDHXTug+e)DduzQ)0>brYt63Yezesf({hxStx7>&* z?(JF2R?f|>4iTJJ=mnJR!VLbX3=r<&$d1O z)%1Ui_P++?Uo+(YX33OwZ0pq=HPTey&RF9Po8r1fZ*MJLan9|Y@_1Cgc@lDQa(buQ z!#daABNszCd z)3-zZQqonZ?F7uGbd2T}LI6Wf`%g4j^0ljflA^fGZPJkXmlOd)(A02?`;$6SCp1{& zk)$fOe~>qF24%==>Hqp6feW^*&mk5mYG1`#3HGF!ID`EyqQkf^#Os`m?aDUo7vyU~ zf1(xrp1d(5T%e{%boI{c_eRR`~IY_@rvl<%s%E;$5kf96-dS=%${t;5}Q8Ll^uSchvVS zFK=2VUL=M+NF_)~@kNu(S|>YascPtX9wq;s7BXUS>r(iw zX6u5czG2Kac;HtGenYI)UJ5GiOXP;03l1VRyr z`-b;4LX_GdxnUZW&P($gscIn^@@MyCfGONIxy;lCmbRoMvg)mAY?fH%r;YC?m|EdNIT%A3csUH#dAtb5Q{J>n+bw9>ig!> z_bsZ@{slhg=-0K#L=@Nzt`b>aHoCu3wRF>kUsd0H>;M;`<+tW#o)AwGTaR#wo)`Bp zGNk6RJ^TPXl{5Kff6RMxpzP4|TZye(DG{qp_Oe!30R$Vs2DeR2%w)XLt7I)NsGsDp zk79}+V&^AcgDreT==J6D z)paqX?v|+a^6^yh1UrR-`1;h`m!HCF@;U5WjFOk`FGPXG=k(H`1)aCX9g;o)NUOFE zg|pJ{V8ba=t*5Hsxl6`4ys%5}HISx7Lk5QQy?OLKVp3|aQbx!sw*wnas0~ns>RcnzoBQ&XrH=eN`<)K78Hd>TT?j*+h!=cDReL%_sQn4=*b6 z-P+|W7`2}rwL^4Mr#kAQ%o-B%O3*+RAbPF8#kx$fqpk>58?1}RrCNO)?7;ti@3nEj zS3K7G#0Pa0QnTuj$=*>|!=?+GD#6@V+?BX?3$FHEV#CSRV0ziK@_l;spJ z4xvu($fE?)@_{BaJYlUjV6_0#P&i2l3J}HQi?*)X)r?@>Z)#J6X=z3Y^F{T}o|8g_ zIcFgGC8Ahr(3g3}ylF+;ft&0?u5D6Oz~?3qV%$`bZjz2$&Jg{FLj*yPpc!|nyp)XZ zGmjwNg1W&Sxd8Uif|gAKR79~&gC)_K=#)_qbyIeVz5d0HwNz>6rgjvr9OertT&Yh7 zvmf8nlr^bE-~H(8YJ)jwS+~+j=jL*=TmRiZpQby@Dws~Si-;TKG(lx&)b%3`Oz5Pb zfYtO$Ik#kcTWUwEna+%d(})>r1mQis90Nj&L>3Sme^#^tMsb-hYdQ=ACQHa@9FT?k0YP?8qy;e&($*Ubd5m70I70TSKJq(**b0-{w0|(XjUYzu5b5a? zqFORpo$vk`D=N`_&e47yN;|9n&fl%64P8GNrWe#67OHoOY)zkaxxs!g7=OKpw*EMDKl1jM{~`eA&!#^Z485)A zG!B9PpyZzCNzc+>uCJ~<&orC~4Fdl|u8sG zYHYnBEHEgHMMagdySYRPQQycs^lD)eX%%kiG0@xdoJB}Pt)e)I(=N+fwi2%j+D$lB zTQ~fcD6pN_qW_b?0h%D4Nc1|sy{S+E-s?P7Si*&j`&bvB& zrpmerc}WN*e`~jh`?+l;a@d%NotW|-LIr4pg(pv1vYw#8faEwI(}Q6=nIeAVi(l*I zuCFDC0BOy6@3*uo16Ij~w-1K3HchN==cA+>=3r9f$Egdy-#6xar`~56)pBrLX5iAL z5eW7)tjTFwQt{n)el8@*eIG0!D8La{bhLb)`w%yNp=wOnrEN;sCUup1X|J;$H0AwEupGPVIAW=G=FeT!FHLDku9XP0}el9JkdYc#|aV#l$$o@5% z9c|nFdNg;WW<)f(L}5<3J6eP3c+_3tKpX7YxQM)Rk_GrjJQu_&qVSa#1qB5}D(HOC z#PnFIkbc}MEQv@qFPz(5>%R*9Wu<#|iC7qZjqv_5kd{f3t@|qT@jUxUY0PV-^I#jT zz{`8`4O&34gh^Fr=3Zi(D_49qHzfR7tDNH+my!Fzbccyww!6PuQ4?fO)9nh)e3TAX z%y6hjE$Wc$OhBm=uj!PCLP{ieTSURSVGJoRjkpE1iX>wq7fu66>3FeYvHhnXTKJiL zxE7c<+ok4=X(KMU{jR)&)2GKAJW~0;wK0Q%?gz<0zkZFU>BWJ@1F9A5QjNx*nJ-u* zt9pBzRMN-m$+G4^xCFq!$5GNbVXvQp=^cN>Ee_=!(GgHmoUF$XqX=Lq?r~N?pLQE5 zdpH0_@fD8Ng1}UHFG7|~td8ycVl?4weQX92mmckk!6jJhMp?s{L}R_vpul>@vo$$6 znLYtBiQv9okU`1Ai{(p&vj1QZhrt%@Yohw`$6^A)1w?$l8fTW8ss?jzQuo1w+n^Y8y z+ZrEiE?s84R~l2Y#b~|r>|5I$3Hb-8WL8f_MAeEIp>71L zU1WJYa$nYZGkUy<=$967r=fja>hjxWk3?Ers;DZ()&|a0s)~w+iSNbr4~C{s2~t+{ z8m2oJPs%@UWk=f{?ac|Rd_0C|2FR+!JzlC$N&Q?>YvRA$xGIESwJW0Y_nMLca}pyy z9|Ush3L^8?OJPb<1(fXJEZ|DMhNSCK=#p7FT<+h?(Qz6w`VWW5lS(F%*4r51q`I^ zvg5T_*ekybtxT~SlSPnTD$%@Gp)MICEA*sH<7V=JQ<&x=<>4meaRC&ive6mI>Mk(Oo>BbHzA5--AGNC zs@F|xBYo)R5$Y5!P0pN+QKF3cC?4} zR8My@BQ3i;aq(e}MF2Yc#3_1FlToH&>*R8cjkT>hMrOz>+}$@a3K)vjZj zOuQ7$a1mJuf)Xc)T97_GYoy(HQ!f^7kwDxgYGXYFt){IC8y?9UxD6uamWU`X(+Nk> zzS1X^0SculUs8GINwKXqqI&f zYlue>AeByTI88LL@IqQ$v&PiI)LE}gt>MV#)p%3tW49Y;fBrYr_y31S{$C|fwPLcoQX72p{s+Ur z=uhh@>mQrm{9y3ipP{V>Xat;X2{ZIR{DYyeY*PjBRf^?#GA&SS-1~Iv+$La=ae5t1 zxjjXAYn@V@EGrXm#opk(^P9(mkBy$o!|)iHl!Zzo|D0mfmgr=yBVXW*@}foM6i?9z|vDf{e*Xt8b$)eNo&%T(g zgkpTfkXiYiWMTo9R{G$xAvaN7G#e|*Qeulw&f-}x0Y5wz&&HT$PZXPhUk| zZ@`{pEzS&;pZk1}dBeA$VH2yheQaK%YEDZ^IKm8Ay^CnwNo_B5s4VbHc$QrBTt$(9 zQ&iR_Dn%y{V`D+df(axN|7UZ2&T4yJF}fL5f0V0D+}(UGFFlP_tgP2%`RA0qow2D1 zux0x5GhgwpjY5D>-s78-{lAHKFPc!3%{XA!uTpg!X6c?ZSjR#2C&e2(%KI{llnYjF z2j{W%4N$r8{36M!8VuC&Bn^}^>7)HHi*aE#Ei&8s&B19Gd%#VX^bx1B+uQ2*571do)GT;;}$>^S^MR8jN*U$c)SP(+8Hd z#$0-B+K1Eoc_%+*z?bLB1L6L`&)@*EEuWrq_MgSUQbLzGdT?$^(kp1foZ; zgzJpSwEOV^wMa)vl==x$>{e7KdE4j#qT@nT*cs|4D68J4jp*o!Tjq)<&;;=`ppQ!e zZ&WW31c7=Z*nyzk11Woqt`LsPvQ9!)U6hBY;;TDV6y%2|QU^Nr=o4Xr98&rMjUaG zQ#6_Qj^o;dv5<(3hK^#peG@moiC9iCLHiH~%Yq9go7#aYs-JEQINQv~HcfB^qbRso z{6KCz1``|NFVQIhT+WE04uWi)gfUzIdWnz6$qA$ko_Rz{Vy*}+t9oz6HC0C zS&xsK^zFS?c~M2<;;P{*gM&HeQn59QPmPQ71Ab*;TGrDF?``oXly*$)PkQku|AwoV zn=q{vZw6MYRodX}4S3Px-e`q-545tQ_F)Wfk#7PjJ2(6$`S6&(lonRMl&M`hq!izl zaap1}cE(O0?T773#y-SC!$<}O^r*LDMbQYjHn*xUE*?hM4hLm;cif#Gs+B?n`5rNM z+2_DvzBC5)uM#bi4t~7nNqBl7u+Fd z7yf5g#5k$+ z-7m`;1Y_#@O-t+g(ZUDmqj{8CDA4G3K?ITRM}?Wq7@$m2agP!HTz1aDf<#W5mC-45DFSgz8_?TIW(}_IWpmsOU;E6m+JgrHG37dsEbd_A6 z646bBAeCOVf`x+bu1I+2b*MGqjY~Wpy>PBh(Izj|7ynx0L=vyL*s{&WIJUoJj7a#w z5csClV|VuIcbNd`J&hHO!=A8vdrkCu@CON(Ha-9NccB^l{O^9vPr4JBZw9>FuzV%? zW^s2j;E`PQQDy7FuTh6l)n9%qh?i{2kll&bPHt$}t+?m@%T)%nE z{2_eV) zUU=|gW?F+|<+Dav>}I-eq|iYk6bafrIZNnXKBof+qmRFSsD8)MsLrFN86%yMIP6z+ zm8lq;)%;xVO+M__%E@K+N@~_x)|>aw?w@^Zgk*kdOX=%es~f$;)2@4wd_(k6zgPj_ zjpFhdGabsM(|lildDqjr?|Q^6-{@-ynJM2bvgR`Dwyn@Ry*F!OmQ~dF^HICTyX9Ly zJ(A<>EFXC`bT+Q07}yV)9v&@pAqu`%Z6+~5!V5Mjep}CJrmt~%q-D}rgyR|`x8CGq^aEJ z(m=6bcb*|L;A#>uzHmWBW)vQ~SZz+WQ855}M(mAQu0N+#ncL?|3=FY;j5kw)@siQC zD(o;H!#{nfDkdxS^EyjAAwF*|UvP^=ssng-_NUjRivn8Wx@XSUe=wZB)1pIL??SFE z8-$MH=yb`TSp+@c=)O}X;56Q&soO87=~i58$Nz)p8%tMMHKc|*|0+{`N0q&Z^#;~t2nzWlgoNm`+0J7YcFO}4T-=fd0qz5*gszmdJ_td>q;W@n-7YBqp>uA={``~M)EMla5x zvGbMlB5rT?MF;2z+%)zF1IfGTBFaALOWCv2*w>l~ zo$X?>Ehc?hxI$@HuiN;QC05f2BdYzM_Ro;;+c2xja%bd~w!Zm>*Ib(-RX`*q;_AA) zoiFCE=HUdghjo|Dn(T<2d5IVQ+CGepJb-7kb@j8cQTyE3;`=HtVojOSGiHYgTeY;w z+0y_;?llO-3^vPqHB;&>4nQ{abK#x4GvN*-#SFHoXgY?wm^pb1G3So9O*@m)*K{s( zsc`d!;)Y(GY1?L6l!)PvJtANIZs!1xw8M=1j`(LQ!56FgWRjaH6(Ch7V_DRy2ROdi zku?D}p5A6-PSX3l73g~DEa77Dt5ENj)PR6pt_9k}wJP&tzU{mnMW}~t!&CLh!9T<3 z`h|h8reL}EX-QsBZ2NGp`R7)6vSa%upX$6V>8LfMRCepV7nIUbxmUSqmis^~ek|X$ z_FKwe(keP3Lgx#=8Artirda@pmE+{mFSb^mwsI)Hnv zyr6tMc3OU+b2m1yn<*pnt%KgEg5E*%=QP0whdH)z?zVF|nZqpJ;tdwcjo9I=*JTZ( zBbl9l_>0=Qu!<7;`|r$~DXZLvRHZ>BI0b{U1a!Lx)l#?s2J8C@-XRWUbp+ej&)EMt zdw+sVzJazep6B?!*>)y^+FUj#nSL;s`8J)ke-Qq3ELr%2A;(qYs%@5qsLZ+;e!pxx zxqj#YqNgrbpB^ipkdT6wlUlU1Ke%gGh0YDS(EKyoU0u?$wg{mw|Wh=1D07QYD6ldZLUKt`=Dx19*=BiOm=7}I(bA^$@{65rQs@2%E2k;?7D zVb4<4DBW!}!-!Y7-Gj}pVSygYF?e#{Bj=b!tQ_xKUoMWHHtkK7Fk^pj7u_s)MbnDJ zPA_43E9%lB+nrN<83&(#@rh|f#8;cD@FdK(H)al%)o+!`b7X0XRUN~J$7(u?7N&Y~ zN^m5XQw`!h4*$9GMxmIY_0#jY0HzYYGL?SK6&0~LzxxWv zxJgSvfiI-4e92fa)8a8O6;Cb|+i)p2u?AQLcXM1;d`cK~8n-dWmM<5^ zlv`XzfsdWqy>h{U>S!g$?NG5G(J0%Uoa5|5@L6)vil*7a?g#npKNucw)Lch`+a^&TRG#|$MSU8VZ3KHmuAt3Ia z1~DsccG{Zm2!7edWo78@a-HwCav-j5D?3~G>IcJejr64lzfM5YiCxp>(hr6+YP7_o zS07HE{9usDYfZjhw`*EE(YT0Y9M1Fb#4!K18ObH}xoA>H4oeBIO5>=j?-3<34v^Xb+PDCIg*+7G!1O*>NK~qLD}UlVikDRh zH_Aow_8+%xzcPBplkj;7bNgUgU!D+i%p)W!jBB7+H28Q2s8yHKQeTLr36|l6ai%XS zPvH289389RPLk+X;&|#~Y*C-L%p14%p9~+INHwv11vaj(+{|cp&H+N=*0yHV6GfuZ zH_s)y`Qt!QEtNqQ6XIFIqbcw-yB}07?X!{9lIX*^Rq4uB1B@FNWcAv?=#=u3KZP? zhYdG3Hv9cHc{Kr+wc+;qH!?ghf2ZP1w@0Z9N(NHZay2g(<>1W@DlVM-Zoas#Zd927 zDr(>?t@A}inmFtz$BxS_y#d=Z^VX64f-!r7iO@Wd!v4$pIdh_}OMgI$pf@Whve=-) zXSoZ}Ir<4!EipXN&CR^)$FhftYQRvYDn1cON^Hkpwe> z1`21Q-q-w|lm61}%(dZFy<}#^rEh0$$A+e_MUbUwE1uC_oYq0h9bAwaZ_gcf6=)Jv z8C^_3x)o$w_zdL+CZA7nNRa@1BNNHQwWZ<*buzxn$Nu`_dsVVLUR3d^^)1`9n@Ul9 z4;@MXavEecsmVHfs$=+^K#IAmgiEwViNxq1k~`a{unP1u9+}I0naF@hgJ!dagS+5| z+ZqrrV~hr0R65G0?16nU{KYn5ye-bE-g|=&J*-#(ZCjj7+pGT5(c$>f>+-#q?c%w$ zY9VQ3zY6ER7MeG8PLGKw=dgFaCU7$cemyyu5qIN7iWm9O53cM-5nkC6uQ*+h5SDJ)wFXTB^+?y1h0@UT%D5xJ6FdB|3Lb zK_mn>KQ2_!efQ@Zscg{?!$!H122ID4CZa7R)Cl##tDBF`Ugav_L7VV%OM39MX5Ej!2rFW@X4yTE$i){i*D*-Xiq4n@CI4C0 z6E5NLeD`@B_fnM~_tcVkLeU4of4CKqyl`c!RLI1~u6U!0RA&}IyJcato$tEm$NhHj zLguZwb*2Ki>Aga(ab;^GRB!g{JC8bRAHT_}cEnD8_u|y4Do)`}iR&ixmTuyyP?S&D zlD2JJ8Rqn}yHwubVs%tizXIJ1O8N9>aUx??kj9^taTq^+ZQX5fV(X%ek_(45(}mKn zlAvFX(JE?G&x6@^JLT+x1<4_D;+)aT_a9Fe%cYGc_%bJ=+mu_1i9Kn*ofDlv`O$x4j-qQsly;>3p(27bqZ1xwVa z^N)ZX$ToQ2aF$J#jcF|w%!F~VX))HZe7NbR7jLNcGRV%Aj62x2oSsIVmxg;v+SwcZF0Kve&zpWNya2r~I=2QFG2l zk0a`P8f3~Lo9zo?aVeQfX6M~@@kpDD-EozT;toq+P=I;&DZVD>8VyY}c*M7RUHe!bz9miQf<*bwE`%|tAN)jGAQ_gONC-k6-LTN%B-)%>Ra!lvo3g2eopy`8de9J@mT6sP0aa~w)8U7s~zK(I7 zW>DC2J%Ei+t1P$N%Y)QT0CNL0%h*@*U> zbfS`VO-O_i5_6LJtLA6Qk$GncxZ{J^rxW6cAL~wlD zX9ohyx1EJM>f)DF31)4kwl=QAeGMX89NlL4g^jL~mf>&9=-;1*)O4nr!d*0tFOZ|M zExNT&MB$}UIu9pnrowvt7wc{^4|VgpcDUY6d+t_|D)?|S43gjSipM6Zq^zY>(-R>X zbsrwFGtZmf>EB%!uy@G( zn5IMRZD8cRX}_*6OBDu2B3v1)Zs+@z!#mxsD=T+v7Df^TvTN&A@i_?XeoJNX``!sR z#pe-a`Fu+bkDlF-@4_fCN*W~8eQInVF8aAB)}1ML{F3P>5RQPnS1}P?O0h6VZHq=9 zX-4Wo#=@h8@D=CTrq2UgYOkNitTa3196hE0y6O@h_bA}HWddi6nhqp|&$idjB42-g z7kxVPJt7e3)Ai+51Sv4=&nrNqz-$C}VAP*ifX=MR(Tn#He+68Bjk5}JKyj{*aAccC z^{3KyT0dp4Z7Fn3QUL3YbBSl{8xEo37#7Igc#>jk zV*|^4X@)~`e9o?-eRdnH=S3W`-jIyAMV=cjRK3jQ8GAGvR!e18b6t5k)X`K`>0Eyo zl#XnAhc!aZN%Qh5KAu7!Kd+Wh#xFzSBKc6DIIOdm$a*dH zT;gsuZl)qn@$X7nnTBX#Nz&s97EnZv3x?ipDySViML2U$lqDQRx=|8NeYQ4&!Q730 z7QmXN(1re8PKz$F?9m`=9X`3ZCsw-vxF>|G)m{{MU^WPwj8);VO^S!mRi$hwkecj( znkw`ra8LhTa0?@>aGr3TvYM#Wda}18SF0&wG;qQ51+j_J3hD`V)wAM9eG$zXk2bWV z>^C(k7M=LY?&Bo?^HO!1K_8~{9+UhI=3Q@z@&lzpZ5Q{vThJmMAyudi@{ZVs`r*#9v0W>BYbJNtrQ3Refo1CRqF@5n zxVITGwd;xl^L5>O?Y@{OYXe^3BE?7Hv|Qa2-3Jyp$0jaaOfwvj<9hb+w(m<~!1E-D zGXRWTZmb;ujab#)M0Fx0BQjPE zoo6eSU}F;9L3JZGb>>WaFejo8VSmYnIu$ZaWL2WT{Z4dLbZ(*w(6t3Nwn&|uJ>MHV z1V8m;vGheEfW&*o-oJ{u|F*qO7*sHY#F0qcYF@%2=4@Asp*hg zCiOQ3?(mh{t43XVTiT1al?zY+-u9tNilm%z<^Tz(IAn0yH}hMozuN6AQmtVURv|MO zKd%-hddY56^)5I=4$%m3#@WsXs|*I9tgPJ98M(*ew=wL{iK=2|Klj)Vwe!bUWL`4B-@gIiVBZ8x z$eSe$vgwyOFmtAYeLkEzJKG2s8Ge^96eOanPEV5!`Bz2!zf8acFoA?aL7(0F{?^z- zL8$HaIR^c%(c@ksm@H7Is@kp+Q=9U1=t$6-fmUjR@nZr;lshzJ0U zl9^(Qw>-|hfN2cOqd_1bEBvE8|6gozL5+o%Wz5sZaemQ*KI7Qo18gN`4_EneOioU0D!#6m1MQbAa=xccPJbj z29&A&UCjUGP_A_j^yd}CZYlt&SQWATsh}<{ifa=&v58V7#0F*Tz#rW*kEx{TD?6X$ zG)27?SUPg#Ouw|b(O9LSn$Ac7R*URgA9aE|~m2H_UO=>dA90%4d%M(suW>gZmx4e^+qdRgWPu~_%SUM8qw;BhgF zd%)v%k`e2~1pvufI8H;yqo@lw(WuJ|^(EGMOC&qCc|0AozT^iezdRcvHqi^E)(bwV z(qc?ifZ8sdh@dr?-drFV^ihsf50ElV5yKg1LAK_v-U|P623owp#SIEVbO1M|-N6F{ z3(1IRS=pB8J{LS0@E{Ax3~708Elr~;gqpK5FWb-^faS=d?7#+hc8=oMfv0BY5N8!; zf?!rnGn}9U^j5p+PY1i|q|zam?h7WduFuU?cWg9op9@`gM&rPqdnf$~UV%9!`2GGB ztvfBNk3&7kjk}lF@d=7`eb!ph7%+f@L~2FAXxpuG5Q6M>Z2TLePO48Ae{ZDid^(}! zNo{wTWwZcl+}Oo>Z!{k;oJGHB0n9EyNXn)C-R@yubldWb)o8-jT$j{PC^$?-o95pl zDjopj6adJ#r0Tx_$#ZqRL(HQux>XA&#K@Vtv@W)u(W+5We)(#yJUY$gV>zb7dDpY| z5{}0g5@VTSCD|W$VG4+iTQd8=5jyScWEc5QLEM+@==WLxSlXZ=09f2{^I{2r3DR@N zGebWCBhl(u&}_6k@^!}Gn&fmTJO2if!qr#_n| z?-NuXr#t}q`LBW(FVn?efD{Mbmc&VFc{y_7Zhy9WtLi>BCnH25N#DLCWxw^=+!ke$ z1l9eYp;_@i(0q3&IuUU6pE-@Z<7xpwz8{Tkx?v1Sy1Z88V!-qV7CH9Eg4QHRi!bAV zd#C*b*0GI2?xfJYeP`5@wWu%)(X5I))@a3C!qt-l03WGK#Q-mJDzDRDxOxu>Gew)w zQvi|nYDFFH(W6t_tXYRHc9$Xf<5KYW$wo8zF*R=d1d>sAi~+sRlW%D7E3?WI22SfD za^Hz?sbeo2el0-CqMH|(Obg@L1TZ;sriOhv_=A+8gSmM^K~Sgz6=SB|?Eul?&Awb|6BA17Oa}p?JvtH1ralxZVPbG~EO=9IO{Ki{p%Hy2B&pTK`@lgz3e= zl+0s#xhcV#fgGY#aI&Es)M4r;lLFN>R6*E#u~ZUC5XRm z&9yh*C;L|6v@cmNm;^{qgsPzL%bLzpkH>)3dnoLo%{?AFn?%=(NCTaSr(2!>ydrZn zf5}KqPLiI#>p~cj!P;zQm332(%mb!UO8?J!Gip-4^#fUavdPo^S{Z}uPON?KIEIviL=}}V)snJ?Ks4l zZ|9fGrbh=*umk}lP)+;uM>JlupC@%IW;LdemkD9pE zlL8(BO2PYSjArs*O5sFgugq>+6Q`Ldr#N|f>Efq806Ut!`3SJ1P#2B$TnG@8m_ARn z>zKG8=621}p%MwZon;2Q4w{+YpqB+R3Io~%#sk2@hPjLgT*L8i5RMmE zp}480a2ee_Plu?>;n#IQK-y8|o@_NQux(r0beS+IDr$$DC!|#uw@uQ=W}FN}rk%S7 zJo**q^3`jwFTz<%Wc*X4@ZdhC3<^$;R?Xf z9l*=71Bvlf08&5z_U@Uc!UZ?}Gr@61{{qY*hR`z}7tTw(jO)4}DsW^xu)lvyaYZ%5 zF2MXNvqt(4FjJd5i^NBsdUME3!saEZFWb@e3&pEW0$9$4L8JLEK>l~k8rAVK`s9LH zJ^n{#y>Rxke=(~F6l=9NXuG|XN#eHuAwCnVwRO!XAR;fiyAnW`_V$Ojw;2b5zWvA4 zI^%#gsXLAb&1e0f4F@o6tYd#E_(^G$ALcRIn>G#!Z7nM_&78qP?_c(6+&(i^7 z41i3C#A}ukHGt^N^f)4cy)rR!zqsvlXhjz+VD`ZmwT_8$4#vxT!FNH+UT1!Q z^~hmloG!#8Zi$3X@?ZQbh7uCn&n|AA(yUrIWwrYsVkj7ZDBl2pnY~P-IkkBH;?_h< z9QgMiBIA*kh%-YSjpBys<2$in&r8XK|A+Yi;9SR85O5IYGmtrECZD^ln6j*IEZ6U! z;97Q1`WKk%OX~lfqffwGh-_=?w-`ErWfJlxC_^VzA^CChyLN0l} zzmij+R6x)uH?e=-1)>U;h(0ElY&m%#IpysMOw{uAB%{R^s1~62E@MLOKj}`9zjf!0 zCo(R7rM8y3+etY@84VfRJsRZZC8GN8NV$YtgYj=t_Rax`*lwk;M5dVMnA#3aC)-ss zf!$eEFI$n|MF0l*5rA=c`Edd)*RHzPq1)=EUS8a>5E`ed<#f)yuCqLoE`I&e)?Oeo zG_wDPX8qoC0?7!CsIYkF-#;~Gv30Xc`)sXUD{TS1aCwa{Bx{VCI1oeqhh)V*5o-q3 z{*aAHk&CWO;vTz?7MNky!*TzMP<|`6xNc?@fJEo|pglYZ`YW|{f1k$-=v$>zlodeZ@^7?Fdd;bXFN>Oo+zn#4?E*Ln)uk~L_38(;8AKmIKSF?%n0A#{u zaEf`l&}y_q6=ud3`fuUf3;L03Ekk^Q0K}|an90-HAqE6tty+2USW6mjrn)-RhWkhNL*`lsp2Jfxr zWtz8do?N5^&Jc@~u@e{BEjCv^C&-idzsXhia!Mersuul~?C&VnAy;FuA1!c8WXd>w z@V3AhlVx9$VyKg4(Sa`o*WIrL*dDVH^ zG_8196fWOK=OOCt*Z+%eV8N08*->pZ4Jz5`I!jRdd|TVh+&s9U2K!<5nk>yTlkMfj z7ae;6)zKfZHhVRG$41j8Qodxny5ese={iyY&WXsWb`ihpf}~wPET4#Fd*{p3Q)7Fw zoOcvYn1isRn&7=dcx-cQ4?Za-R$(x9Di3w(f@KlYN(*SE1H51O%B+yo5%<`{Fko7k5p*gybfkjM^G0Qf7@ZA{8swQBx&ffir5MK zc9DBxyXc0&=uzClj$zn=42thl9t%j5T*MG(2eTRd2(9!PU^fqzkVwzZx6RK_I^-D8 z)04t)X?YAMdV4s*%bi-zYmxd~1h!f@!Z&YT`0vw}#Ii%l6uT|~wKZq1H4R*>gOI~R z%$|3Dl{)fXhd#*jw1HLnb zZx<`4K8q-h`g{5bio>lhKE5QPIsIO+U@@nO@YW z!X3RKh}X9kht6J3RY;;Pj$JjhCo(dcNKfz6+4&t|wZZeba%;?Px60va(~d`4*Lu<7Y!plSZo;`maxiJhe~ z8|xE4l63Og{e-t+-U2-#7;k4*X5Bt1(dMA#n3+&-&axLkZR z;x3fGs_*aH+XX{;@(aGeigDA=P zSfV_j%J0FUi@D}MzfN^bhlns46}%fjbm%yPqaCfg`JTBgbBxRDE4iiSAIVVaC9f8f zYb(b=1s-*AD81J+c2*_!9HX*#0l-%7HS`*^htW_=Vc0EX=rY(f+SxY@3w-JZiUz1Y znPjLg2@V+)=@giUPavBQwRap+BG^Du)S{as$Krj9LSxOoJoO$Ry4~Ee&+{eEB8gwD z`D$Y6_unrHK6)z{%s=7sC5|fL4lBy17hN`$>|Hx0SO@Ahh8^IS%uJ)eW)7#*`ZFkX zYl(s)b}XtSI^#wsVfYoHlb~4IZ(|EBg>g zN~WS9Q*5Dzo&%Ci+z`u0qg*ghte-I=iOJ6e>KN~TRea?tw%vS;+tLUum#13)^NKCe zN>FP}>+x4umOqtvUV!DgkVx4+ixfFPtIx052D|5VHZwa*QFFWwS{E-S z`7M}RU?A$WuDIG+dN~y}JIlhmf%ft}+C3h&-^5oXW%Btw)k%>ryOQhqj%aom>#^Np+KwzMj4sTcaD)Tl-h;#Fwr5ewK5dZ!gAI9o9d@fm<|H1J!~3zjli0Xi zba{5d!MCJk%mLMqJZ~*nrdFYwExhIUM#25Bdrz*q$$G-!H`RTJ1Ojz;!Pufq$IlN- zj~BxBcN5zEo-4pw7_(;P++Q|&&(Y9!jn9b{Td;K=c#gf@(U>YiuIO&0v{mfhD4^dq z9M?COr4(pGt{Td83(u4#+zy|;Y9~5vA?LyL?i3jVoR_bZvbCd7Ct0`$Gpx&ze)S+$ zeug}Z`7l=Jy%j95)tR{J*{3X?yXvN^x1yU+M6f`*RhAo-){a+-fbd)blKm`p$&+wnd!LhgOwz*x(+wiUQF(JdS+Y^}Z_-$z zEcs_0Fy%FEiuaz97UuUw5!?6a?0m|hVa&XFs!3uyygCkp$Dl|=UvY7tN( z9HH#oc_g55v|;5rQ#7$y>Eao0f(=5pKFBIchSF=UW33g|AceNUZdA?N0VTl9^WH=yxrcwy6J-kQtmb9j5FhU2oS7Q zyl)sg0`qVgOuTP6(4k6Oq7j*A@&cXz5nl9~wt!{<%iDcVrJbLu@i!JG*?I|u2g#%9 z?QL3C!Q>f_@j}1*V=uS(*sx6@TPAuT^m}4Es_@5H)L)t@LZL| zLp6RktvIKqGQsTEwU=fA_h6P_JC_ByP3zcTW5Zh(5P`m`BKbo{zHFa~(p3$a#+JmB z>2j4~jEU^zSkJOYnRJocNLOekUwc=~fqkTv;hEI?F9(w`EgwTX-_YF<7u=-St$-B&rZz_ z*JFAczY1l_^R3OvLG@NrG5ZX2a^!%Avt~VP$EU#26_t)BcYbvgJUoJvtX!EBojkR; zoY_BanQUJ-{JbYSD|9D}`0#Mip0Dx^%k8w>m&eBXhfP-73T$}3Lc1LAQJFNBpn_vL zO*(3mKK8tuNG{UL?yk+WJDtwL>iG8~O*%1)`a^3aymKz`>@^3dO5@P-d6}9Wx#sC8 z)~vjEV>?wbsmzpNX!kEi^LQ20Laex-mb>$OFXMbdQje|)$pW*dGUI8+INQNi*%hH| zke*P712YxQp*2Vb6O66F%Dps4#^FhOs_klw6|;y)vO!Dcl%~p|w{t9ulX%0e1d5TE`rUWl z>h!Kr{dn@)l($J$bZNYQfEL?S0MJTVW!VW%ya;Ql7xt zcwTKcRyWbUzib$iW(sF@8__ivwd-wHZb$sTfAnZ9_woF;voQTp&#q zV>Nyp2{fc~lAW-Fhg>m8%+&2w0x zv)fq6wBU70l;pQDy71ZSw~+{5D)w_=!idG(eABl-EXZaHfqjAN2{%|41ABolIoXff z68?^Uws+~@Xz?FuP_wOf44sA6QN4^0f2%Yp>>(7Yd40U@nP{*{qq~k&+wP+PwGWS0 zK5P8l@#yc%|9|`O%rrwjI;UDTw42CsOZxG29av#`kE%~L-p*QE>uY8L`0<%AE`ask zmR8W?*tj{voyn5uwjH-)V!Vn~@BhVo!+&uBfc#a%9D&urE6&ZJ`4C?e478`KfgPcOTxGxt-7RrFcx1rNh^AN;HT(@J|`-=sC`|+l$sq| zkONrnALcZtb*b(Yd2Ycv7LJH##@(4BE9w7R)2Rio6`iN9H8lsWA%8-t9jKc%0fVi* zoskD}Y4vA^xGOf1(g$OGK4pH4+?~No;U}1!M>9cwl(x6!sg@K5x%3R%lVCQtkd8b! zGppOi6orY4>XB!jOm=Q3v7<}4Rp3QcbhgqN$F4(-_2@x~V&vE~%}#q%<2WX8)-}9_2pk!#}szoV9!>x;0PPkx}W6BSKY(o7KV~(C;$qc?5@$8#taU> z^WCEAfuT1{2S49^#DvxI?mtS3S(L!t#N6Wi^Ga}SeR?xjp(sR_D*xocigXzP*Bp9m z@^c|-#UV!Vt7Tj-miyhIdQ@qLL<>EiB|Fq`vv6w(EnTza?&K~(d-~}y>Tp5d5YLQk zPcej~nW2WtgNXLs*5t#vZjkkW+Yv9y)!F=`%*qSVjEX`B4wvDc;9DfaL4_uyabL>k z*e~IO9(-)QLY#7MyLs*|$h4YcJ_%F{KUl7fa+tQwD2r4+u+q$(x*1nN>r-gdmmW90 zwZXltOLU8-Fu+M%lQ#{6qoOP@yV8@jHvT5NwUUz>);@N2Lu}#%VH(%^ThXol4RLL~ z*_+qCpnOUkSUG>$1=-ya5TbB=OQ05(rZiOh@NkS4r%|Jxr>{4jsYcsKbdBeM=Jfff zv-*7OP-Zt7m8?m&7HO{bF<3GEdEBAEs3|IUwy1d~4DqV=89$*>RGiDvy2(3Fo0iSM z_{(+xd0cNp@RbE>0f?*=*MTmoaOAo z$;ciaz^nfAj@kH&cSGM7#Ao%TqedVi#+gak3FWGaz=AvzyQwUV>mM~;Pe=Fk;sRQZ z%*)NO<0aP)@@Vou@}oQ%O%?9k&Qfjx)&z2|1Xekqj1gwT>?#+jEJoco_`}^rgL6|u zFA*3+mI=3l6_%@?JT_Qa=ypLS*$+(a^US02pD z2R|d@n6)xWzt!>r=aLl-8XZ?k%|#yytE?fb3aG`S%J_5FEy8_oEZd7~kFFx{GY`Y^ z71!~cbujVJWj%Pdy%ry5K#||es%x2oDBHM5gm6aMuc&YePW=yUs04QZkOsi*ns9{8 z2$fJx5lv~<`=9A)Pp&{J{8-%x%#;9VrRHLSFS^GtlBgRbD-OR%+knRi zn#6u3(VHd=oy=_TB~aC9W*2bxJu;5qcyD*JDy}UW>}cFdZ@qM^(UH7S2BV*@;zjX@ zImprfG54yd$l2B1Ret7EA;xS`(%VZyrr)42ccg@0bu?dn_HfQbtK7MRbFuDA(tyf| zVak)qfoYgLROMUsZQB8i`dAy|gSp;^Bc#2}r`^B3f)y?47^b&TXV2O-Ji}RSaSptW z0&RHQhP*Mdspz(=z!oIul3oy>19PnOc!PLUy;c&zS~s7|KNx-5YRP<4do)3tUty5H zim!~1rYVd)u}q6U8s%;UmbM2o@nf$^)b9`&8U`V}>MQ*q{0nf^gU^aqNI`ssi<9CQ zzi{igi3rJjpm1M}eL$jEi}Jd!X*sMY{^_ZRf$@nC^0`(Ybr{h0cSN+@=Eb0gx=jqZ zmnsw7%@AwPEzv4=TsZsSrt#9J)}`@3rYH7Ftv!s2^PfVh(>w)?$iE-wFG+3L$K74D z0K?riF%L$9SdlXI+QaslcR8$GjPzovQ0}(qgdq^RT%oFvzbek!0A^{wCuM)+a=*E* z5W>-Lzb6{6$ztR_4MJwR!c?lMGi^KVGljv73^kKP`4#40t|h^W-enazHRSH+eI5Oy zqnwV$U=A1QcF1w<7Q9rz7^P5my-36^+DQ7iD1W7Hr&U1ONsVbR!{9gzsG}^jdJwm9 zwekp20;&9*D9F_B3QLsyfXmd!DwJOp1wUYjo8q&CNppfTMm=S^F)XqUB@~DHun&3c z+J)}7qXs?{=eIf9G}3u@NmOaYFOEpHRhm|X8L2OEv69+=$7vSfiu;){#(>YEj`Cx! zNcYOL`G_DA7OyV=SLfVx(B}P!&tl6gZ#0UkKWxTHz&VwbOzXvI$(<9%=#G|q?#$HE zxtI@Mx~~csq=!o=9uYp3Fxr0{$$-@=+{N=x<-_opZ^= zc~73YZdJ!w_dq*{d83b#-s2NW^+MO>MN8)Vm)=)U3ub=yx-ZEE3bk|O%%!KSiqS83 zX=~R(*JgELrG=iv3@XUm$Pcs=6f2C&G_Gz#_QKoRC+!s~94#Gn69`Y&H(DcKkGxxn zf8CcOz`X87BaCVIZV^xug@86k+y{rv{PwUg;mgU3N~Y*Iwv-+B-6x>H`V8mg1picN zXGfiabk(+Orf=;8f0nFLACgwm9>_~XMqTJi$9nmL04NO)?`G|<%ifQOE~-4rrKvr! zP#H!FyD)|>%*CE5 zqlpU%e5<`tyD7xy0wSNiAu9daLWoS%wW`RbmspC@=Myn>ir|kMEKgtqjbOzb@fjI8 zA_~d+V%36G3$O5TJ%!5&CYp&K01a`gc-d8%RI|1=dz=Hy_#jxzkCIS zLgrYs0gl`1K)#wxqOUOi-j!mUH2zYP`0nP~79S&pF-ny6jjMh|bjjqHXpR?$OnOC1 zcxSm9DVkNJOHm3<5EGI4wQ7Z(sam@zDe9hwcIa$j-Uy>Pw(50>UWE5Bv@WH=iYY%{ z&}E*F+WJFB!2q8ip%AKYT^6RkQ_x7KdcMO%e=ZL{gAgp22yLS z$lCTJn#gto{T(%??hi({;*g$um5d`bMg;yCNfj%+WV?0dR^ix=I4@hK8fA(}|E$rC z2CGl}nzc<+BDU4{QBHuw3DYmR-m5>?%|o85ALY<2_F4V?MMi%RGNYns8`Oeu(Q1SI z(`4iHCJjSiy>eYwhj48kr&=t|eMrJiB~nD@H|tlS9U|V}x@W|+Clbn>#{)Jc97K$0 zKhIXOp$s_C#f!*}kMqO1DW<%7Greb73p(0W=Ne9~R<0ZsP~;Jyv0rQ5?$Y@X`qf@o?PZFh(n7)jaC1 zvBJBBz?lsTgB6^2N%*~2ML~T<)CBsgw(Gwa6Q1x-RW9n4^E;QW)_ODZlI**)_QST$ z%5TQSsO9913^9{ze4e(^TSpI0Y#Q|AuqkA(Gyc^po$oDP`ax%aAw&b~1sWAfhy`!% z=a`4LT+3qJX_Q`rFpNM~uNhO&^X6?%$l7LPSL7?SMYr9?z2Zc#INUe^lxKh)_s`+O zLKKLEhTSpE?_|$7R(BNJPU_OPWd0p0j6cwHZcdZ6N+g-Bcr-P!z)&O1jdeowVfWX@ zlyQm3ny>C{hV~_*(=;5l@6mXysyzpDkh=l-md*n!qP@ znC5HK!>tu!QB(mXwo9hI0Q8C9O^rV~#kjb3VnHz$Ab(W9og^}r=uXK6BDi_4@*1glMEFVdARgamJQ_l zTokhto(K|k6KH+%ITAN{HSZnKap?537e1l&rk3cSlyYzvRx(66GariMdp(q_J@-Iv zUgc__EV z-J-O8es!nod~E=C0BdKKuTgx&X4UB$)k1T{I z^1^~j!ELIMuQ=V_4ZCkAfKYjHqx^-VOzV0kdGH-S-#$2Xvoyc-=y-}%2_gwI2~S|C z1i6kGOt$4NS$^3yyXRz+Bv6E#oY#Itujez7&#nH^JmH`g`CP}kK*@D*38gk6b}Ysm z@nS#x$-Q+Na)OA!U3;hA3CAKk-EyLX44q1p{l^x4&@D&(x)At?QM(l)437%yTBmNY zf;eP2sWmwkrQ9X_?oebwBuUcvTl;Pj>(wZ%rnwBBTxa zqzQH8yF}PGI8s+7bZS1sMF4yA7NNy^Rr2>z{Rt1cH_xr&duv+qjYmra3k}QOX^fAj z>%9?BRf5>~RWo{T1#vo*sYix4c-iwUW6Frk(ZSqnG9Wi?_E#hL-z;HD_Z-4@EZ>_- zjJzpOE^+tcem_g#$FELDc)IwERQDpo>+;&tqB@cq7a^Scm50ky&b+- z35dQZpc?eCF>5>}J+lRwKtAm9J844h4o+%37ol_fy~uhoA~J^=r4|QrHGRXH>F3ku zn-OIZW=ljQQcU9(X(OU4hW%|P+b8oxErN!|!svf35bhQFHAT}vtE1 z&a9yO{LwVEcje)tBjk_v(k#46va{=-U#kFmR(Y;lgc&N4ZndK2!HU1W3Dg;;2mxqJdQ5NlHpQH#g1&u3VL^K5Ld zv)NayAmZ+8<;#94__;e@x$avVb(yC)i>YdUvC6U@OuEFEpRItYKX1x1$?4vVYd%Ov znCi5Q4HSjMcvq8qLO43e!~>aH`D~GNJqJU1mMoV@dkAjUIO6vf;i5pDkmbC+(;;O& zCHElFv!2Z4z}B|}Y4dW9Ds~h8%G!biK6;BX#lni-wRO!2o;Dkg>4Gt~SNMU=0yeGI zEXc?_zhhz@pS&ri%wrr3WReZw4ByD?X7+R)_A0a^8DKrEjlLVR1=mx;R0Rolcn-Hp z&|P%}!b(r~f!p__9*G6u^IJ?2L*m!!9Nl35d^T1+c&g>s)x1wfNR5-EumZ&!8RwQi zWB- zJsLEbw^yr*zcmgvc{`gJ-A$C}i!(g%g(ea$K9e|5K16=DgPeaH&v?@msnt#um>24g z>9gynD80Jlyc{E{CU+2?VqDj4Yxj!xW-m)t;mfLbYA+KxMv=ZZf7Y+ddS~~~kNNFs z_g}rpVM-)tF;+=X#sLE6x7DaH#v}_(P=uJa0j3yStMNO&g#%yV+pjyX@2Aa2MJSMR zur#7K#J!Xp>HV^v>BrT0YiS141p6$bP*JP8Jlaq1iIv=Fx~FN8@JcYBH(izim^TU;|`M!qsY$C>JDu}S%t#voc{q$DTR0m276M6V|WLl1=4!2~iMFHe$&VlL*@uh`D2CeegE<#$6F?h-Z;(R%oAnK3QD;DI#BiS#TW7ZA8<%%1vsVf%_f zxdmM7e>u|6euG3D&k8t(!1Olk#3hvwIvjHV_r@*rf753(SN*E#7W-n1zVfGvE(%nR zQVfh)tX%h7v~Y4INq1j<=p(I71|yU3?z=Thbp7@ZFFkwA(srvJZ zK3Xb44B1k(QM4+WV-a0Z8NZJ};i)uW_i_x0*_7oIAT7FtHvuH3uyZg5hjuPk;olnD;9-_Wx zpMW>hVVOqTz~-#Gvj&NQM5CdX8y;TKnXUNWULbF_#Z~#yIO9)~bJy5yu!a_Q9qY+I z*EcF@!1Y|L%vLC3JseLeQOm~BvOY8~P4`RKAF7oQShKBD(8U!-B2I#;mEG<*T~CGv z%16W1TwcX0$NK!w9xl~OlA4-mOxuaQ$`QPV?*3#b>b{|AA5ED?rwrC}lJB^;ZPvtc zPUVYOD;_3AK4M&n~ zi?y=KpJ^614)U735f`Y*?XOYMjvXZI8k9q=Wf*l=P)JmkeTPL+aAh>g_fZ423MUd| zIdiYbA#{w;1{tiuaAf z_Mw)aOU8b7O`&SrWmHk8`p!L=8eQ#h4VP{>1#qa%31*dUh&%9UB_MDzcg9 zEY^Z_5g2=!lZKjRAXFhmZR>gW6uj)q;7dcU59X}fe75|;M{B+3gJ=LnDPF zV0eRhB@awVDRm}C1Y%@Z2su!@&wLNsIc|Ym(pO?1$RCx~38BXDs>|N(EI%t?X?6iJ zq-uy0jS5~FhJM*Mzw~eMKUDW}@jL8OmpN{PFK0b8Mbzv~?JS^{Kv7Ei+#G4q%}zk) zyqrK*Nx#u;-F7Ge(;(@W*YF`n-@C?P7H`UO`#yy4T?aJL_A}CqubN@~#jAphl)@?- zbj7WK-29|{HAcxeNu!4P10+?SD#}&|X@nH)ei|D@=c>>JoHo2@nM}B7xW|4HjNq>9 zT&e6eF>T2&RLR!@qETE3dP zQh0Ys{Q@@lQx^T*6by;Cfh~&6|FYjg(UR!^L2HifO_+^Rnh9?3$|A_22Vz?8VLMma zJETEagLxZjI6Vzjk9{M!GIAEPg_hWn)|O0TPi*I`C2k`P!!me9Q(45zu+!8@T@X3DjuD z=YG1?_x^OGwZS*e@R~_J%DTs*Ry&V!UptrS@Mn2*yJ)P09buNKrW-b0RkyX3nio3j zGa?G%ualX;B|d%Pb>jJL^?9x37QfLq@DnOODJl86q^Fa3yD-WTb6urliPI!T1>y#+ z;URxll+ygzYrC{e7x~_We}n?Wa6LA2I5Uf5MpXntms^*RW+Avb9zjg&J-AW&L?B_l z=oilw0{_dWy(`rLa8peC%xZzb%qo$_yAP>jVw{_p2aL4WGgS%AFWBJ{=T+~%(|K^N z;~Qi(G8;xB6wrMs-tgN7y3vWGJ?Koe?C0aqD8YRe6>76k^^XfQSO}^EA(C}1t7{}2 zhvTu?Tj3JcIra*+Nz;6f)E=IqERQ4?-4@-9%boH?>JvTjd4o;A5dERq%9(WQ-8o3F z5&maFx7H>s=ceN#F(sCE@1=h*-Oo9NEv{;jmfSta0>4$p7M4Gvu;V97*ZdjIwb>jD zLEcH^#5B?VOqjZJ+t2)&%47xUaC8U*bUAJ-Sc)Ug)3Q7!gpRTT<~*AktiyGWK^)+S zj9`*hn~%i(11FkHNOlQRsYNEX@tPZ6MhEe5wwGtDI{LlXRCfl!QmhQ0V-z|g38ddT-2G= zp$jQ_yE$ZR-G<4j-uct@o5b7{`38;0pomhB?2%0^P*$(HQ<^_q=S+)-;b(1dfdhlQm?WT)4LISG$XG)59P zo41TI%7-g_bwh7CrZC`>gAt-&%wQ`s zff?p;eGj*0X(!t|C4~NUZ=FBNS#ZYv=~=UYS|^`=TF<_^uLt7HW6?tkw<*w&$nL4P zDC^9bl&tflqnp>4suk9moIyGCZWNk1f#`bQ;hGeuUHP*^r0=z2eqd z^vR3>t!8h>OF`**;&i>%ubq+-@~=N_+jumx2We$@Y)j~Q2$wrle(&LX;O3NJ78f-pb>9ThzMMEc;6qiH+f~6B-^6ntiDUHp%-wLyi?u!OmH26cx&zJt z5#@3g>r>%(osNwK0!ulGMfbbic!ILzFdsG^6jhYtieTPdrSrVCqr5Xn2{ue6S;7|N zs?s5GaD(V1SEk#5{=67r7h=5o=M_*lIRau3bo*+-Et9u+zHmpbBmZnn&Xj{zb`;^$ za&SgBS>Q{(YZoDckLjnAF^R0(UG6n-xj@lqgKu0paQr61ZqPwQ%~v{H{i-(vfwpzg zw|`l(XhqaUY6ocYFNgZ1oT3UorTqehO@4t(8$>(>_clc?l&Q?4Q%#7{F6%d={g1cc zxa+d%jbF!DB!mgDuCju~YBM3weVz^*mRs-mVPi7T5U?d&S&Ja`JCekb{JQ~ziEq{u4$O@gKb7P5q_0`CJ`FJvr zDq({#TL5hox?UciTPrpDMQ5~ch&1IiutdF)gtECn-oNj2xQ?2(Wk^-4TywtCNyyG#mFk(!A1rQS3xMcV z{$8xc*6N(>k&sF z!h?&0b#t`GGaurPFb74?0_p4c7{Y=bj8E_UbD#WTA)#0=>M4fnkdaNW=F|c%5a)sGz0oWZK&fFdajiK~{WlhXPnc{;19c zjRlL>vNd!ib;oyoq&3b~Exe`QV)(t26`5S(W)a+qX&-Ujcggx|d7|$ilC&!2FWrel{T?_}TsVaXI{bKQocHa;$?L1ZI z)I)JUYo2qf>Hj0{J)@dT`*>aVIO-^tL3$IVNl8#ZLdQ{hmlg=22q{QHM?i}Bssqvj z1W4#GbV!3FBy=qF(4==%2q3+8bxz*3_gZJ|kLSbQ=U(~pd`nsDd2;{n-|xCA7JmO} zqxJCU!KlQ7>Y)z@Ek*A|lj`}(r*yOqQyhP9-)BNJPBv`j8#He> zfOGCz1gTM<$14icl!I>*WI(lPQj(FXkI!h#29$SQ)$KwBqDsZ-sBJMG3Gg#C24wne?O}m!y)Ifb&)!TYx%{qxObS=v85VYjAM{P9ieMwG!^W_TY z<18v=yg;P}irtIxDeSbMt!dxXx?RCMEV^9!YZ`fwF?Sl_{7f^EW|sNW7ow&#yMtJ9 z0Bq9i3@qQ26vkzxuV7d15!|XV`K<%~*_Qw%x*^;Gn8j;@ljD=6Cm2`(Um`Rl;zkN4 z&6CPJOzPmo9$CpGMfdkbdV1jidun_NkzT9Vv#{7PUm&_7r81Dc1}a(r`#i4`YH8?D zdnK*@?wyNCT^qHzvZRJhH2yPiX6?QUAmWb`-r_cYxoIo834!!M8D3C@(iP7Q?^U_- z38R4Q$;-AoY&OS2wV^oN#fMmykk ztR(ZG7^%L)o$#&m{c1}=kGLG&o&7r(z9(7Rx(pC;b%8|T@VJJaJ2C4sLyA7RNID5{ z|JcGf#5vM5SqKZ09GKR`Y1VPyF^f(DP`JFn&KPwf92Dd^b;hVeCmIgaYKb1X5?0pV zud0Cb9r^pMjSsNx!UdfnpL|SK;lUpJh^0 z?#Q>1bThlR;m&E0X!L(ZM@B~NCTqX; zD_1F@%Q7%e4vWF&qfYn4)bX^%bAkK&sD<@5x~mdaIYt#mt5>93*N!WFGTml_7jSDM z@>F~I1=;4RVlbCt0ig4vy9)o!Q!~?ys&@sWR-Id$RWYy1U|0L^)~a$$n#{cuT!E5? z-$?bVJ!gSmYRQsKU(RT5zXJa~_hYq#|3vOctTI~(P2lfgCHAbY=Kk02EpR&l})l2%Fcbt2jqisG@2Jt{|*dP_Eyb6D2G1FiD z`nRjHM_E!Phv!QsW@0<6zi**@?_MTj4$JAFi!~;Jc9stgz8i^U*p{~;bg5Ahc;Zwo zluuVn1QOeO*ynh9;(+E95BT+sq#wBaL+P=xv*4DbMhQ)WM>7KM`l#obmf%oql|R|d zO}10=hv}W-0pySGpXawu>39%MK8{ zdhCwfdU%%d(6kYje1TN+BGOg27wb#}jW{~(X*vdk2uPZFN)bI~32W{LkVlOVUjnA_ ze^(DxhL{Cfh`reGO33>RL-sEEJ>q4^l)m<`;DLfndD{kR{1~oeFCh_t$*V@YA=0%* zF48oiOLQct5GzNz7&C18iS4`CO`c@*RGWFH>8-6NG5bHk1fU6;T2tD^%BA&T_m?0l z32Vn$(LbOLIVgC<^bf`EL*XbrxTE~AwMEiDKfLc#8=V+Cg5M>Rs;TKOpqUp3z?b6|h z*_c#_ua<~`q$?Zm2txJ-jb}F<3QulzO2Z~7YM-=ygs!_uo|}C^i8!w~eC(qT_Yvg# z2!Ur$^v|(s53PLXscTnAJZ?qV7S|sN2=`G64Lj1OcMlTf7!a43L0o)sd7lT#LV02S zdq2g7-%MCh;nMFB$~i`$5OS6)6Fw!P1-a#PQ8#yDt`I4D^*YPUN$5V$T1{Sn5|%yD z_U&Wv0w3wlUUueDie(bRR=GM4?UtomKr5Tw7& zf5h2W48F?!mt*cos@1!xkO^}S(Me`12+0?V)C4qfD=cm&!$#HbZo^V987cr)jT(05}nBWjvhc=%!jdW z$2pT;C6lNAtup=Ygl&2%Y_MaHpk6a6j7c0$%b2tF$?j9W<0XdhH~f_TQ7$7JrZr`a z>6i<+2{TJ3^=8^4%bQBF44wzL-zORP`Hn3e%y;~v0>C>^$z;5o@bTP40DXCHSHY$! z`JEaaKj{6bxoc z4mkuvF5pVjv-UQ`L%UBDW^xY{Hr^R%ptq$CJU{p_ZGOsrePh~J(vQ8L1Yz01nrvXf&-zCF61w4L<1uGs)F9p0B_bY=r1xh&d6!KS#(bwn~L%( zeq)mH?qmEP=!Ng&#Dvnv(O%LS>lnY(Z%_y1@|mXY=^!KL%+$&2=d(HSJZtcpbI8S~ zwt-?M$twAS^Amj+viDc|OBf%6BY)%wzfK4z8lX}pt#Asd#ie@7r7gu6JDZDGKle>yIC~pyr1~SL_|9Kgy8sM zoXg22hWxu@ZBOe<0A0~tVL=QS9|R%0$z7EzsB%yNd$RZZWnM{8Kd@{%wr2A?$Ey}b z8=>JoT{E~3YhjqUsWk{kkY@9HJB)vb8XXHipK8_R|!$V?qi)P}@dHmjSyzf(7}_YXF)+bQ`Hb4EK?ZPtSP zdJi!f>wTiWIr65ttUU@y^3_Zo|I}%8`NL#gNqiMJ_3BRz$xlqDl^KE%fZ5TP-_a@M z0Mz{SxONLDv#{e(WwdGG^gcD9;97SOc`oVEGB{@e5OiT8+16Y5farYdfeB0LR0~+1 z>;ZAX@##8_iVTc^tu><|^*YtENVRg!Av#9{=3ep5}FIg{eDWeM58(d&~VE3^0Rg zuBX~lCS}M;cqgy_gc$K8=f992^SwA4$9{RtoymrsoIO0@xS@}RR5I^vE^(NJ*$eN_ z>P&C`e??y}E#zN|+t3n=BLihKU$-o*no$%?l+TBi-6;^N6JH=(NIT>TaD z_mqsWfcd@v(B3Kzj4zjyX&MQZs!w1^%TBG61z>^I65Yg&1qIh6N`&||`$1`(QpRF` zX^e(6@zy|B4uz~!ipW8DYdD)iB5XxMpy~;tMx9qxs}>a+M6Vm7uiN3MtvLwMNUV}L zPa&&EdwrHPDS;o=RQc;8b=Jz1^g%12$_=Hh28e*WZFwDEH>nLodp=!nT9ZyL_Hgqy zW~k5Z1y&2oHz5tx68Q?Pr(CSeQXL%7s^y=Jl_8p9PTq*->UYTPR7l99?pqT0dv_(4 zM&;Vr!OfM7x4wEjs%!T>ZpN5NyVl&RcjMt%0sEBqy)Ay|v{p4qnj2a~jhg}*@ND{H zC-qR$W)Rd0sgzaG$Yj<1TGP4{pRdJ#yJR{8;-`Q*_UIU%QX=|RE5t{bTV2el?D3FH zH7b@1f|@)?Uhnk?F5_~E^*ebYJGMcNs%dE|-_zhrtP7)>QPo4QR6Z_p&Hr^zOa$Oq zfT|dtTnX%tbl6oFxzCnF+ba#x1sr7Rxg28wx@$1Xam94@dwVk=%8tYFPUiFQIh6Eg z=4ByeRIw7hqd0e>{G${|d1}mKjF+Di`Eh%K-ENq0@MS#S8dRv#T`|P$X9k(8BO1S`6w$$tF*YDVRwc_1HMH(d@Isw~{>B04fPf=s#bW z-E3yhCavVTwwndJGi+uQ+`-QgtYHH$Ar%;27sO8a>yV^0{W=nw>gV*z_MYs+Z?otB zJ!c%`?w9^+`P;*_!@DQ%hQfdkH_2a4b25L0K94edsUw{c+7 z|DGFG=6%@l@3|Zf&C_TnLHU2q>;A{=SCxzTkj-qHh_qer%rl|L-(2`hQL{mHk> zpe#rYZ+UnVO2TenJ3FxVZ8%td$pVQti}VgNcqcLjY3T=p0AtV zkDd{uB4(j+4gG58lRqu^&(CjeZ5PkYm^}46FBVrwISSmVh8@3$c7E+vIiAst1a2zk z>YO~79e)`-DBIwie5YeJ|Cd%o&|e2+1I&fu5oQ`8k5*XsbbflsDv)bk5n)gQQy){M zUF!$kbuJ8-ofF_?Z(N>#UE<>d z4z!{{2rMTqep7&GKWI|7wAHbQw(kug2Qmm19PzA_wfP8quv3A1of8`rJ}jP(fMdRo zOBCs92#-^zP@N14su;^Bubt+z;mz{t!@JR${Pr;H@Z(Npp%WReR9B0ZPNH}5jKh-| z7M+&4Y2nnIbC2=a*c^1u+q~*E*Oh;0mFSKaf z9dan@%Jq_n+dcYX7a350%4y-3Ni1nRmu2`DA~Zye?ZUX~gQbjX@d5M0i+&Qn-RfRl zV8~r_U@I08$k%7}^+1*q%-ZhLTh$cwnWq99*(A-W#gU3T};#(hO?(LxQP$Bt$~yJ zb|#BozAX>rp*4LIDr5e+aBu_h&fRJlno;n*>y|F%xKIqNbTyW4ewh+yN5 z8aSS0)`?WasPj=Xr(K%AEMMOrNT|2xEHiTAuE;C*7i{l`*XN+`c-jgjpig$ZJ(0+C zb++NU)I-IHfJ*tz`LX+PG|tZgyk_ti-j#YbaC0WCU4FiI*x94q*UQInb-m*Ide_Os zD)tkum_Wigk5X70-dCe-V5u;v%c>8xa)ak^6BPE_uDi#^4CzItV6GI-Mf&@rG_=}ON5n@rkC!_$64nytGj4i zs3}df*>r+@q{oA<7o+ykxs$lMeKVo0DMy3iw|9;tMmq95Wh@dqZmWt_+Oi)i?Njt9 z>J==a_8JNSAp@P#!My~UWlaUhaIlR25W-KE=~F;C%zbn4rbz)jbh^rp5*;V!I#x<( zOKQz9l9}kAJ(`RMs6HusqJb14XDg}cY7mZUh*`{?5Ly@$#L?@S&KqU_<0j?(@3bJP zdY2f!-;!YX2h~)$`0T)dIvoG?Moo&UN=jB$=2~jeos6;4JjeBkm{xMT_MlUw9OMv& zTd!W-s2mYFUxrRKdOY=T%H(FfBkmz%u<6z|7KRxGClq@OJ!h5&8^FMXzTm##Nqj^3 zWdw6cX{-e7HxcASBaT*7+8`S{gV!?|pP7nZry%?CVJkJ2aoOuv>2e7UNc;%P8(lm% zJ%HlfuVK_=VN*ul_@EwXe6z-ObxXyMMsSLSo5S|OW{DA5C?eh%XZ+p)!%QucDnTTeDPRTevI z4xCgfLqrgL;6vZ+-JZ1KQr06oR?SVd%Y+qZ;m-ypox6kMNlDGjuWk+xO7v=D{x+ya z>RmRy;vnBh@{?~Qe-wj8u!v(sJ){=afm${BPdwWink1)IjL2NbBbzvmmkbs?X1HAO z&odpqXY>5!{756O@_5psy>Ei+h`-f?t5kk=Z;TfVJ(#LP)Sp2@qV%kjU`HollQ6w^ z23cI(C3Q`7dPRHTL`xi)TZuJED~LAYe~zEVD(k?MoKnx8h3x~|qz!~zPnOnrbcU@) z*X$Npi>bauQ`Pu9UxiV((N%q-*t5_&e?vl7b_bzQ%9{2^-JjHy)=sMDTOJ$rhQ4}r z=DPnxY`;!rRHcWDdYZ|Xu4Sz(8?V{uox4-n|DHpJOAh}U3}iVMe9nLMy~^}d0&Vl7 zbI28eSket(|0u{k`FlWme&?jIx#@0@&A9zq^D+;`ojy@Onf-R;cR8i?AekKU?>YOm zS=8 z|6sNG^4&JrlyUq!k@%kp>OV^(f?N})`Tb$y?YN!CD{fb< z(n4Pjww>{`fH*qA1~2Ck1MKQ1_~GrN8AIhvYG~9PMnF9S6onSnW%W+N?&l#c5PF2_ z&49DgO>dk}$AqeKWG0p8a2N1Jy0wzb7}neD@e!vRXg32FpB|I0qzcM=53|r*MuwyP zxQ~Tu4vI9^7YENqL?#E}8=aS?lJ=a*jXWrtf{(qKH7(wE2p+;?;yC4_?*nFh#|=J+ z7K|3sQfC4D*I&7@=#s5F2?^_O@^P`MpQliJGAM#hU(MwGc_q#H$jlntldQBL`H1S< zpHSBVi}Y1#4QX9x_sULYXjRnFam!DhVB{*DLHsa#`wi5gJO*Ty(kPwuIK#_(2F=^_ zVW*EX-+Vf$S>S3CW3xDU0W6n7u?z7qby?E7_%S{LVG<{-?J%k<`ZiqaD(zb(GbOzY zd&uF&y=w{otV4U`>ItaUlf3IwrYoCINm66>2)R>W)_r*x9G?_QVc zStYYe`5|r{LOm+KfcF$K^j|z*Z%{aS3m8B6O?}Te+RaV4T(Hv-%BO1W0oIS^lYKUe zmA5NZt{e-oy$f|R$??>L*DgFrqWUhb*oz^53=Sar3_FDzgmD#rbv?xhxst>8D@Td0 zWXD3H>mQOyf{r7f6Mej&JaPgtQpVTJc!Wm`4CbxhFtA zry)Oad>x@RA&O|fgo=#Bsl|Gx8FmszygQL@T9g;y39^42Z|68@SfPa#uLLF z8?R0&EY#;X|9DIFDR>ssk6@C$;Mp{0kG+gR)q|m)-->^g0%#_;*76q}H3eO)>NjKV zKAFMm7JZ+nIg*K2m+=JKeciOUYOSXb`XE(y0rQ;%v(|<~UwJQ{7{~ZF+thE77 zH9bVY7E;@8Jh$x@P0_7Mj2tAwBc#ZZYt58E#%G-!4SqERa7k?H*lJ*riB-5mFoati z8XnToJ^LYq>Sx~N4ky-=F!7*fXDox~U7yPO8r=B|HW5|^&1dUAYrA2&lqJ?-8?>Zk zH(&gCzm(lQ+%%+_A7*a2`^x~Q`HlH^PW+aEU`Gqb-pe$ZOYPrBNiJcjMqF@QSI&^m zofui`E&D(N-hiS_rHV9SE*TTQtZ>JplZVe9%ENEOB4HZ7cK~SJ@{EdDn(-0APlr`Q zL~R4PHoknQ;oR+Kf5;e3zlU*XYpoNUk%H@I#z>WIV}1K7er@X8mT!P&Q*TBPhtrmG zmeV+$G&}Ax?o~7#=%?B@Zm~o_PnT7em3GhM@XRx6=w#gYSLk1}%0jhs(fjX8Uy3Zp zn>Gy(>B6AP`BtsdJtu#=iN9Kw6a0SXE4g%TZcPI~(W6`Rudp}RFLa2_AJ&|2-HmAf zwxcFFH{)XvQVshyd~jWyD}HW#y}7f^rac(*U`w;pc43?G>QdaNd9(VqV1puNzD8N# zA?N`~aRAs)b;ztAv*Egr7H+3r&+_XR;qSiFo#H@2bX>3*|n%Wc|f(VbG+;%^2MzsaJ`|ONoq{TpJ*%<_jERp?ffc)6jJdeusw# z=V*amzf2bcAX>|`zQ64=>Jsli#=gPeYEw&PlG+{QtO z@!`j@4Jj|=z-0pVAmK8viS~4piH-V@kyb#1EjBT0P!|kx_;_Xf^{(oz?`Y!S+V7Tu z@|{1q{41iett51%Q-Fx*^^Q$Wtt(c zm-JA^Y*T%2OTE^`312F^F(0oEOA>^^pR{!t@LDTTJ9z^b!d(k6YvB&g4(q=gEyjO0 zS$`6xlJQ183SXpXIzuK>Ne1&tKZ)PzoPOgPW!^| zqw7cZ4peeZ{Q@*8m%O&~974gH0lIOTuhC0rF{KGcd7wzWK(dyjh8{&J= z)H1Lb-f^V!;^n8W{ZbiubZsGLJOo2i1j+S&u~!H&V}z zV{QRsB8xNhqfyFw5hNGe_5;s?;oY| z(l{7!9Py%wkP`qr+{xxQd5{a8D!B4WPNAOB{mYbNa(*7;JYtzYS5}Z}Fd}f^7x@0@ z#eku_70u) zH=@eZjtcUJo?hK~ckc2HmawV!E0iInu!2-l1tt#i%fGe$4d|`v=|+D+4!1Cb_Bns{*g7o=ksGY$Pu969OAv>Stus3&5Lbs)Q`g~%#=6tNcK z{ZqfA{i<~_EFQ#2L_3Y>mz&rhi)Ci9DA^qY989gt7ZdIN{2@(9enW$aGX|w;#343} z7})FUed%y<|Jz5jRx_d67N?W+^)v{%ap|^uEkkg0l+=4A+QAxS9U7W|^hYl^$}u{z z(vJH_5b4sfY3qNcUDPMJ0wx=WK@hRTV#7A>P6Y|0o}g#dFA($fpL>a-{)@;g;Wk(v zAfTLEs41yr*+Ry_lUm&(JFJqCCjNk?e}b3Iis@ln?$4mLWEBh1+C45`8Y$I@dp7JdKiPyPzd?5`dzd30+yrz8b*OXYcJsWW9^eSF-)tNedB&0r`-D&~T?VR|n$gbS9`g_e=rlh){u%2K1MWi zWq*h2-ZWgiTV+Z{E0>z?1rzx0#?OBI4-_R9Dtl`A!@oh3sKC0=Kqrw~!3P zAt2&bl8MbWTn?UiMqnQ48}mbLW0(7*K8E$e17S*XNG(ko9*Ua)Zc^&H&;gY~2HFXt zPBMlWvH+x`S}0}~_IxtHxRc_wS^*4{9=3Isu2{t>9|bD6CcV3iZHM^R0(` z>T+JCe{9M;zS{QZC{o7@uxABRNUr+moe(Tnn1v_7)<(vLX(`B(N+~DMg@SX-t?9+u zoYYFW2cvG0_<%Wfh40w65w$K@u5$a|b9znsJ%v+#Es15sWUxn0_h6@P|l_=xY_uQF`1@-sNb8`IS8WX{=kpfg64X(~%BlET`4 zbjuLRNJUy!YlTOD#|zCz%its&Twr34xxoLFDP7kxW}zs`^^JbE?wW_UqUPwGhalu8 zD>~5=VzZ$5(R+S-<$%28F5Dpf_@C*i=_Ns?oQuhoxl#ceg=KSD%72iR4iA zlj(PzlUVFjml3#)4>%RwRaGe_KMou&m+k@mLs|pBxZk6&3cs04@9%O8kc5xTcUo75 z|BSEhI$jGNW37%1X^8Lo4W<-4-pnmQ*)WbDPNv-h>aybG;h@fq0!gl z_s`c){ehw>i&N{Yj(|8NG+Of8ag-}N+pKQVPL8iWuC&Qe@+xp9elw2$1!v6DEa#&a z>*#i6uHUxHsq@$jHblTsNn<*ZU4c;Y>+A-jNegqerntLP%#*KG;NgXe zdO2}PaU(u6zBGDTbl2&Pj-{vBbDA5Wt7#M7``@5(V08hBDZ&Xpf6;8sM#j|^0?Tj^ zJm^I{t}CpmE@Q+n?x5ok4#4j!#d1ECK9%OC?qlgCa>myG^vTf7CUVAwm!%sQn67-tjtUtM_X9t1H7 ziYE%tTJj9S+^)2cf6N(vXm_|I+wDGT)CLfwc(^`FZN6&Jy11JT2A6ROVd~YOXt*=u z3=+;;-uAibO8cmf8Q-KwTk*!1>>nfIUI#>GPsLzO$+8wOzBIVkQAMb8!TMl|swIGN zemvpp)H~Fzq8My8x;fc3ZmhJe7aNyk{>Gv`TRjPA`gd$iNts`~I?`~~z(ZLG%HiA% zn>OqJ5m%pPb;%8FQcWnRF*DFuod~+ypTWVw4I^uOh8Lb&{!my&PQg{;JkrSug7l+fr;M4X~-CNd^IyvKM9-CU@_KpJhe=X zr=V|DU?2tbV|pCQ+0AP?bn?PzhZs6#L2!!?s6ZkpI8G_izH_S>(iJA@mF$jCvDWI# zjKRP|H1`wy-t>zR-AuA9PfExD8P#ML5aME;V-=)%dS#A&)v<0zFg-djY&1CQAIt=4 zZ&w}c-Cx)9-;Q|PB`)IhF#%m#gEug zEOhL$HPGE4&5)0Q7e}Zc-b*misxIO;n>MmEUd-GZAd|PlBcV@GfcEtPceXIzZYET+ zYo`3up{`moHFcmPFekxWm(pN*ixRL)?%wVeisD1AUtW8c+Q|JTeX-ba(&e|YY%Y7s zQ)a@mfbn^pWNB1V&loh!5QKJd839V&s06+U;$E;pod~P(trtr%3!9jE27B#Ze0cfA zkWd~Z-SLFEq8`Q~$evDn zFpqj19-?>t&Nv9dhk*mqE`^tp@NdF*&E5E4c0a*}*(w5Y<`K?;^DWOKu9!6n`bsa9 zgZ4oRpGerxvmFNb&KXDc8?KSkE;u#*_-oD7iSTZ#r+~7R+a1I79j2oy#&rd9^|p~? zmG5(l&V{W`OxKu0r&Kz5z*OO2>V()54)UO%Uor-Kt`BTVwPTKCtolFzvA_L$ZpS9O zK!S}=F6xpe`gsAFNNLV@Gk+DTNmN(%DXx{^i;f&ChyzK*jFin`q%(wqFFp&nVv=0!(HISidcM?lyXFPha zxi^qqJxHLkM!{wo#k?eYR1r}Mvz266b(h)?!#XV*P;U;Uvr^Ns(sC)gHtE=#HmL#n z`ueU#68EgR!(*HEmF^QrO7a8(DS$wr5C~)gdwW+Dp_$-GGlz$Xz7-s!CN_E{!h|ts z!AZ6ugRHNQc8ZN1E0W+WnZHZtnYp7{8FI9akn8R^@Jx5-US%dlCFVo?NcYVEvCwo+ zMOQWiI3qO5H*!rYnQAj?0OvxlRjR;6l3@PdRAIXFd+H+h7-88gy4wfujtJcexIRMj zC(GIV`Pg)A-I0JKOj=6GrUEx4D?3|@mIfQbRuI%}1vYCQWgI7F7M6PvqDho z2jct9{u7Xw_u8v^0u_wm^=`0~^gk4fgK?7-#I)q+2M&LqLE%iJRTBgsjPa)}n0c)( zYA0UTjMD9Mn&RS{6iqHRjFxZQg}_46o-L#@HG#)@HerRWs#(B)vVDJZpgVXjk=;|6 zYY%$n2-KxjcL}OQ09kWpOag(Nu*hqtW@(o$JdL4G&^Pc34WAm638Jh%!jWk3Ux7Rmz-S5+L$fc*v4?AQzFK3mhDhqo( z^>&t7Spq1?2h@cDkJ7!?+nek@w}$^Aq&eH^z3AMkXr7oF1C!I$WDY9!55=pmIh$eE zN7uc_HtZ5)YBt$o9?pU80po$!I*iidKh@sGD#=0n76bY^t>L@SPT2Nv%hi^sUV4vv z^?blkYkFkBY^pRBdht+8VO)7s@=YtfBsl(fkah?aLPC5PjDBkp;a=s!xKY{13flt5 zC4bk>ynWIIcGxXFyMCECFhA8kdGI4nd+jy@tI7x7^iWPtYEgslzF0mWzFS=hT5dBNfucYH`MFQYqDYX* zrYd*e^AkYrt)$mnrUbxC)&7HB2c>5F(pXC*Z@Xd5lu78Nh4jtCYB zQV6LwCu$MK`!-(sq!MZ;5`d))%S9$ao@5Dg0XkNK`eE02fQpKuc`|CiFls3$=<^+D z9B7sjhe#8nP3n|0Pq|8X(}YxikJ2^Bv-gDh)OzI0?^kuo7%l>jY)kOs;Pn60f4%iE z!afa*K0Y%Ndfy6a;Ua!rI(rTa@p2q8v)w zRIV?89o;^3^JXTbmj2G_ephQvUkJ$3#!;wlQe%_dPbMq39S$=t6xdU6Hjt|MfDrDw z=?B!&U4B4EU1W0yjOG(xa|kE&j)+vVt30alyI#_ly7_e`oo$*`avq#4#oOWg$!SqvE z*EfrosaNS&96}ybYyiloHbcjS;jUIqBNS8et_7;WYiDSX1p~H( zTgI%1`BrKLa>K+e!zWSH7SSj)cfd{F?x8oINP~J8YVH2pKfyq36YD-qMt)zwokBpl0;(u}|n+bLb{FnE2UxeYbdK*lsN&`8pH9h=PH`LBkC93(ml zuBR9nNf6}a<)q>(MMeb-3^lB683G1NZoeFChGDtMGc_*`ED(IsuEBoSY5Cc|J2eo# zV}QTUII3fyel{@=lk`xLWd^kwBrPRPi%ynYTROK*kT}YF`L5_ z&poQ|u|SEb2G^A$F{A7{q_kVrcJ1Ls`-t4B3A>TMI_|*L4|QO2Nuc z+mCN0=H|4$RFC%+65|al#PVGjJoU`oVF($FQ>a^y9LVx~o`6>1e>5T)FTZWYX$VAy z52KU_OOp(H=drOhkirvm?%DH-cAiD*%R|Z6WDZgu%+L}jjoh=4vgUBA>~TYotaY+W z1#Jp{WgY))^Y4Di#ZlW`A+-oDhoQCH(97c|dyRNF>6c-1P4Se8QH`P8Kcnbru?*$a zgToD2ICuE24hEgM`Pa`@zHOod@HrxSG%p|{m!)8<*n1VNg*V=Xm?-%#7gfdOXFI)> z6xrr!&xYbkU&=l+5pbkmBdVgUe#c5Vnb=cm$K~LG^3|KvnpF>)&9|!V;KMu@PJpJ# zyVHnE3~)%Ah(;M`YkL*ZMI0R1!td_C`m+mZ0|nZr*Y4NfQqq_HtiZ$KeR}4 ze9!-TRxtkoZ8D`Z|F75Xd;`FXtlvchX+;TW&Z2Me+SQIHKde?z|McHsm z^D;7SaFX+mMy26N-uvXS>e1P(QaIYp3DZ>qAEl{^1lC|oBtw?@QS?@Ap3ZC8W0kXH z6sFdnrVSkAInWqIFua5wc zM+bsSSyjG$6@%H;`bH4*j)m$tsd*<(2SbV|CaN_-=qcyukmzXx`@= zKOnDZ(`O&pFL2=OKckd`IzRc!E3kN$rT%CB5^;MP&c4}r9Jl9H9Qr;T^cl5{7oE9G z``<>M|JN@5K#w3?ujl{RbV%+#eu3^j2(tnN{1B^2@{f9`Xwl&Pf-}*jKKNEU-C;o* z{-$1zij@0NQgu2WHTnu`_J1^fX&m)rb{H;Vql&rKjF=4%c8#Ujt;X$m7nXf0FnP)c z`fO>g=K8eEe(G@+6ec*n_{~v2?YgOON-MeOO!?5PCdWnF(mMq*^|ONR^lTpgen#QCL>urh#-lK<6B`R&3hsHAAhd53pa&V9} z5@bKvEX*Nn5G3S9{lt%O@5Of$tM2_12j5scqz&A^lAsxx1P1yfOd?e;LAiirM)Vc< zr@UlinRSVd_=b}kO+%N7##~Y@+168dVF)Uv#Tec_QfUn^kjy;YAm_9#&an-@uiSjG zlT>mTAgPZiHzw?3-0?X?0~tN85Tuc|V`AFwjY@z|WGMG>6JG5g{8%ws~dxh$wARcC1)C`Yo%eevNP%nUBYtx->AMXn!r*E~jJtWKHri?^5V z`r@8TRY((6zQ21K5cCN72NI5q+Z}k!(!AS~^kz|$I`fWVpM*C^rOjL=9Z{(o;wqHk zYyrd5EExlzn}$1IsRxU>`LFI+&Lu5GL;%oUtLs5fBgSk5BLaP|eY$W`aIV#vsceA$ zVFKbEy45-J`i6*sixaxU$-G9(i=e6(GP$d;GfrLY8m9PMyaAfN=9?yYziyq(OGMZ^ zkj=DqtFZXNr>5JFuDOzxizXBa?}>1wBdqJ;VB5wmRTObQdT8UC+E8!>w{RtdvGBFU zn2+8tg4F=G0V72C8V4Iqb8Ork*|g-4$IXEv{_={?@tbial)~1qb`75^W0SK8Dq_ZA zBFBCy(>lX^*esU8+JA?G7r8xYnTc4)S1*ZNr}C!KOfuJBHhk{8fVZtT7#$~lI=gQq z)r$|+Q*i1a{jnsKfbe)Pwxf{RSey`hSi%^C6jv_+0Qr~e$i|`*QgogpkLStWQ&Lpw zt!_V`f6oE#TVN!W-!f|SK#sw4%Q+1@k*^@j*1?JEA**wEx>#4m#s>STP>pDOhCKP7 z!n~A5x8(WSd+b4ypMsBkHp2xT;l$6MzziS1BILJD-@W|z7FgRN9HQN*GCVKSUYxtK z^I$hXKQs2`ehBq=9MaLUQBguU#d%A|2}pGL^oT-C1zGsgJQ1|Sn&UGdxH!|S%Fsa3 z=^0H(NSQWWj$|4x;-^htip!rb?4+84uq8TuA-I+V>0jG zba1;k5$ZQb9uX5>Q*Qxh61cJ~>8h6$d3HUtP||{{ofjXJ>1GeW|e22s!T^gu#2}adj&fCq2-%0 z(6HqEuqG?5JC3CCqbfa%Q&*=16k=O62C$_zbe4bI)hgZd;{YI(HNgTCI#sQBu z-c{$0x=cSEnVkAUTp}lqT7OCHVVv!TJowRVM*bzIJRgkp(-*dVv&?o=bmdY%!B;$u z79o+8T{p5_j189CvDHXot|P9Mm7Re~A%S5+A!*lSB+Np0@4*Tb2*p_*n(Hx|Tj5r9 zUDCBW@9ZM4z0~=K(9sU5pAl6z{AejN*0JDGl~NooM1V~Y;@Lh%V4PGn%}jVaynp=T zJtvwb5nsR~HF$UGQrSec*yOg*cY;z?R-=;zNHUY!w>8h_m}UoH?Wrs+0?+w*^!)~I1_ zXcn=iSsO^rP?`~&JHvFYMf%E6{p%uiMRU$J7>{Q-dhz&-2gh4dH7_?Gp`ivQwsa-A z!&)_-qA`2$BaDw&H;*?!rlHN)T9S!V-_N=S>M@ptCYT!c!l|jssy#cmIs!s$eH4sZ z*nT(L$titf#Pb}C*AgA+Nc_kX968)0YRwqZAv=dyC#N<6F-Z|=(lH#jn1j4BpjikJ zUTkeIBwHRuYW9KzR;1i-XPL zv*xVlQVznkp#M=sJEAw`xF9t)_1j%7OpN1!d1kMN+DN@hTt7fZLn#1N@Jr3H@TYFg z@?~~r;f~wL`-8o2pRw?tn^PU7KQ3=q#kkCtw!%TL?z+>dqP>XaK^%V~+NJx#cSNNG zIpIdVtML--X1Z_mP+tPt8+4%HgBR<4xem4@DV!f&3l#{vr$#cxb4wFdiipA=Memz; z&_0!x19lEjX?DA6!o#}L1Ai3HQSZz;HENdsscYO-KF;r-Mcy;bCb!3Z%YJ{efKhCK z-yio*b4x`})biPwV*HDY?3R}Y-0lRD_-+c>``9!ie|lOpgLE11rZD@P;P&Pj8TS9f z-gkyYwWM3OqIeKNL6HoSGf2*0AVqL2%b|+%D`9A z&qPULqCPtoP8W~6rO?D+*Vo@{Vla@D!+EY8%dV@P-951oS19jjIovO1+2O#U4mK`R z?aExw@JH<%%hwUBie0~fTfnHa*-05!6BL4r;cGYmD%+_Mlp-igVP7nvN*s0|0zU!U z>|!LVP4*g^nDY(mm=A`$uWr^O=tPgI9WEAQxowfGVQQm=y>?R@14mjZ^I5l9j27Aw zgYzb7`dYCp$SB%`$Xr)*DIAIgHc@(|V!06BGgYl?Q%Ka#j7|$~-AdH?0QBaJT042D zKt7;sXjb__o+uHj3!%y}u0c^PR~_zRH?+{Un-pN3gFmxi&sWIIAv80b_5yR_fGLM_ znSxQDNnv-Q7&v@zwQkkawg|F_^|K2F66UZH>q@d&Ypit=C$K^g=J@&u#g@Uv4;HM^ z#oNkt3UQLE^v^M-_(F*K;3x`kv!o~oU`dufca@yZU5B~-FL3B*@nWByF%IX>Q}UH# z984A(&w(<#T`iYrDjbOTq>_uMGmxz?_>kdlKn}rxu=7;_f(yHN`SV%@X+$r%e(@g zi2K%=qcO3yYs${u_z;#(-jKN{I}$H7W{b)@y&hs?ux6Xf;{fayQ`1l=vZ;!EFv6osV;<8tq}lzcwwrxXbx38%fM@ap zmB@V{!nGp3bu>NJP_uHi3VyP(I_Xvfhrx`a!|SJVh$_dO*EenPRqF`Gr1x~* zwFag#aRi%{n>!rS08fai+Sm8tEV`3o?XvXx8%#H=I2^*lTPOLY{Zm)+Q;Q=OB5051 zb*oS_^nfwEO9RGATqNlud!Hvd87A=BR!0vt>RXG))(zuONfJaA^&?-appuyco6mWY zLDl#&JLVZ+>Ecl;x48^%b5hVnFtfQHSInC=YwW$Ualy!dK2>xhFrrE@1IIje!Czm> zd#+&&K_x#Q%{C+!W#p!CJyau`WO%5OAHTp5;Sb+sHs6{+zQ@y(oc6GQub^eB%}7h| zHnz~fM^IoU?)_Io85IV^nq|L$OIM!CNzO-q*)BYZm(hl%?gz^v9{||JYXT6K1$)!L+QdYc$-GXfNK*Kw9OKL)b51 zi5YcFH!Lw;qFxgf{ceFR4xJ!fQ5_^BMjoZkdcay{-mW`Q+-znJKiGPR%#sx;x-<>fqfYmQrt(YebrVuVkY0DZ0j!w0kI;v7AFwpd0=I!uB?ygc6 zVOkJXpYn~*1w(z4a;sU$zX5iuR}&}}JQi!)3-VY@nb`AOqGBEl%#Ew4w>Z4!T73HX z-P#USyR~ok-FBC@82D6n+wC;%A?Oxo_cSuGXV;Xd?6Ju>QR24Lqyl$ZJU&G{-F;Qq z{V@uhE;|+T+$^QW3gsyuqjIs@f{}XvR$xqvTFDK+aadmOgHZYVVWbcG>gkYgD|Sms zYp!o0Q!YXF({chvy^DxYS&gFJOO|5e3y64mPvM z9p5ccUoim>_rFd&-stb%5G=?wW6h7pXVCZ*>hQ3cO`1_jT(wDFqr0+g5X_%t#$Qpw zRs1kJO~3R(>=e7#EA>*BfKpZd_p|mp**3XVBUWNQ6ptz_>&Z#0>pX}k%F4sov|Udt zEyePEtk}~_!n%y|^QArcBVrgr?XjwFPdGi*Ok`ClT%le)Fnf_97v&r-Uh_dCBpR7p zzeLh@ib#cZ|C1y(5lEGAIhX}(*}{$L45bq~lgKxiMB;YvN-E7Vk62uXIw~=%{ZuiAIjPyp(R~MC z-V@%qlyK>S_-w;4!!#cQEZyUBIKHJS7^f#V-wmgqNs_THC%3qUNjF1dj~AP3v`Q71 zmlAwmk4g84%2M1Z-x0QG&bhhJt{!2=Mbcu;*$Fcaza717D3N>gT(zaZtQenYbdwl?t;6Ku6Teg1;gg=I&0S$Mze!`&Uo(l@|f*qMIUoA0ZMPR@54v!dNH!)rl2#{dX! zNbBXoWcy-b#Qe_dd}MlQ>op+XH$VWylW|S9a?6td{w&gz@xOXbVMnc?;K@Xqn%C8v z;q8m6?Ox^KJ$G9d;m-@%XOVd>%i#f56+yI`;gVNNlUp97*BI){rpxpe{SELscLdw5HCjvMzb+_(g9RKX1Qua1nR~1-}AfO@OQz+MM35S zk+;{I72fB3Q=M^|$uf;BTw76gnk+x%;U@Wpy^ZMa3j7cL_}9|2_Y0jP#}B9rv7O-W zGciIoAavC?3#F+_-kxZMQdndrTgg(|oLH~A8xkJ<532tUe8sy?Oul(wI;n$#Z3CH9 zA;nf}BhIm(xABOEf=cm)(H<@_JxG|bU$#l|Dm(i(K(O`&`EME8cmM6NlWU!`s1c#s z!^EwESX6WLE-)uGmDGEKMD641UVfVSgKuYe8O39ZasFkH9I<-G3}pG!`iZ)>Nr zIQu1yU!_kl+rN5qS42gn4_c3Dgg88$Uh*$G=+@i1Q=x8>95P^%-)>F3H2t;G&CP00 zRPA)B=*TOdy;pptWS9qY&uU*=u&&}HHSgR`4beD^znr!|wnlWzrQ(#CWD0)Pr*cu1 zcRsUrXRq(n;vg8M7JiO<*9v&?I`=nfm`X zb@|(q?V7V-Ie^pF^gQ)kktdcUmDBNummoys0PlNGfs8m9#etCVR^WeE{P@p8JRA>^ zx5&Bh4Pe>&s29>A&9gC@>dA?JHWzgE#pG;xNB)-|lL@uX9i6zl2mITQwEs6@{_W^+ zi5mNbnQO??4y+UW(+$%lfTD2Gmquf#WVn+HdYn8MND$okJx9 zgL#65K~06PUv7`ftT70Y*?M!<^fDVts4!NwZGhb{86`y@q#9}{L!Pr8m73*I+d8uP zvF+i;>PMqkcK-_JO<80j*l-9`Vkd_4epW?J)X?8t0ISom8)(&6Lz|0wG`MRcqD=wxS3I4 zg;%khL`3Ge8T$pxa%=oGYz3+LZ*?6X9x81ZQ}aru@F|bzg>O`-gmieeO&h|T6x+k@ zBGXzYGU(6i(Fp1V7xm0>#8nbl8ZEamle7ZvJ`ibR&3B00!YIZxuH*ytxB7Y2D4_;N@CEM5Ads8_A zYx)LgL)LXHM2xIzi4uB&nRs(M?l|PU4-41uNU}QLL+OGGK~Wto;0wY%n>ijo;XPSB z+dLMEPGa#a+deuAzUu>loJ_H(S>39|%p;Bb1_-K$Zf1m#lZt)=@Cb3$%Xzp$`0K3> zIab{ElxA7Zv`HVIpLkXawNDa<5~~U$S)ULTHYrUaA{208?GAKLJUj4kjA=d(;?q5? z3Bz(1^~7a-^Q^YRjfhJMIJn8C!V}%gLJk8R4jPP|eYa z!H#p?mdPI#az!Q)*GtNnZiQbAC$WHZx&nQ#ijlL)dn}LkwwMXE$^FnC>dW@<&LUqC z_$b7=Yd3PddbYvhgCMZ4J8)897@E$yc6LMe`quPRT-=eK(f!=^Md5j?V*VThs863~ z&)uM+h?L}_o-J^e^z=rpUQ**;-7;cYuM;uzQ>S>%n=dTq?F^lad){g;K*j(;JG8bj z@TMMH_}bydmPB9;OLfqY!EVY<#TfA*c;We1$nveW5m>Lw8B12en;}oi*eTb&Nrt={0&;uG+Wrs=9Qs z@JrwvZ5DR?1HMTK^=O0zwUQtPaxv3zX9&O7vRm&_JtXF6_NP0$LP4+UvK8{$M~71^ zJu@d$d*@q4i|5A<>StMJz(a8dMwiE@EGLaSWxIAmmk1V`gj^z0&j>%|ier3XH1LW# z@{KW_!GG*RXCzdvifsx_*8B=H#L*=-wW_cVH&!K`-D&37f2ivovaV*BO;JR05psaq z9Byo{$;H&yw-|!1u(>G)s&VbtB}H@g`^Rvh2e~J*oSB_%3VY2W5$&Nb6Ed^Xpof;? zi(CuA!g7?iPx!Mj=Cy+CON8ECPw33C8{!)vY3{&r+pXb`2HJAoUJY^$5gA(urx5lx zKx^aP-RT%a+B&Fj?AlN9y|#mF2;`D!+=Wq*6uY`9A_|Adp`0jDC^&7cvF|v^8%F$o zPp}W3NSGW*+(kA7X?l^2-oG_>%!!P)n#W{~(@KLU!zjXOYqx!F$8DDZYcCz@#4tR0c_)cFo@a^H1E76jF3aA$oT& z2ixjqs#+fMMvs4~y*Ul3V`ty2|1+HFB~4$(;_quo&7IN% zWdlAHhVQ87K=^wc{>Fb-ATT}LKH9pXHT<}+Lu7|Ciis3XhJbP3_k+47e`w8>9N-e1 z@aRC0G@S*n_)dmMPkyCpi*p40xRr{m`Avfor=^dUUYUn zdF3C}^ZOV>ww?Ww&QAQcQ!beA#(SJ0k%p_k9{d&aAA09+x^_3?lF;1+zX2$`X1BI3 zoC1d6jaw)`HJ{|S?+46Yv?0N4CJ``;?8$2}zK}`$qd$^0ffS^mU$TW0E|M+&4sN<_ zM$?c2@wpw`_u)Tb`pxkOta%GLu#t?0aJ&?PEjtS4U%80|*HaNmX~Jkffb{pyxdOJ+ z)_2*>4!i;=y@)B2&{k4BR@YO18rD}7vNu!(M*<9VUJZEe9y*!$uFz*Kaion%61*>r zTmr8qC;z7iyVZXgfqIf}fUw5xBV?8b{?^rvnWMLVG{$<>mYur4EWNPQ^f6y1LQvMP*UXh0{!NLw#|{`TzFpN zxP{bBH89c!EF$4@RQC_<|GiY}L~jM~N;sj=03^d4Q2O@kAW{s3v2t|&j+?IHhAj81 z0RHOkvZGcn>$=Wz&1q{(rVCM2?DuDJxYWzP)3ohBMa_4?0D&US4lcVAjr0w|@hDwP zCuUOYhvD)HX@GzCTA*4%#FaL+85@GCt#LcC!Wb$H)5YTt0 zxq?6nMEFQ_w1%SkX9)bwV*bzM&nM(pOFDP#d1(RS!^w|btw|e<=2(uzK!~hj$)E1$ zF3pd|r}0XW!mxe?OB_-F6^?5~XDNTSib#)Tjrgu(9+PF4>i0V%A<0F|g9Yo5?T5a+ z^e4SF7n{#7eejit=^!QiGGv9TzfxHkfi%R^)nvN5hV~z@`JMbN9g#ey=LwuU+q|2! zB|LR{p*QXGXFUSR*g=ZqIXG{xlK-@G%3YXV#ApkVKl!s5U0(XYz(`OSp zzXYWdh0tW3Da+mWwIW$Rx8`sDm-I^Zkfh{vfSdrl?``p9Z$Z8^{0FipaE5FVa<=t9 zwb;Kw7{YxelR1=^v%gr6vw9QXuD~GTKXBN;o0!?}&c~MgyBft2AfLf%qy$vEQU2J4 zG7N|jWHzBo12cPcWtBZ~za#AsIU7b=E!}oF#4}nLH(=`U2h3dh%!c2}IN{m}{RT90 z=5wCAgW(jCPMe^>GqDWEACY!h>Q@;%f$v=n0yPJ0q`_Xoaz=+7WEz7;#zcPVn=8h+ zG>w-4Kv>}}Tf1+$TpW$;UL5oN!BqKjM(&u>_}%t)aJpXF-uEF5pc=P+3g*tuv>)1V ziTfXX`4q|d!DZJQu(JtWPX2wNQE>1f`F6Z~)z7~7QpC_Ju4aF~;>Gg(R}rh#sd3M7 zb{9hYEPTI_#lW%fmH*dg6ZS%avdu7UV^5-1Fk+JW&l}Z+{o#!1hZUIYUaB3fviH&NXkhwMbkn%@xOC2=+8@l|H|K2>Cd+Rl@kAdzx(fP zLHOU?1Agt1xS(-;en{D}Kg4-fD_?f;f&moXo2|U37a0R5`MR7xG8A@LyQ8*6M67Sc zvZJ*g{7I?XLs8GdEiJi3PgQ(;uT`(s+QF|D(rQ)A_d%ZXL=ptv40i1XX^@)t;&|*d z4pZ-b1K`v{S8)VJ7O4)~t9jQr4-7#?0xF31Tj~j&XQ~K_zv}xdo`2!xukr8~zx>6Y zf9bS=%}D~o|M_+g^nBZ+eaaf$#Fp@aW1N_9jrE22r?&#=PVE_ z<5cM*h$lBgCY-&`hk6fYk-O|c&G=_t^89|qKmJYmSdPvh z+1NSy?u&ie;jv`-=l&|tVw*$rSY!$`edTAaZhZza;e*uaU8c5)A=pY^Uoq3g_Et)o zJ~4)8i-T8}d}M?9d0|P*CC-geGeD!*9-`bN`FNoDMCJN!nWU)Q%G+2|ZS2??HXH4| z5xL`ZF0l}@hw={CPa5z2@g4p8-#cmhtt(W}i@XzNcx&ZG{0bvmvrOMy%*k_j7G=-Q zsNL++{Y~>cf=_m+!*Ki)MRkv0&1Lc?K`mL11qX3g#o<+a6z^4|{+iGvdPkC~;lvMJ z_QOVQC1CVB!``}aP&;?;Oez&%b&g($<%Lxd=LGZ+Ju<>3^V5?Qd<6uPE!=L09EIS~ zKfTBQ(1$2CA^JC)w*1AZ9g#0u?7B{~1lb%B94DC{P3@WmZ}yIYF`VveK1)zawhMmQ zEd*m?F84k!FHHjuMVK36bd(m+INTC04o(x0D)-ZKlKymPF~w)>AV*{ZhgwhcDjO^U z1>n-bgh4b+QJ-0R=~oH0Y+t)!;geN7yrtO7!7~(Ly%*)S9C%``sAQgXDE8c6EP~cI zxx8I7($0oqkK69Hm?TqZ%l`1`xCctlj#PlHdP*tw#QH z)i>mudjj78Rhh`lV;TH+t^v>E?ABRg1f+s};+4If&%-PC&}?qIL{IlF-pAzY!!IZm zu&9+~GNr5p@=36Bjf`S&zxk)N{D(fgWma_Kv9?`m@3Txtl7=^v#-_fe79nATY?P6Y z{f4!yUa67yd);%8kVcQ9eo$4JiH=p45>5G3N>;=$;~s&J8)5KAeALXQxhJTMIyZ|cY#LCXgJRWgoflaU zllHm`eKIZReZ`%2bjR0bQb}eJ@60rYVD-YK)XV6D)(h$_QV)ZRyY!1V9M5em`I?PU z!x}J~tQf`o6kNJamHi(7Cjxd=jvM+)3)%^1*^J}bx+=tiFedeN5&`>H@eg$>1^ zs0%BS67(D}iEvg``k0qb&$9*{4>Sv8jZ?2@XD;As;=Hg|HbH6yyjyEqKR4NU7EVVvD>qTA7 zw>V|cEh-{S{iZ${=8@CE?1ShDTYiBU9Ikzx>u~5N30!74607i?FUSBzO4!K6f01Ir zqJ)NwOk5js1_0O?`itIj3rg}9B#H^jg_O=jVc%#0wuS zC%)^Udqn3j1-I*38W%N$>3VVr#O^TKb*)z2PiJQnynhQ5WxWN(XI@ylK2%VHt~2!c&8f;KfBUH<(88N zZ}Vu1wZ6{g@PQUjd&9N0)7`MXBy^HhwG=a1+GVK^tpz1LM5(&L#Y&U)AjigrF*lyG zrLuI-B88sew#$pvT25@T#yk{)b9_DpV~{HEHPHT!Q#5QR&yC z{^w|L=V|VfyIIErsg(n5Nm@oLNmc=C0)#577R?-`FdSBVkMZ`;?zTwbbnCq7Ows!==dw{A`mvek%!ut7 z{pu^Qj%*mTi`5l3N!w9MRW#q`)W5PP17TwRik0f?jQhE4T@VD9x38KbdTqc49LysT zl`O7DgIj3EkYie|THsjkke_#Yn_zTfew!;`*yiORdpH=Qa@e{U---7=*KSU#%M&J; zL%~;;exdGqTATJ8P-e}hd>Am1tUINquAUrOQ{y`#vxt`py zA>@X9t5^%5Rr{p0mx*;9f2qSHXgc2LxQ#+BRBXQst>oqS3E>UbXGB#B87Ibud>`Hp zZvrM+M#F3j0=2^mmLd}U=7YVb&09@O_YKe|`MmUiRP(+iAqlxK4*DLOwSg?zw=Mp5 z5xO=V8g0S0Xw62DU+}Qjf(pwHGghm*CLMA=%W!L~t!uq9_zX_O)iZbyYfKp2?5XvN zeacTX&>+;@l%7J6Pdg_VtcS`kCmlil?2DDa+#sq$U2w`1pkBxNZCu_HaENq=15r)Y zw!KGq^nORK>>KCx#ir8Uz2#3(Ka*E}>~;@jb%g_p*QL%rSW}Pc@EbkbcU}2t(&^;( z$Rlu)hh@R0Q$tlAruKG>H*jh;k$n)4yHtRn34IY0WPZ3?%w+IZEOv1^Ish zhdy{_bCW3^w!5nXjDEl!`mV~7e1r(IdZV)$^r68rGtymij5)PwUTc?7twc7Q6(1UE z$H+Cp*1o<&RF8rgKiG*I8LkiWpyS(l@|muz4YBH*rFzTEN!VE>y=pAgra%FTsKOx- z#u~*-o*M1bC}niX_x90KgR9fO>!sU+%IOcXWe5|fiaOvg$e0Ba9fzh5OT`YgTI0!w ztOuUrZoeC@37)WPwp}h87H0p##-{uDwYz4Cf^rQ;a{zst=!YfwqFo|bnoU{lg?!L_ zmEUxZR7rq=rJ|HpgKYA%?U+n?T}+DT=@EzcJ?i3K)-}=9VEGy6L3abw**K6ZsZnlz zrczXt3x~JqCVE$KokNnCLptTO;>%~BX&+j=9pWu5TY8#ZZrn1&YanSrH|)};@y5{N zW3+6An~$D+dx2sfPh=77!Rqo^SPrF`RZ|*^`t|n!0C6mc$5qXGIz|W6K1w!(fCna9 z>*PeZd&j{&D4~5r16aXY8$bqz(#4OmvRC1y#o3)$@-_7d#X~pa6a7AaBD+8LiE{6W z2k`X0J>}QyKpPXa*$RB`g_g7tr42QEx!Tr4l6lwBc+>VJ;CV^R0uL2s%@9w9Y?QA^ zH>G5oWJ^nszhav*kN(gtrDt z^%C9bwp=T0MoCGd+TWK?O-t5NTa)f{9#NqiOZwo*Wo zNgvWp-sQ+cpy@`X8y(-C6+^Qva1^49*0PUFxnhex9!SDoB&<^8h{`TRZ@cdJ!PZca zoQu`q;cDhGX|C{njuqRELhJz@%m=Rn^v5P<&y@T7b7M+(>8Vn= zMB^5?ZZ1dhHDkq}xnSijjW!y=PMB5`Tvl(3w(Uu*fy>{Vz2tVEteyH=@I^PZM0)Vm zv1-leO>tD0RT4pS*9nNDw#tdn7v}PZ3d|~IwWp1w{tchUYi?tdH4D+e>nd+c9}id6lhkJN(`ju}=%2vx z(}bSdt?Gw~Xh%O8Oc+DmXUtuxaC#2y;Yd2j!akG}abB1(n-l5m3?fbFG+K$OJj;J4 zm6BxhenCb&I?#A(V}$9Wymu~t03om9nsFBjd|kN|(|19fj~kT&ib0pdolK|EE?v_x zVPIn($ZtG9bR=thY%f+Y)4x0My&^af#v}9wHa|hS0T+k8f8q@9MPH?$aMPxG`AmbkENzM0M`iL56`*O~SkbFH(K+X4yfyxlD>ck3c31 zw&eKWuak@~VB*aB-BoxVfOF=~7jDTGWI4cG3Wkx{zh?{s5f&#XNGu{3=FB6Leeq z9buJfR6nmwNkJ3ktEegNzOwS!g0Dev#j#ZO5}OG*`$&V37hGx@N~&QNv3c)Mbq~3V zUw&lS=YmfPPA#~NyvQcs~JH|8_diA&4~+Ltj>+!jK3Sfa?=|Pg*-R5 zBXm(D0JW>@O|=?9OzLtmZC_l}Qcci%-F34{+2(}e9c?MD;>CyY^|4*y>0#lle1$lZ zlcb3i6x}n1OpBUpWXdjn1!2_M`f>L#E9%{>)6Dme7fCwiHm5~QxsOGbGF~hUbqfq} zIlR}VvfU9Fj>AUpD8t;W0YkmZ_!f0a-ROPvK;uUw>i50^0G9mg9J>#mEgmu2q^TKA z?`)A2KXc<86AfAag(+`1BcjDnO~g=^%#>}1Ff+LO_)VEm7X>W?Nt&w{&YAX5pp70@ zvIp0ECNB-eC_lcWG;?`c=zKE$hn#)rvlnA@DUUL+Cn(?MH2jAqum9|_D9lM1mHNv( z)e$>K8k#Dn(mJ!;tyPYYNZ?S5+}#4*5POII?q8IQr^Lgeg#&Y9CQLC)EWZKjt-n}Q zq8?p9zX1XTE|#2d4q|Yfxzk9-Ie3Md445Y);>QS_beju4H5ydV+-~y=O8NZQXB|Wp zA*H|9Dl_!n*<+ZZf^k&aci|%kwD~+(PeXOtY{^Ct%JQgljrVf=qu%YI`@z( zc2jKW8dO_1`Jt>DU=xgodCxVd6SWRw29mzOUs#3xz)!CGVgRM5#1t@b^2Fzo(KaatL^BbkC@qN)@puvUF)w~yNr0qkh1)HlakK?5UAx-X(_cnx*KAxR zavY?%9`((CUZel?IpsE?KDk7=m@%MKQ`%~2!V`Wv;<)DK66w;D-_3e9jbH3V_tmP* z=&63o;e5g2oy0xfjnYL>z^yqm9rqkoJ>W2jP1&`vl=VP%V@JKGf^lF2E?L&(mbqZV z0lKZRNJF@R+9Xx@*4mkLuY1ZxHcFm50AOM;x`^B{rm;Peb6DQReY4errKr3RC-!Sz zV%wCAx^m_F+Bs2-LO~Y?ARLC_I>I3z z&bEq0<29JQ>RwKh`R7t&&e${Jh&RUSLGG|}JK+EPoL>vfzZ z*2mTU7=mzxh1R0#i2T<(G9;halpczd4r|msE9RmUSjX+Ih%9?sn+0YZjJ+sdaSPuR zX*8uxc^gudfq1N`{+DC^oyQ6UY zUMAiMXu-i}X5$I1C4@Yaj;0aRVQIyNAkWVM&yrjBL**R#@E3y@dFBSu=kr%`IVqV4askOP?SzM8diI%y&P8DaV^7mD>ptHCrciJjyA`-z zTdc_=u8M4HE?k)o)OZ3#TfWc7wDdIhD_xW=e4&V5iJTdk5tB!n2J^XuS`htF%Pqy1 zDB!eF3;0;)OfL;Rm23ogbxLFpuNu~JqC+f6#E|p-k_6xJ;dF7c=Q{&rZE;ffa?o84 zkeRXkUl52L$OaM6C^Fl!V)J9E%hOgcyzg>MFiO=rsjJyyOaRh7Wm-&BgL*5nZ`*crEtVa+gla)>(9|+)Mux*4x9^F z(%l8IzisB(|&CdyR)Z?v&)%0^aFVTb&5D5O$TTdY^uTdWn{LSAlYT&|?^x_U>=srj_QXL4z>f*?cGPkZ_MfP3TI`M>4~>9>`^H{5p1JVrAZ0&Bn5Y z2x!-?nWXo9{L-ZSwhiTQquYv-652yl<`ictO-h-PobeKOjNbq-$Ld4l@{@pH?1F1B z3EY()>(VXbyK}_hhi4l2b`{K}L+d_o8ZfghAPn_AyIpBK9r>gcusufq zEe7a@VS$`vNj)?_9X_EhVPmE^dri^kx~lIky40@izS30(6z%SJCi;28KP&u zJkOuslxQKvJ_`q~FK(E@Y|l_jED~*TWT@RGfeaiKW73L}XixBT4rSp^bYn?+Rp>#} z-QgQ@ahbz>y;$!SVu*e8q+IuidMFclR@VnrWUIRJ(>r%fcZ5!kCp4i6l-C}f5^D5h zufiKn%KC`{D33CfarpWpKhRSZFiq-s-9|RBjQ$3URrhJihc;cCvhdIh%7*cQvE*Xd z*W~*WT=BfWz}=W4g@EZ(&zWb3q#e?$jpn80n4+WS4O69t2h0@kKT$t1j2Jz673r@0 z)#2?% z8b{ab4URXo+9p(xW;Q+|$b-ty?Ztt*OC@COR=Md_m_58S0lPF`cBR+waXr&ZZ4lbPdm_r8a+_a!`` zHKeR zuniLg&mGq2t#wMv`gz9a$9D2r;p+3_R_4=<%3-9yPqe-|I7Ak;sIV(!C_xMd15ksS zfZH6fBceLl`eb)(1obY;_A7u9dfGI2c~xgXFL8Vz?1Xu1PBt?)L@z?0Kj6U#g3z%S zR-8{rmL5G$rmCX%no;vzlY^yPo1hC$ja%iNM{C+#>7}QkA8$q;n(%3cGxegopxu7p zd^G&!P&FNDTnhgs%;b8Gy^ArMpE)_*T^!A2LqC6$IbiyzKoo(jZ1|f#!Qw!p666J#aL5O(ZkX=E$$5P4eCY z;o_Dm2Hk>+9Z8Y&FE&RqN?7;Jo~94>NZOX>ND1|%L{@4<_^qd051+QWZ^n+I`S_n1 z@Bh$exAc9$sI%`JV(^fUB{^+7T3Vr1HzP>U-gHGQ-dg}^6c`CjrZ0UtC6va{TV@_7 zYmet7SC%oW+oDf*Rt$Z_{TLKO!{(4hThUfEADliXCZ29h92YUGxkolyNj+cLRkX5W zx|Zg;IoF9l9h>wZwYFBHviS}d4t$DfFtK1d%xS=R4X_uKch=Hf)k?&b}&D)Wuor02)UoGXW z&bi}9I`UyB*4GZ7#wvGP zt-J4GxamXa47>~`p0rrt!Ylk8`Af=FWSYsznOkhhc}HuIX*RO24ebH|l+(DCMje)> zi{+Kv4>>&Ss&_Tu+$kMMR$}u9?)=ZdK&phKMBr-$|v&KV0*Dv@MRjr4V$0vX# zNu)2-7rIN%|%9&Ja4eRXvGyw8`Yr_ zqTZouQzZ4&@bK|cX}PZAqXkEjkmUD8)AUqj`m>r1Zi|Lb6NvZmGg@M= z3jp}FPIYDrx6MB?Uo$Djv%?Mxu<^3oa!+PTP4qu!UA8cGdz!h7^Df;bJuS!yL;i93 zS)kJ-mjVvmQ#Ry#-G5+v4fKqI&Tr3no{`l+x<3O@eO_V?d6*y*N}KJaTpWoZZQ>_9 z36$KA$Y%oU9G=-lQPa8pG@J78-*9BE=ABTUEuJeOd@kZN0sPp4q34XXMW2`#`5ZV- z$>z^2VTtx<#R)1ZLY>3I#mPXK;+-R9vA{9KemHd*MMrJ_o#9LG#JzQhhi9}8H0j=W zcgC&NR!K*)TY(o#s4mXc12eBz)4pka{@PT`-<(LGZmc0OXbmDe@aR4j1lFbpk)(r%A; zFutBCdz23Z*J`n(5a_&z({c{UCh^6FaY@}fi|xjqlE8&H*)J?i%jyDcvJ`9`Q!oml z#RY!(wiB8jSPA`097mOFZq$VtsH`Mn3m^;Ny>6dw2ncoA}bci!pL+#c{)dL4Oq8?{}c=jp5bZvg8cbwH^gwlG!5+v!OJ z0dgNoF#s5{-s`z_t0`p@0{#a0s$-2pLyXRxcf$F_K+U|Gd(5)0PQGRzBS6B2a)EF( z+9g^TOEFa1MkZH=U#f-!yOw%E!=hH=DG$;rX;ro1hphz;FprFVFy9}u#E8(H!xt3E zoG_C$ei}3`l~wr$Vfm@z#k%w_ws@MV;}68VHX~EAugQsrkZXIBi@aJ<%n%rK?n^7J zNS6rR?T0fy?le^juHEyO26BumS3FGrgvN=F^>%zD;Y;^S78q9ByjO(bA)DvwEYY$t zTU+8?W>Vz=QBhDLO(r*Oi=beH4QK=Dvd$)laxjWT#8JqrQ$#H+#M#m;Z`_>dpOP%~)9xDmLMF6IMNS8mYWNZ{$#PJBTIMl=Nd=mHgS#9g zXk8a(^|%6+_mlG^jDhJ>Ia?brLs36!9Q{LNy(Sg0MS{6TNs(<5uV|2BqYo-Wo~^@B zx4US4_IA7rtb|Ez5)Ajcm2)odGi@bV>WUP!ixM^p_$prNdQP8?4 zM?a4a4z=>yJ;Ns=mHv=QV*(P>1#u%wLT}W24FFVU!Jws+p$Ui8PkHR!oh6TDMT?Bh zC&7U_CRz+^=?&K76-+kV3u^4Z2t&KP*Rv<*AKYJuX@Qf7bFe3kG6!?$jmq9iBgoEY z^Q&$SnRu>a2!gFa1x3LzYG3-6HRtJax~)5lM9jND_vK<}KPDK6T24szO8C%?$L*$q zdHq-)&Kb3b54?Q!FXuV_-#ez8ZG!|gjFSj0t(7iJlxU6Q{vKBMTX^r`a{P;y#Wk_^ zpC9aMN=5tT3$xzs@~n8rA(kAv8ag1Y`D8LE9~*7&w?g zCq6NlCbVSy{l{dYfdqihyn@mtDS)?1*p9J#w)|__j3ZFU+>3mgi(4qTS% zFVZ106Qfmp3UkP8B-v@Sp|j};F9?s^Xo4SrJChTJ5h1q=%$5yoRBgG1xaqMmR=BFi zwN*b^bd0XOib;+j93P)I%Ktnr%OcTc5aU;DBX{rN+GwDMXe)AYKW1$Ds{rk_5rs~c z)vN``>YE8jHM1BX5<~)_B7HlZtEb_ag%7Z#Snm7$TYK#J&N6iv zZDnYOaa95LasC7y%fD*w5MC??jyj-5_EBbN)pCU4&2kLYAwO=3sG1L z0{JhXz3MNF@G?7ODMn}~n2gq%7q+B!cka?Cy(06W&7PkqZcTV3v1RBJD?X}&#x)GW zCLHQx4+%1O9H2+lB1nG6J;rj4Fq5o)Pb7NMl|f0dxsWUJllimAca(AWQ1V0o0AsaJ zA&UMNaqcti<-sm1H2bQsw6MGiI~;`=KANG4}wlcTZ88Ji3ui6D>=;@7?R?B2Bd z@4mPDzk09UstVP|OjmbL&uDtS?w)Q4PgW(2v1!D6k50ppe*9#S9|^842t0bW=={Rr zu< z^M?lvH@!^43O+yMPAHs0gVZORSgUsGC%+;peoY13+nDcpjV|nMloZ#0((~*Y^G;B6 ztFgzIRojc}KY%eg{4QPk<4!k9^9HN4E8Td!+1co4ChCMJ2$_;6<=W}S$&=4t4bmOE z=?dKD&@K!IJ-avNi}?;M$~8BGm?z^;A#9JPC8k$ZYb|2Gc}e!zNAK{cmN9thx)VGn zkTtx1q4yc>*k3et3s2v2Xm*tG?0nx1dC5w9`yvub-iZ3NB|*;7P_H#G^N8lXuzHO4 z)b*mV=8yuzrj1WKA_3lWUY*T-%Le6PYsfpea!UZeX1PR)mm%7X;wp_ldquOKJKwkz zt&Tjcy+P(J)A!TGs{)f>Hk3bo*>W{YcWP|Y319fEhZbhIlm7dRwZNxhFD-sUnft#B z@n|LEHjA$*QjlFqBgGzLa6+v##4TUIo^dXjxES{J(zl8mmt-9bErdBTve#Z@yT1%8G^RoZ&uqm zx|_G=R7aEwmwowVh0boUF<{q8ghM$&b9wE4MFiqEHYFuhCJ*A@8!I6#I}pFgEnX*@ zIFIRdaqD<1x`&)yJ1Pom=eLz??vh)f2OEIS;vd@@YF#tZO!-BUR!3Jnv0HYJb>ro( zriw-y>jq5v(4tdac{)V9KIS;RitOlmRtn{^81dkc|#bBx~i8 zZ0w%>c?kIPuOByIIKF`U#Qo_hTtUJ$2-MD>ltf`%lCi z8D^f9cn*G0$@1PID%hJ@QdBdWSsSvdZ1s`uUjC!9{zOu&rsWX*4#Ge@dF?^Q>|g_1 z6IuD9&Amc==sEM_8z(Q@TvG74kiM}w85_eFHSk7{0inPoWPK+WU7=(3P&74op!xc9 z_jO3kqeDJ@(VoTHSG9O2qiWMvShD(nTi9n7oIk|9_4@^W+taYru%jK`bzLqV z?8FsnqL;1{pJDd%>#C`H4Mb?;5%+=Z>db1ZSKT`7<*x90cckz$lCe{R$;}ha{o3pY zl-%uXrYFCw&++iyMx!f^$Nk|*1qOG6GyG}?SG~>R^Qh68kEJa`sX`Tq^;r%Ju*$}7 zp`12v`6WJK2npG9_%uP(7WO__ZO$O{&=?U^upmRsnf`q5DptoxPhAM&F zfZ+jG9;SteWwr6?%5Gsz&NoD5#|Kj>OiH&#T13ayMp#BA7o}XHrd6fVZ6tTi$0X!7 zoIV;~>2kB5_HqT;Z(vQs8E{fnl5=sE7IID^7E6xX<#W-aLfj)fyYl2>^J8YK$rD<1 zr9--j7VC*t9F{s?bK=5GA$Q>i_5~Z-d%?{uuUxX=_PyFV!lBQ+1UV(TdjLwT{C93^ zc6J`9zmDyB7iTo56F0ZnyRCgL(7&U5{cffsN)#FT;NA`CHBU8TgB;7IoSzte?&Iru zCE1mthH{-jF1D|f*Afds8`y6KvzBFbBV0naO($gQ+DtV}m9Fbb$jf%Ueb!1wCVm$S zkb5e*JK+L3WWKg4Z{Pf8AXcLS!`Q-@RB*`0z*L=S3r!p1mp-viSn$^N^xz zq(Fld*6U=p$xBvAc<$npoRovEBokR1uUb_l_8?*0b z9Z)jdnOxhc?A#=~ru-v+{aX4@sb5(}T z4CkKvQng*%U`}WLl5EI~p_)%b4$ll-`N`ZTwNX|sb)H$Sn-TD(Dl)zge`5B|aB&k; zpEE!`Tjs@n>~Ox_tWO}9h_2J!C3E$v1NOvtd03dGUYlS?B74!-hZ~{niol47x3tDG z+c!qE^5Ukg7(_C&TBaMbYrR>`mT^n$rvfCCPnR!eIAU7QhOQtKGQIavT_L7FX2nr0 z!yt)Gm`w3EvMatPH`s9Gz5VVRn_5Rr$02Ba$Sx=NUS5`?sh4s;y{XjUv%vx5LIyS6 z0+ghAj%G~1T*S~7i(LWdBNbokN-KsMc-Dt`$*fQoH=)1+lvn+iUXVGMqrRv_c)ohE zZbH18gGD1IPdy?ziH-HyFQC7j7nsn>P#k!}4a1 zd@rghS!c8PD~epZy&liI`4jO+n*gc4O^UL zfOA_(by{=G&Jc}1?axGjIkJo@+|Z8E4_7k!k|C^WqF`3z@FvQ){BQquz<+*5`9V_x zKCTS;eitQY_g;*Pw8N=a#}=L5@0@hq;h@rcpCpwf$eQnLz8b>v%h8r=hq_)atqqKV zF>YaUsX6^1SAfoLv?(gs7!%87n3Q=EzHx=7y?=j{{ zZ?|y}zP}Qh2*Cc{`RiPj*9kur`Okec#&597OJLzEUM{*Y^29vVvYjTjN->u@ljn@U zi_UMzza;xLMkm}C3Ns7*wURpsQmSx4&QB3d7)0TMn7^Ie?yqXB-OV{XpEujgeP53X z2?xUa{0D#O9sCK_C1#~uk`+g2XL5z>VB9M^WiH7kKHhJV zh;5I0JpS|17Oi!}HcClv6?RE>R*{eD;}IBqHk6+W^Z^*AZ;gB^hw=yfN_3E2uf(OesE#$r;Km_Yfa1KU#&tzDMbNT@PGp z!2J>wdVnei9-Kro%M|_i7nsL?gCYD|J?%-&C0U3G?#txHVbXV(Vt=(>z^sNKF%wQ~ zh>;Kd)J!Z)`hlk2x+L?h{7J&W|0g=SKc+E+yQ+et$@}=BFLV5%UKvKP49@J`$SF{u z_bL<+tauu3o;#qUB&QPpnq}(0Q&%D>TR9Dopu!S*^{JA z0L|Jw?ltjcJTSAX`(pc&tfWt#YdjY|6Bq*q}I$LC6Hq^eB`=`AdgN)twNNx58_B<8+T17PTGWmY%ZOqpzz;d1&)mS&s9=%lmR+%}z) zZGVm1J%g8IX%C=90`~Y^7HLR34d8-z>SvYph2F>e4S?jF=s=ak4ovkW*{*Bu)=)OF zgq`hJDCEKp)!`I?Awj^;%CG?dqNwb-Mo)VfDI51zKgr6S`~slx2r#KZ;9MGss{>>a zjQrVV?Zl2HF3AQ-Ntkbwe~e*9Gm~W4g#Qh#j~nT>ua+xV0V()Hk4dGNP6nRgAAKQ` zh~hJ$%rm4M^85Gyf`n`JpbTOzN$K$-s4jBjO3tNgVx2b!P4O zhVkOuw>X-Lt#jruU^*S)F_%?w^m+Ha>$aqy=hCrKO}zwt^WJpx!~yt>G4fQp#rWW2 z)VWPCw2GjuLl}5-=sCEh9>vD_Nb?)TpKuxU!N-Lwc)eg?o%UdTbiDHVFy1xC-#km8&i~Q&>Pu<~m!b!{sb5L^g zsuiele0;5^*{^2yAcgj`?NSFqyIqkmefDs66 zVY3uvUopJQ-v%sIiWIaz78DqVm zX2+uxE%eiQ=SpRgjJ{aiN|AM7jP)y8P)=-X8S)P(Y(mlV&H$s?4(HYs%t<25&s65qH#u)8B0{-Dz+! z`bch4dn(M2t??}j$dKwoF6hR(Ap|nOC56by3S<~1tXajmiqcpKNTVyo)nS94pFe@( zGphD$zJ{Ey#OQq2radA3tb(U;)eQ!@{W@yxHP~Ehr-`${sh%AtdDJ`e4Mpz@fPd8k zAPTi~d~LJn4u0*D?8{ET^mY=CdrM-{_f)(M6jVrX+`%A%&R!kshhDgmqENB&5KlEi z@^L0wE_4TiZ%g-%h0|-2~U6{-{eC_B_L~0;D=byR%UOO?m!L{fCx4Nu`nLl$-OE>`>9u)WRK5(a!+` z=rS8QqD&AS2?!qExnBZE%t;EgubKaL;(}NE!EDcDOepy0{;kJ7!KH5TRa;I0GkzC` zr*Rd+7lOVpeoNG8Tf1)pNf@n!=u5J_BWQVqbUsntPwOOS$z5uqa!aNnXc#|scA&6X zdT(QmNG@3YM}KbqIbB7$x_ocZNwXa2c0*8uFyPxMT!U2Gq)-urU{>;Rk>erlZmlS^ zB9k7JgZi|eSgy0wl(zl-IDazNZr7UtVL3JqJE{o?$wA0zyHE$R%SB*?+f3n0-AK>i zz!ope-aOg)>HdMQ43|84=2AlkumyiEA9b+k<&uyzE}gZ=iB}D}7=jyt3Y^Q&#b4%j z25(m0+pxpkl2a%dUUtb3-<9uCD5Z~XLh~C0@6S~?SW?*IgAUCG8-~vO@$L5)TH5~s zTicMgkzhe#@wwPfXvejGz*Z;U!;8cxD*Ns0ei%Wu8EtiGDWP%gzw*nYLRy|)fXJ;+ zZU#PlMIi0^PcY-_7>QAZlRYcH%0R(7@|mIsHw^#|fvjRYBVoHp)J6$!x-GJN~Kgrl5D&O5r`w6|9J0mfZ_xrADYgZ=Yc8U!>-H zD!5>X5;oJ>8Pp=xT~ca{=lN@=^?6PkUz5(5-~H;${zA`T^Gr8OL)zOFoi$!=gLK6m z=^wn=GPxrrFqxsZuU7j#l&u-@Sqkc|eKr>9bW)etYrD1f(4eH-^0ttTDcii_vWqi< z2f1C^xHi@m%Ka+9%w=oIu`s&QF5{An=aIt@NCQXn?xUI>z4#+GwbRpK6$gQQl9puI ze;O>9=CBjgzLK@e*Dr3j7!@^r_B*2Jopofy@tK~IpJ00iopkxayNokW@1D}4AKwbE z|I+w>RvjEF+Sw>7+u129D$Ng#j4LWy)`$S!zN0ksP@FJMWc5Oxy+^Y0kTSOo8~Rhq zf^DYafI{_OXCv=$&$u&=``Gl%CEXSa^&S2yV9ht0&mR*wg+PSy?&4l3wrpf%1s@95 zD2cQ61zcSD)V{HsKWl>M+gJmpcMrrSK3xxwh1by^O(f5s&1uDH=~i2~sb}QP>8VaI zw!3cKSYWPU;OA=`&I)ZYghzgjb9j{-99F{SspPmXmMDE3>y^=~RuQW2ThYW=ZbS$C zBJJWTax4CB{tv37XvspbVUKHq`AiG9vIg5xhToQ$WK9ICX`=2X6)XEkb+N|8Hy6xd zn_PJi1-9i^HiOgg^^=xsnfGDFpvuxaXzK~7L+zqLQVC->urE|>FL+Bsh`m+z*vIei zP(2MS#w*UghLv$wvS*KKX)aCOu0XD8(YKTYtYEBTDa|#sUf+}Ysq@*zF-Bb@oOrQC zBhZSv@GN%P*+jpz28*@OR^z!+-uJXEd5)BA2zDR~(}+pZO0aT&qF^em|&5~ua?7tAM2 z!`78T`5sAo%u}fOLhwcCPUYfV&}QCW;U0tj77q09!u>tI|18{pH{JgbUoGm>pCv;I z^W*=gA%~$zgZ})j!S^RP!JR)#(Uf!=R{v+v%1g3da}dF1i0jaTnSq=kD1qL3$2JT~edDBU8Zd1+ zaPgy?7zL=%QH9o&R}zItM+c36g|iO5B%=!dHvxt10Gj^__uqt1j!LqoC!N2f$m4qE zL2(ORT{-6I9_{&5T8YCr^X5kfAzr-nG#!1pSNBeP^y-hQGVghJUa|gDnp^3k_NuU^ z#|zD~3;F}IcT30i>abZ8=fwqaU-2#&LGk!!dFU-krK~(Qt*_(><`Z%hgP%b|wMVPw zR>kU(zi6meoxt185?;G1{}^{?`sLUOZWA%YhIvTxr$;o|)#O=%OpWYkdJ%5x(OUk- zS~Q*#vRuvN1$?3~myNuk$>_xKVck-P#3Deod6@K!n8B2RL2GtIbg8}qjYZs6XzhuC zDbA=gYj3vG3a3WJ%l2Hd=|uL0eiTMVi%CbhZ#w3?IJ{7|yyb>b(PM1OLpE*Mcqyl; zrqkD0H|}Z~8IgK8?c>VCn?FsC#PTMLjSZ~Y;AuU3dHKbw=>y2U{Jz-@u0p)rsVZc0 zObtX^M^R%ZLbca3Cg+_Hy;efQ-Yc!*!pqvyc8xyP9+apeRvJUYp{kcqTXN?` zEbohm(fkrl8`7VmgPvwgOiV;yU*BNk5jtbN$!yiA30dxL5f$eM^Dr>5d|lj{LYpDT zA;&%?HmoA1JM6}mv5w@mn9$PI)lWnei5jey43qc0``>3F`>UR~Cb~d}yN7A>r1~kp z5M=Rs!eK6LuYHgd@Zvj!1MUdPh$jiLB6x?(qU0UbEZZ0ocus zze@Gm>;VSrN*6>tN|CF9eB8#GW&~$k+}#r3H*(#OcJNalpOH*v`~02d*TK70c0qhu z6#;EKt-~an0rzLeqyxf=<0Bm$8FLCG&P?@;w%YKLETJRY<>$pip<}O$`=4)RcAqdFl9^7mC~sNtQFPBg9f4VJn7Pth;KR{C5U(TSZiA)W;;&r%mTd>^nlnDXCZ ze;O*GL2YQZ#pak)$B0Fc-s7@Tbp2@_6mD68_nK8_OJ?Kzb@eU3suveLt|+3OIIzL< zGw<8WL(g#t)GEcwmkk6?*{{#_$I`evtCfK}0>##>P(h1(Jsc9E}tdHP|u0q>$Ev0Z`W$QDjvVbC$jCyyK2~ z?=0R+DxUVW3Trrb+}g4qz?`>q?EhA9|B?6P@T?5I=XG9cH z95!Bwm1p6@+={2FbBAG}bg<%>QRUxszWrHLH_TkBUDrhXJ4+twSC&Eu=$p%hSK`4w z1ysJnrO;<^CQ|l58?zcFPN&YsNXNv^&z1CQzJ{t(-)DUYnjG9)b7FU%z5=;9pT_ny zux>4h-^?ht@|loe^C&;fKOHhG;!Db781eRu$T&2X@+B}%(4(#(1K{&1EI93ShH6XC zQ!S3^*xuBlhc=*RvFh^OM|Z}hYLBG5#GATi|mf$jazj5jRnHANSS5JwR`I5 zbFXqn_$jfz{PO_*Pkr5cCmnbo-*5++w@?hGh9@DNBzMiNd0|CVV@tqgP z8;LN{L{2$Ctx35d*xc}kkA9JJCd7^(I6a)$xcR0o2j7%cZc0;a$7xl{S!8A>P~P3O z>fzQFM_lrgq8!wsF0(!GgB+3~;{VOhbq?vbZ(fwX(g*I5T;22hNha{!qr1-K*XQWg z9QjK6Cn+4~)ap$`4C?g)g!BduIS2GzBzU%5Y1oDXMUQ37CG-|2cG|={b1LHNlJbBw zWkbJB@)l-1rH@+N>WN+Ey7#ETyvuP^Lpu_Jc%`n%aSs6VfY9GVe1B$xY{w0O_#vVM*30J3gfjR9Gh z#e1_2t=~1n2K##8$m%oXG`WeD19X6k7QpC=cDxj&{I#aeFqw%8ZCBn{!h5a{Eh5fa zPTpCTbr#FOa8SzpirC2dgW(c+1n{BZR+Rl5&MyBq&jL#B>q-dAiaLSW@)1?8RB`ld znd6k}Qo9{GX;F_T;ZhZMm=T4#T_k!Q-IsLrTNc?fiOCy~Jtp%U2lvTy9jhNSQ`2$3 z8&SL&8e{EY8Obzuw{%Dm7UPfMv>8x%sA?wXx^Kk`M2dX{ z^B{^M^>amN0}q8TdvZHUV080_7>#a#YRO1?xJ%p=saCN;-03;LeQs|jb8qg5#$o(P zDx)vq81?j$%;ap>SLZ}^A6h->O9=Sa)|HWs0-OrIx7Tq1id6BxNUa%J`SCA}kD+pc z1As|+8B6^OJ(;DQx*RC;jXxSCk8oQ-y2L8X>|yRUZ1IxJw(RKa>|a{{pdSBsOnv#I zHBOf32TF#PWn|0X7*HbG)(&OX;tO;30zLfscDtr4GvZx?E)IO8^jm3zA^PC5-Gb*S z>ytvunz3uspaeKmsEVJ6y3SaEEtW)_t`@O5EbnyGrOyp zm7xk>L^J~2?A#QfF=(K(`b^v6+x81f#8>g&(~|<}_>BOr5RxV6BkE=c(Uqz$#QZ5jZ8iuc^?+Pj5M4E{{hBiH46>rTCfs4ti6DXHN#-1 zd`k`_%em3Fr>L$nib2A=Nhh4nF~bfFElw!H-@|HEIe>z+R~c%{1!{fDxz6w`q1G8GJN+uhQ$9i= z_Ru2Qn4ABHgoRtm&o^_Sk9qma)5_}WXRQaHWb08VqvK>&T=mqHX^~p2tYsNqe9aXR zvFkC~W~{7!gLDjLYWYi~OGq9n0>o{Bh=>f%^MG5#|63#Y8~IXw^_{45HL?dmpy@oz72x_9x7_Ih7TO>VAAy0Fzmq$@0r zZa#5C@L)G%COl3f<@B9^{=kQ`g?gM*S}(GqxoaCkWJ4tDlk*G4#eY&t&W`OT0MESz zwuD7sx@O4e*&MteYBmFL(a~ZNujp=U0Q3OT$k6KCkDd)@eWFSBaLmKW!dl7UqNMrA z_^~7TxEWe>#`ncaKAiWPq_~uI;w*v^N4LM z$iX@?1M8xCZ0!lU3NAsOQ3PkjI%c)SD!KjH!6x?73>QrZe%K!pXeNHSC6Lie7Q5 ztYE%qqQ3W|KG43V)pngtwvA=azFdI$*9l57%#oqaYza-ckno3pRxbaIEu`vkMS{#9 z_b&FjE7Zt}UgGQdEZPrcb~!f1y;b-!x;E`tg4p>ZYtm92S!K!_yJqop-#|L=bt>yT zXsdLcyr%0X&U_kUv*Tp5>!o4?#0B_@=bfZrgNRLskQ^_c)SL~2I|ql&Rjrea_V8ZW&a0q3Y0)+kj+Wo%Prlw*}<_hQWKFM-$Po!|bu zW4&Irpw@UnuHm8sX`H|Aco5t0&`wvMidW5w$x`j!I^7VMwH8kEeLl!_LTAleIqMDDgbj${?<)CiU-iG#>U;CeA|ilPV0( z`IL2Zw~pQCj~d*a!n#jo*kp=^c4`w=AcJfvhcmqcy)D#WV;;`Rp9*qZrCB(3PnsNK z-VLE2lDNUthgLaQ25aGqoiI=eptu$pQo z@&Ltj47HOecF*RT+;{HtvCFM-o$CzeMAsLW+tufZ)en`0iw`@zWVU)<6%UXb5% zFZ+xu(v-H{@BUnz{gGxKpn^#a>a$incsz1`RtAUg?yH?i$k_>U%-tq#{psmfFTNT|vT{T**s$PV?eMJ1VB0n&mxndUKdWgV*XY zt!iqipCQ*98b|bkG%aj=E@U(PQdi6tCXD(le4Cb;6{w4ZXeO!)HU#S7dUHs9u(>u1 zFMCEpEi4~%w@-7U4mn-x4x?2@k$g3>H55Z3U;WL>qgA9RJseNI8&VGncbJm{1cRl9 z?i^P;B1p#f?{MLb&3f@Kg2B>5P{?|hPQc!S4uEj?#h{f#~ z+<9AyzI6)Sm?Q7^28S++hexN!ttX8Xo;n&Dwq!LqjzCj$uP{gPaRij{h(TN9Gx;vb z+7`N?(FDYMu`IY7pmB~TyPcH(wD$)OxEb4*-Tnwl9!`|X8Lfz`d|yv;uQnkE=5e`F zGp_|Pmt=i6C(j-&1a5ACXy1WWFkIn#>@Dau!37V%w$d4NB^UjjpLfmCHYgs}E5NjS zf)?HKU)grri zPDa3?4e@SiVf%fTGtsjkaS{UE%1-H`FViEz7Z;@-Cp{nIvkQmyg{LK5jd^%}kBO%# zjX7RP)Zqq)%||P@=0SWPBq2F?tFuX2V-B*6IK~Vd2~UeZiIom&VK*di zS_Z2?iAV}9&=(p!EP7TetoGJAvg^}4lu0RCe6#dzs;=#08P`V{;Y@BXnC)bAR2>SF z;nDpC4OuQ7imw5;U=Jz`4LACA=_fAGx^1MugX|19fjnn4rP$*7nv%9(URH&6z{z)7 ztpK@#mmFMV_gv+YZ*al#{oGW?P9E|r4@v1(2@SiA+Z8rZ&6Ed5s5-vdIHgGVo|yl| zAcIfkR_iO3)vU^qSh$*+qA|2UdXF}uH%yKBo|OetlnBeHba5_c#T;QFwEx#f04 z$BE+Z2EyI&Oo~;o!!vlpOWxOgy;wI>Y?vdFRnH(eVc*_{U#`ujqG#+r`$&_36x@n( zcCgK!J!N*+x`1A#$gg}wEkB9ZP|Q-TGq!KPJV0AfalQ1m>t1(jTeUztlec~nbh2bc z=|vQMlh@yGUjNPiU8&koYo*EZk83c^gqbPDeHr1;=L843s3LmUx)J3uTW6~MLIURf z*$(m?FyHNQW#t+*|C;%Qa9gIZx)dXk_{<^Gq=*IY1^vg9dhfZA2(Iy+`lH!cV=*e* z{f3lbmyt@(`wpjAVj&B=-_+-yJiQ%22|9OHoS;ccM4YADgqK{Lp)&G7SJc4KVh2I~ z;xRIEc}?cUZx^TuOMuI9yNhvZA1lpc&RF9fStkmxSGRK; z?)#rwTbo7nN^6;J5`+EdyN)CExie?)z*&2~HO_nb`QTW?{2wOX+|gn`>VGgVX%+X{ ztVg*kpwfTB#@brBKbahMr3T|2?cjRpJvlio-Vy8Z`%4=^r6g}9r}&D-4J9{->OtnG%9O{GY~OMvW90{9 z2dthq&4dGwT@-*^z^(gXdVF>2Cx?yRlgq<^Hg2(A!k5g||VRy0ij<6j@zZ!v9^B9X41x5KqtuYIsvch79U*Xbz zrMWQ#-2Fa>)K%%mvL4nr7u3pLg4{O-t*F_U3R-&}Ysb;f`CLZazESE#rV&ryr)jvh ztZp}zW^esNu{ig%aoEWIDc!DfoZMF#{3jZWGmIpatL)OQMu@o2a!KY`3vjMNMJOj7_Z&yBdD7u^*U(58cGp9#xN=v|LbWvDV=_NL3ADf*LgY%_!i#xc9|L5qJTv+ zoQ24zEy4nP1lwFL_yYNWq?fO+%Cw93$<@cmlo$G=-AfkJJpX9pm^CA&WEDI2r zcX2b|ZwIEZ6}v^-`~IACHEFbWwEKH5;ph1-^QOY;Z?5F$z>nviv4j`Qe_d|!sRA*V zWEK7OLe~L^vR9{E~M=PB}+@3#}$h4v#Q<4?d5EeICt+|#L;H=yhb?i<#qyl*BvG%Qp zIj{LqD|W=9g;V;3xHeOekSewQehjSxzV$Lk@}qGlyP-X#3>LMyILT|d-dAqNsq&Fr zJgsBDuCz1_PzjEhA7Mss(brbL?AKWX{l8N6(B3|zea4>u|=ps-l zUf0iS@G3M5^s-`lv#w8#PlQu`Y?O+v&!J&DFdDM3{@8Y$I#zbDujAhRT9O&Re);aV z+Na4$!oorl?(3Gl-CKZZu04;^8FnZ`Thcs`M(WFZkU$cdzGe#=SpzKs-8-N z1OTy%{pSKv=BKFk*;$Y1^>jc6X_t$@D4w1WBLgnUzTMx@SnI{K%=`&&{EBxKsRntk z{io)q`?;C*Vz+`4k4Q0)aJnadkcZ801vC;R{5f`3;Oh4V3rQ;T-&sgTy78UEpgKzI@DLZrV#B15-RV+c~0j6CY?T8JG2Uh>6>-dpQW3Qo=IGyJr-Y zfrCxnEXl&r(@jUNtSLOKh%jNhQ<4wdPv!?u3RQcu^eI;K}s>r=I!6B zql)$(+X`lA64IN;A~?LnSd_LY+#f|CGiMQQQ(Azlzqr?Fc?T^QwGs8sFUc@-RqQ(F zsS-rz5yGqz)yLZs0-wHC#|%u`(%g+qSV$g>?U$+o-!Fn>uQ@$t*uyIj`16^?!U|-8!Emy3eAsX1O>LfTd-^ zj-sa9jEU{f?Ux7*eZ)&LLg>NOJbwwqfmd_KS=)uwIljmxI@z0fq!pfvd*%aJ=`6tu zNbGtBNVaiRZY&N14h1;{58qW1E5_9C5#T1PUp??K=nim_%Nfe zI5rn3wt*;x=VZYQX_v;M>OCeX<4@s!Oq78{VB~@O&Y7+3W07sQaOx4EelC&Ww4=P^ zh3e?90g19Gm%9^e4JjC}1G>D168Y0lg~*JGSS>N2jK93_Pc|)TUt=IOkXGBzedl!W z=;~d+K8jK+_U}~f?5~A>FW?3%`ow$;(<>+*))1|qRUOY0dpbx;`%L_iH z$h5DOfwuwN8z#Z{`uF{a5jqDW(>ZG68s+o3uip)QeJE+fFs}_Bz)?i!n+bXPt4V(%@_KUe8w|)q#MvN;LS?f~D z|Dr{4a@*#&|4^;`R{+Fwwpv4q!lXS$6_uCk=_hS3+@c-UH`xF=LBDVS@)HHqaBif11D!g+qxN} zp>&fmk2g6Ly+T7lY~O_NHxsiJ#_m7x6)w{7vJEbO)^t=jl*Fl$+4DMe-sF2;&6F40 z%Qp;H;xfYSOUKz-LRcD;dVX;PCiEXfM2J6rYKcxq*RWVEcDU7FWdn*k7qnzK5 zW0Qi}a#LH(^|+qD2z|PAk4Lv})uWYDjeS(wG;5M?OoMkdXw^vx;@Z>GgK5rSfwf&5 zKT2r61DZgqpGjIe#jNZi#U*`118eF@RSoJIqtdW65;WnQ_0p3l5wJTIC}K2&NN}q)zK+jAl!#mfH9B zm_~WrpM%&vY`=Qb)f5uQZlt@HFAlWJ=UHYLFCXEutoW|^QIcem&uGhdfl$igujV*6rbC@K14{>!7Kh9$-kXj`HbQE z^XD}Ht|TIinG>FX(r{A3j|dPA!bkf_>8V`Aqt}F%KK$zfupupg|1DdfKiInRC$^5n z>Jb{?x*f7v`(tnvyk2v zAk8-y+6OS~LeC#O+dtiNWLtu5PQdn6SCrjy67a^eIf)>x^tuA0IJrX&eTKL&RY!4O zhQ@OdzA+uqqXS}Lue?^@bfs#ZRX-{KqVRFyMYP?}{-l!p28YR4K6^5EIzQ{mn zv%#SbvrM~J=uThk<>J1L^k}GV_Nh@jrL{lI$oNE_Z9n$pKe-=Y6Owz-L=oVzP1ou4 zk<-G&&{L)!4qOu{v+;fU`%Fj>co3NpE|bspP#`rV@t{0-cXH!R=JT z)@d9FJsy(g*WC8o6l}uab<5TJZpHIM*krFMv0n&lq3o_n4Z*6|N zI(*0-;nsNG#%3}xyD-%^)*_TXKCW+8-cld7PU{sZmW&mgu&lZ|>3_Yk?&xuT6Iist z)OVotmnX||+D?*s+fgN*LB-Jsq;n-ZkXFgE3rL&$&i}T%LkHZzP@CaI5lEx&>C3v= z%!6g!Y$e>820PK-nW!GYB}KM2W~m&uD>&=R+JOKyj9R3C?!`y^lfKc+PjmCqMKhScnBx7{(gT{G7q*Jo>tq*o0f z*vL%{R7J7@w?rnSrQxYV(eAr*x^7y5L~>uUbHb8w_`@eRzGblinZFeJK5ZwRz_x`* zLF_B+WO(Xe$B}$*_9;9B>fg}Tt5329kQtk8PUwZ5>qCx`-b3MGsq#p+hb{pjn) z(#9Mz!M2(M>g`gc14Fvavw8zYcD0n=PuP2((vwc#wd@fiV`3qe0>sB?&BEv&8)ciE zJz95GQeeN`6@S``z+8`x8(p_YHZ3X7*#ZfAJTB*Z1U;>BQlLNR_p^6qfpAYj9QJ9?(ATJoXD-juC0bT1#}ww3gv#!sqs3J|}TftkQN)a_td4=SnPH z`xdY%hF2PD()Hi$_fu1c)z$pY(-*4zED4=flKu?71irPj~yGYpqWW>g<9y0o>`JB41CZK*@ z1u9Y8R?gc6TYH>?1dk09k$JCbntnP-=uW+!oLxC52fo(0q`AKy0$Fu3}Uz!Ov$X z&|q1MeelPGenVoLv6kE_n8)jI;-;6>7VJN{&;H*96aTRFk@$?1YzVR%_+XRk zd;(I5cgOXn$=jWOAXOg0PC-8aG9T%^x!>se@5O$R$Om7jK#S*GpeJ{Tz}U$9Dr1$W z<+CowDnyA`8HuLT^WB{yJn48qHb7q)|9?S&T>XiTrs-_(4O=+8lQ6)p;>s&3oBqb) zunb4T-ZxrXzp{6#c9!Twm1z4@gdwcgRCRBz;mW?#*tl5QTjn~A+pfZ| ztqoga$sv+D+WAU{MJbxSAG^FX$t8UIswV4%V}6|vNZFlvC%O>jYcjlMU}$Yw-0KAm z8J^;5EmVFA;?wP$0Ow6ld11j>-+jFhhoAst%1#qrpF>$mW1t)6b=p7vD4qQRc%j&q zAL`eBZ7=ZzhTQ|k>^9e;RteBOo)c49$l25k_uWgf8EcQap=X*?RHbKoRnf9VRQ*B& zJEw$;kLJZHk+zzVS|c&3keAX$c^@(}Y3y_wc(>Kpn~KZ9O%-4% z8c!ty1En>@;qGe5!NWt-1)i5gt*wp*mue7odWk>(;6W!)mqc?_U=f|{Kac0>w zg?EmR`NEdGnyuK~bdQm;wc>@$9KF8R=fW52;BNQJ1#tl8^KiqY0sEePn*?w9!SH;n z!maaf_nP{@f1`Lz|k%I}65Fjww2m~f41LXjSj07TxWD^8P z1Pdgxz&1IXBoNUi=bTfu>h>M4?|q}c_rC7&b&vkh=Z82#`|K0;Ui<95)|ztyM=(_> zl+X8P-G$gE0eCJO1EM1~8D18E(bqD{{?PYB>Uiq&f4)u~edW%&+;_@%e(982KW~T| zq?zCJl+fn+)_*Q(=vP~{v=rBxrR*7?dBV!3#gejotUqDB`k$`noVmPlX)hZ+JM#F} z9+5x#^e_UHa+V!`-h}Izmzwn}2R5uR<`2-8jnE#In?ZcMnZUvuynq$)8(hCLjv^X< zU4upsk1t&R_k)Zm7hP<5d~1s(V%~J3>&4c(+JW|yQu(|(J|dOj<~mbBp{z;z(qnAT z1)-=9`Fty4-;}JZcT}zyB46RrKtCq%S-~0Sm8WGsHvMfYuJeAQx*8Yvei^30A$Yce zcoibnl>|=WJIUx2O-U6nYk*bG`c`sMKj3`R`gg4+eAk8Mj|0sY=LNK8H#$B91#>84 zPfbe~?lF=oTKNI>Vm$D@=A+-VeYth+WvQc#QR06h z5Ybi3HwJ`%Lm>9lx7~%fgPYxV{4Y2JON9i4@HuaR0XUoxt}GU4fkW#VI$j@Gs1?5V zaXG}bEt2EPApPiYE#QtMl_ibuhO!1P3MD1AX07srLDU%t1oi-}CV@U{N6L$*HRyEx zZkSBHEU74mmW4_GOe?*haT4L(d}84Be$6KLuS>seZidoCqHTulw<~6?oi=DX&`7y| z_NuLrZe6S(*ZD#~b7+ovlg7bcm&AF0qa_H?EP_p0=0NkG<-#&G&J&#;$Rod&KHol! z#vCR+wQ3rZu0FUSB}yF)uV|Andl;^UeC{V-;OWL!CDjF9oKF?CGKsCYVcMuqNg_oODyAdHOdynqy&Av0OBw8!|emOi*-~A4M4KSI0-0<5hflCdr zy1we6k5Y2l3fi>pzU1-of96^*!|rBq4cTBDXXy?>y_)?7??TC-PFh}=N=Cr@1@~II z(@nVF$>n20n82mg2o~8ZOBLEUJ|nnp%B->OM1tpUx20>=TLL$#u6h!}03nDxhCIz^ z$z@QiW&5AnGNnp(CLrxyb$q+>a-GFRB$NqD2`GsbP@ z>21A*E`;3NS$ju^sN+F0Y4I?-!ZjX`gX}*j->!83ZERXuDGcXTpN~52bg+N9s)%p0^{ahqaiYLxW$d=0}&B@Xxe}S90p@>2e_l56AfAtE%&R) z4thoUXPW<<1OD>dBnS{*EafMeYvycQV?p9Ps@*)9VMY47I!w;7Q zTy+r3FGh$#x3}f5pTyC|^U5h22?g_6IvWGcvthkyL7ZNSKXYfLc{Mf<$Ek*UBNx9U z$yjqK^kM(_pD{FAnd^!%wUzEG$?w;4lfz?9{SM<%X|Egi(>HDY9G{68#euj0{g{ zRHl>OFdncz5Ex{RAH$Ig`qm9OP9F4)@CJ_>Z}1E6rz^>ayw0v=esjd!DHwo#ROG8bQW-9y5J4V^4r~|iQUyD%{4lh+2;4whB|?buM>LURoOt# zvmgKeVgD~a5-!!$h&Z5modt(P|J+@>V$_uEoYsftcxkyex{&O|oy|wrX^a=ToBl!m zBU6&k!HmZ1xX-e3lJzJYH+g&`EZ!Rq^vWnq@5)&&;2REN)N#YO7{(@Qm2DCY^!0~4 zbL72Y+(Ju{<1;*CN%@ay5imgwm~oOLE#2}o?e9FxK8j;Vg$g9@DXtXg^^b9iHca7G zaQL4nAUtj^w$dHkbQmOxSG=@Z&`(mY8;Xt4X;u zRdjlsTkUfF*tS+tX*9N|4=_m3#*8SgnlFY7Gle4W@63vk#yg3#!F_}PbwQ3kLbmNT zy`OTk)5`IO(5JxmmtLviB&ww>_~A(DDn~+_W!^{~0Lofv6Uko7T^fm7iXtQOplsCr zwV+VfVfURJPC^v#f84;oVdlF}>HnT{(4g~H6)G=&oqgfbQPIHwADZ_DG9z;HqWdO! z#O7yoI0k z)zbPADVuyxAr8fB3>vvHKN$r0_{Qg-@#=M~LA%d*yCPO}U8{31S@?W{m*`iA$Qg(5zV)TRMdlhE`mw2l5xmEZs4e*Z^1WA6*D?>}@dJ8C)~u0ZaYe9Ybi zmNzc}*T?z4ZKuu-Rp53R}GAuogP!{yeZ6%VH$o&0e`Sf9pX zY4JJx>DISeI9l?qPcLrUt=(&y`nLAhbxaRnsf35MvG3h>Yu&hQVUW% zcz^4#G`^cICl-5-bP740Q_;qJd#)+pg+Q zf!A;%-(!t|(GFEDR8oOl2P!Eqn!qP0EXn=%)QM)Gh2b2&UQTEr_;MI+1_ku+1_Hq( zpg;St-WZL*HHVx3`y#CvJ)>waJ-s|PH(xA0z2d#ye{J3?|MEC_{=eM5%Kv5p|6&2k z|6%~Sq8l6KH%cMa7Gu!S+NAvPTLC+3*y2c%nl}TtZ~{_Hu*td#g_d!UXz!f5HwBAo?p0sY)E3U#SKs2U zL$*ZC*ZkX@ukL^0oKGU2%VjM4NL4U2b||6KMx~b4^G{5zGmNt{Bt!Z`uS=@mZMV7g z^JDdNZ4Dr;Z={yzIx>5K$$w&^Hdw?Z!!x%1Xx#@5Q19YNNwPEsm)tg+8rFEau4_rk zAkwmf%Lg}P971_?S#G&nW&R#EAj?mN@a!Xdg2pCCQxCmdIBS;+#9T@-Ls5eKp5?Ne z^7K$_iGfyO6nQ7d-z3FZxKu&YhyG(BsiA5%xL5(BL!}%fGJTfeDT;<#Fi{ijiwci- z%WCyB97gmjS$*bFZ$v9e7-N4d+_A6yK%+aF=JGCv`2;!RGYTnKJd|Drs6Gs2Y|Zz{ zb*2Z}(!N_AXGWfG&OLp0IX_#;H;yrC&6O^`GT<6>`gh9QD0v*xTl#LYgrga>05()t z)SI~zW8V?8>Xyi8(~6=Bf7=x;j^#5BF8B(}GT)tc^?J^egU+~RFcHLLzOX5IUB=sV z5L9E*oL5rdufVV`HKo`6KYwNy6TVhcmbKYf(&6YE{7Fx7uY5-|N5b4BZ>XZo^ zmKT4}BDx*O{*EeTlz}7Vfh`>UyJcEJ>`bzOIUJEJ2R!<|(u}Ytx|i4T54Ip8ua(ZN zD3LT=lNPn^%M^4$je8{)gx!cLq=iZLg%#U-88(H1OX=MU6uc1_x-Kt_!MKzu_v!>w z4Yj8}R)eIF3lJ3!xDcUOCu*9%-E|~uCGv4;?x!-O3tY+LlM~8OOYbSYy_N|*PdjQ^ z7XG=bwCE1btP=l=G_r~Fc_|89{&akJ9lJX<=fZ~nsDUjt)dw0el7ROV&{$Hhw@xff z810wV!H6jvfz=8`r|sBq2-O@DXqo6Qf4&K%x0GEcbfYR|T0~LY zW{XeOxO045+XqZIy|pS>1hi`;r~$%oDSgsI)?HmI*Y^-<24z9W7vegV$CI!=<$4#k zQNtty!-MsWfb!u3|m>9g!h0-8p?w%wd{W$H`MHyIazouKU5qX+pQh zyuZ71Gv%#|Iz~f&&2govp|0C5#S})8?gug%J-B7isl@YB?1W?)JLN>l$q`y57x0-H zOzMoeYbob4eV-rIn}y=<{b&ubuZn-U!j~wKL#&$i{yz1^BAS0pmEsJ)XANLhhH8?AEku4PU-xob260iTyiTi+B^UU35ztmYA=n1MQslT8qmSV?E=itOy$ms$=3n%r4FU>NFl-9HxR zm)6>R2G?|0oZw|;b#A-!Se}Ixq{2gGlN9xu^D=AQ|4(BB{WBrJt1)$;8JeCJBMVV( zUjOUTt?UUU|7q>4Pb?vd&y(#kyolv(|q6c}By1XKxzm5cph(zwl z`Ms@AFV5lvf^xyZ^h`h|`k~@YVSnBFSQoThS_gZnM%jpSkJ$#ap1e1*I0_X#p2xj@ zgSU4&3oUQ^T+E;B3rMn3%vd>IA2tCI-Fq;!;6eSWprB12rYH5qT)VYfPdO>@gUh<| z&7o~jS#Y_&)Hu7ImZ)6729$Mj@e6Gf{^^Be{FcXM(8ao_z^6fCvaIWd(kp@!(cldx zJ}0fLoD?R~!G1lQln8aX#+P)1@3Rb>1NZ#}HZ;=?eC@m{UBJwz>c-v5aRi^grK+h0 z3cFrRU6Akg1r+{G3`2Xq09w2Uh8|`H7z_ao=_QSbg;7Yc=$wK#eRO1U(bsRw7JYd3 zLGF>yw9b2B7dcy<1xYYY_QBtq_f^Rlbr|+9iCU1)$RY2I8-CeoUvG;PJ@zojY!i@R zDS81G@`G#K_}pgWPI{EAZ4-NTOP9=hCv2z6=l3c7*1nr7CF;<YI;jE5D`vJH?!!X zL>=8_y&60mZ0-sM{8oB&XU1dt@?(!?jXMQjA?SqX!DZ;v@sc0rZgnMIlhexANYXAe z2fXjAj6GGc0tZB?w+Nb50B58T{p-1|GIRo z=0u(|*S)(epNnXbVTX;E+Z8!=T)pk0K1y8-^jK3>?)a$TTwehi*uw%0Cw0=6iIWc2j0nE}3H8P9Pes8O=z^~qB*W`SBNBi2~kK%Tu zT5uT>BHUkOH5k-x`({9_^erPfPOeVh2P#c_{m|R4fXp$qeCorD&;@ZhdDh5|DJE0H zx-uKkSwu*liiu1WmC^8gD@;6RJ@eFl`p1ZhCeIN37`>N!fDoJz$cJqtrQ@{Ce;!vvO2$zG?hZ9PzD49PjZBxa5rjeY#H+WJZx2d1ZSH z&#h}^@7cyJv!=;owV+5wmIS_9sF5cr${3gnx*aIX;W^Vw-DpX=wJ=0c50eSOgTHAFVO}kN^L& z?huhzKjFWwaJnffO6(FX8i9IfQXj*K49TRzbM+)-TJ{$;fv|52vhl+4UtKSRc`|zD z;Q(Fch-TvoWXGJF-ufu4Ki5FMc#I%iBl(c~O`KJ0k<`Ouc8bP`(x$14SuFy z$o$)?)k?Vlw~OvCwLJ)7=iqyDxZPLDr;`-DZQEBohAtL-@eLV~?ZrN0< zG30I@J~gEHc*48PblS_~$?Pg=10`-9xm4sxr<)%rlAfkuV0V|JIgh)b0Vdx@InL)k23wIgl;c62bD}q8o zs#7#tNrkk%LIeU4nZt5lUA>>StRm1$tDhq7CzbG{^M!Px%TYOeyfklzr1G3SjXqi5 zmK5~5!+g>o4o2fTUJ~wmsR^@3#n~gZMkLm0?@|{`VIeLGb5)(T76bt13X5<;{%B@m zj++lfz#Gkmj{TAle5!-zRrQYPPRbX=e)r%sj;RwgZ1V|@ITO;(_Lz-JRr(S#f04R6 z8lsk4AJXE4bvd#y>aX{yR1>^Epu`&-eP0k1((8alcH|{Gz7Du?$i5f#%4&VDdHm}v zJZBT^DsH_^>gVf9l~n4Z^dn|`*;>nweZgAgq_I8@T(UxkNe7Bd|>twZDDzI zgNFu(kNLtp{qWn*{(Oe~L@&|Xh%-W7PinZm#;YhabBVgccrOU$1DHtA`=qP-XUUg; z8saZnbE7frZ%NOxZ|h3)Mi$ZhoVSDnRxDh^X7~?NkCC8Iua`Z_DyB7AFMhTnmG-Kuu$}x+izgr3QiMBXt0tUp^G=8gyVm|ejs5VB zIR4yYTie45Ed&aqxS44k`lBQt;CO6fEr+~mlRS5M);JpV)INcO9d4~9E7DZq4UzUn zMtiOoQ9)>jl%O!Sg+QTN2z@E2QNzTcX#~ZvWb~txUcl?&o0|u)B#y6T}-#A zBF1s(L-{tNr(JC_f3x|xpa*29$Nwa}1D@3fZ%{fG&91Jr3AehF>JYnSUL;u+z(cq^ z7!b8^*iXhC<*9qN@l-(z_{TXS#`NEJNHG(WjEi^GD~2(G5ZnA}qw!J{2{CNGXGe66 z@su;vh>&xtL7^p^et3pN|*u!#KzAE25dZ?-JlJi3tfJ$Gy& zuPheXUWjMQLg1|26KE`rjTd3lRS@fr?c#HZNsiFdpiTQwEE{;BWx(ld>U3Rz2CG!r z*`x_T`>j*JJ8zUzH{u%4$%o}CgV+DpmjT=%oIpMM%zqw2h-X1e?JI;ONw{c^t-K`M zjfbM@;K|<$D>r3b#8%OVQ+B(*$V)xLm||z2YJ*)%nG53Ly#iRP+e_^Q4Lw26t@L7< z${@R)bM{6G{_|-Bk$6v;(iBgnd3CQr(-FGNLnZITx2@(~`kEXe$idtBhAV11JpJ>ZcKnY&_d*Ld_u1f^7oQrvU9~)wGegO4 zgP}Pp+x5;=a$n=LyMxN0_0hE#!*AZKDyRMHk^j{`d#}m>(q>@|GQ@VE;*wE*RJyGmHLYsN-a*#;Vl7^Ia3s@W7hShZ>a zcv&v;puP25^kqy3cA}?g&hr@vID8I7GQvgHPeO4y2V#*0vHCHUej*AHhLrJ}cN(?t zv^+PFyWYhOnQEV`{*byy8hGW(lJ0uuxRsod(BtY*CqcP4>*8~}h*)yd=rQr;s3n^# z*vl7-pP=S=nI+``f{^Q`w&EP#U?FZ=CbCOuIFRD%R(Gns++kwH6X3aiGSI&@oj9@E z>Yv;8Cg{qtOQmc$i*CV|&V;q?u$u@dt3oz6^7#$S1m>z~y|O*#sER&eqSaPKNUiwM z0Nky30H#<^LrBOPoK?X2U;`a)ejU(Z-k?uGd7ia$@&Yh#6Gr-ZZ~7TANsoX% zw{p6A)!=un7bae$n?$~L5$ZUIoBLX+d@F0E^G=bb@}`b@hs0?oYu##>96<|B75Y9@ zxH&fXRfsfVrU2wqhU8OAUa`rgew&kR5{z;)cv|#>w@jKv@b^F|0T~w&hw3y2ZSrL{ z@qjDo1KVb8`ng6uw(gMgL~=OQmD4jAs_bE}`CVPz{B_T-efq1i_~thW+#OPKJU`{v zqcN?A3cOowsS{Jk=8I=d!@=UdSz}*3O7z2Dj&5}3PE?bjpjWNrg827(Zbtq`D> z@!Iw>_O%s~&jW-eEE*eAl^0Hvzs@iV1XFxbB*;8Tdb9MzQ~rDLCIr(aFQD$3Ywxb~ zH`UhX{+AUBY7DZuQLe+)lAo=dK8tw=`SrW(r%pY^$xqY{bxox6)TtXhGdk?{L(>zZO7*L*sMu~Po8QE2%)j_sR zu-RMu6QZ!iVSLln@6Ep507(OH#78{H5k`g-Sjo(E*L7WaAU?t`cPPH)e9S3PR2vGv zbNW{016j;q4BIDhCi%7q1U$HIceerC8NL9|Fn=84x)!aXfJl=Z5xZ=J_?XlIB6C&L zrJ6}n*CtsX6kDYY!zA;f_6yiX+tDXFlf!R%GI@sCOW$%MdjlJR-fz`d-j3byc=}j` zhBH;@uHhZ51g`eEs2p@PW}~F2 z6n-_(1QIx^vtt@G(W-@u-5ggmYOllh`6x0YKLIO*{%9@7&$%#q1#=>ziuwo^Wf9ZD zlQrF0uB)+|AFKFVX>_%(iI(7nGw_$~as7^%rwcw6@|V#t*9xYhVq$EVLTa+0i{@B! z{I7afH9zlR^2B-@`x`XAg}HL_2ZCYGi9Y$0Z{!8@;PT43RxzL%WG}3*2Ulf|oAVU* z^PcoQD9JoKaYMC!tTJOaroMsUM z;@X88}tZGyMinx_*5Ff#swPSYUtQ8#|xeP}o?-V*VcAqDM`Gqwl(;4bAB<)YNX0yoaSnR*h%`EpIM<9oeqP z$e@;w+;)i#8klxo6F6EHV`e{K$^@;n{6K>`hEsbLEl@^%VZzrSO@z2^9Cd)3AoT5- zx0&>y*F5WkA2sbSB?N6K0%JPg`Oa6jWQOK^_Z~PPyMru~83Sk$ps2!O=r9oG%K(7E zo9$pq6QbOnd66A7eyRe>*{z?0Rs$c#pDirVF&~JzboR^+YC5d0G0T3DZiu!otKyWM z(2~E)ljfFzt$aTA^_zgA;6zd-?1yHVQ0nr#;$W(nAqsTEkpnh*+e(%Av@;!G74V7R zxq=sL$1N>{XSnINWJ+tDRPNLT`&DDyup4;cb$!N3sTFdG7f*cpAc`~~FP{spio{}k z3*7&#sZSga);j*>zNai z?313UDTajU(0iZa+J3yUD)RBo$|IZm>Nl;RDndPcCZ}gr{H!@wiQ9}_GHE<0W$fOx zU3wWk9(x#6M%f*#(hu3l=qoVWJ;m&bOUB-c-TOS2#@{x3pjf<88KT7KXS-%L`&+k! z&*)F%^@o1Hn);d~4Gwh^{~U5oqy;0)xjb%hZ)@8*c|304&?XM&zFS>WsG}rBQJ)&S zb;eo|a9a~|E@&h9GTz%&vUpb0z*^a=VA==|!&F%vena5Gm@qqs8J0oaRq>*}Wx72@ zkuK?X46(1zQ2Lc~Eo1Ky%@h{jsVwlI>&#CtD@@NB4M$W{tv6I&dnkBTo~N&m4eKtaD}`Xfr!Lr5Up$4;l1iUzs^T+@V&6f6qcQ{w1dBRSz{%h-Zt?xv!2C&H|6P+ zpP@5rjeo4#4i6Nh8fSEthbWbtm{XpGndsQOE{gnSC!U8|7X@oWc3XIbjWy)CYIx~j zbuoJYyNudHJg&;{?xzD0T~1mcmNOPqhZxppGHP!$&n(*f1cLa;&Yx?nv{f%V42(Oe zP1abk2;0ooE>AATocNC1dM`F`r9NCP!b*rPl^~fs9CoZ7OP>93=%`nJ4X00iV}VoN z^-ZoFiZgw?o6jQ0CX{Q5EIa6}>x_pTIQPgW`cRR}tV1DxyXj~6aYI0Wb;)+l>HJmP zu3H|aE8(noT5JzH;k)Lke>tun{tYdyE2_s3u{mY$Zdu3>vWwi4Kh zEyA<(o*Mkzm%OWN0*oWv6iKmkXum;n3nK7lIH(3P5guAX7mLSrfevr0ggS2FwAy5~ zUHXjLOSQ8wt;= z)AV9~XJ=`23Rt}EHaq9*@2Fk2y#fsm&{baH^D%WENUdm@7oC^5nw(}4!E!S}FDW9h z;byTn;l4|YP34TM&e57oG@D~w0GA?X3|PrLib_w<)QP7h9`-*;wkkK|8IEcJa|<*1 zfbd4Fg?L)1u=#m+YI~umUN@q?|J(lAt|Yhkpp+!{@q(@En9z*pZwMS21ng(D(!$_& zwz#=*Wi)w)fJY)+j`0UenqOPH|9j`zbsiv4dBuxqm@v$38s@9RxT3=Vt#_-fI4mje z4_agg+v?~pq#?Ofm#T6mtCmyTo@8=*2Zd$J6KlrV6}B{seVl=|Ipdx4a6CvPM1bRF z@nLCCE_W<_v9 zBxs{jJH?iGXvC7@Q*kfJx_cYZ-QK}#&`71Z#kMMGjbt1$*XZG=F*VJKNc>ELC>AMVy#(+#mDS=su%{R75469 z%p+fxg=tKC>3Z;$QS8ftI2P&ZrnFr=|2P)h=)b^L_Uz?ebINOY_t@?LoY$hgBM*-Y zd)c;DIoXFj+sGSH5VDXVQixtuhm70&<}<5k2R6|9A|trlbSy*hw$O?`a z1PbuCaUUH^bd_F2;dbPdo3^cdrIRh=AB7baqy^lBQ!<_(7_-CebyQIfqXRiSJX~3~ z53b9U9~WbL;haJjbV^}$c5KPb4#K*IkK!6ZfT$J=A14>S@K;&GnlkH#mlHuap(Sy< zS+6u6_BH~r)NYJMHlIn0FVGvAe2YR928Qz{T~Z!9IR+)NyuVT5tG2S0uXM`Cs}8e> z6aJwF&x_SHI=f<(BekY+C8A9t)ojoGmb#(7&kaGZ`&Q>o;&0%Un$sOm&~I>zt6=-0 zL32dRpGB80U44|`=;N(XJ?EtGmG7@h9-qs(U-eO}Xp|2Q`Em2BTMU*#gnW(uNA{nu z<`H@&g|9x2a{g-HT`%&*F#RZqtMKectZ__t9YZ5CFITs!*6F3E-quqePq8cGH79-K zm==1PSe+qDXu>Z>&qw9&t8oV}h_H#@@aKE-p%|4N@omr3rpY{d$i;tZEu`_r$?03K z#}$}pv>eBv!g7~%zQmkJYyl{jo3{<6o+PS~t7AM~U{yUzGZM^$s>KN{`88k2Z=Z{=0j^I3U&hSEM4*s zy8i)t4K&~1RR90r`LDU8@?WixX}{emRCpa~6i!o&iBXxfkmmv@+_>1c5WdK`@K~Tr zYgkg*B$K9>=oVVL8i+jCd^>ntTl{mhd8E-l#&j^9b+Wd-z5BbjH%K1!J z(o@lTog{cUtbrFprMKyNmEr5<$e`O8>UCF`#6NHy7j<56O(05UTarP3DF|#b=Z6zDdpeIwXug2PqPhXA)hX^dQeO#}qA=PA5{+cJB5n{U^ zlgOD;G)yqp^;B?nG322B80JRzx*A3f$b8S0tKz_$OrAgVKK<WtC#}Q@^?P@0s7fw2=mi z=}jtZAtJ)`#t-mjEs1_1X5;w8TSU&Kso0_!aeYKbUwVg+bGjkd11Ua8g_*aTtM;=) z93@=gbY(cReX$*xTkWB>&RR<&-{KS0P}j(nVWGu1Xt|lT-23#*-L#KDM9?~;y81S^ zfU-+hYXjq=YAFuig<0*8Hmr{9V4QmP+n+ZJ5jcE~fDCX=eYO}thWTH02e z<=`+`b5~-4kRhHm5$V`;OT1q#T&)-S=(O~_o6H2s3ZL|*em2X<)T~wXhXweq-}TLi z9SKxSRl>weq!bD8^(PBzEQY>|@(T_>d~*7+R;%pJWZY7s>yH1bsLRSc+;;MPlet|T z7g!=YM4Z_nOYWPOM%pJVDyu0-$M9ms7wKAMTYC>p6omwK6CHI?YSH7j1$ zYEAkzOs*qch)3qpn;g!KLkEYJHHG+o6EhqJ53NkUTt6M)=bPCx^24*BL7A8B*3ylT zj-kIU-DRMOKI~4=aD5_@q4#PvY2P{;3CkPRe_cYghH}W#onxP!X&x|tzkfkfbEBhM zqh(Em&W9V$Fl+sFX)X1lt)O=HLYL*tdsO8hb$k2wQR_c+4-5*9UWfjtTH6kklt#FA z%=%`rU;ny9Y|BPmd^@?4P1TA2`SU!n&qMs|bH|zLGS_(`*XZ7%WoU<;N?iK&i$TtR zz1aWy^t;4xN1-gvF07la(~v}PM{)eK&|NIWX5v|iiZFwCFD(v8N`K!(0vCzfvz zA)gveX0z=l6%W7C70^vA|8?oH_8E9w{J=kAV3&reTmyuhuWjyqKE8LZ7E;ir+)?Yd z`Ht(~>g4*5DrNssW!%44NsDd#v&uLBRwY4gK}k}6{=J&7&j_nmP5&4#CNY8>=PC%} zD-z^!tNXRSLj<}8GYG-;Y*0~wt7f`&LlCBo9(o3pKDuzXFZ&i3!C3@o(Q zyaxIczlK_kF2hjYV=h`{ z>x1=9Ei&m_s1GfBmfLx3i)c%m-nH%rX$Ars}}ySnpwP zeQ$sq*W}soPf~Kq`0(%qX;$R)#z~_}*tOfDyLdjmbV-n)YqJ@Wn}B|LmL_TKar<-A zV~a8cqU_jx5~~`f{TSMvrsKMNgbv&3*K^ga?qkS(9e>Ee&I zv9P(bCz|#GtLdoc_X0Z!zom_|b|M7GdqK3h+pJJ>lb;u~Idtjl#>y2nWqM-G7s}q! z@|wQnD-1NFe*#d_rjdxkGMJE%j0`|OK44_!+(n##&Jh)8oG4-#$c=_vVJ)P>^zptaQ2uB2!&s1`d4 z4C(wLeqhD*c7CADCsx)u&diB8&*QvsoxW?rm?I|ocK9d?Eawr@dZ@LqS?tlqb7)ySX(diby`^aA zn?3hSR^KmeTdq5GmB_-IGBCK zRK%2Stc7V|ot1cDjx(aU=sQbL!&Ny1C>yU9%~A0=QFu;;qvGtkXyMRlJZLTXXTLC8;Dh4c zZIR+<#W9sLx*icC98r;Xz9vjK)SuiS`DXMi$;#3gkC{Y(Fdo~s zes8*W7B?U~2JAP4%_HxNm<>R{AoURm=0MFBwzKJqQz`IIf@|Mk7x9@!_0wcgyA#0qYC4KDRplh4W308DRA;--GaIB z?tlEebfje48_l3Yk@v?>bLWss0kAh5h5;5W-TfDtnh~Cc&mF=debi@4UC>!F)uhQ~ zyQgsWJ4xxqRgV5^?Z)DRu+i#tB~-XF zAB5VBUbXh*ch^YYQ2|Wa`FIhb^xiV7#u|7F?T5AIkzh@dx4PyEK4(XLyNu`YG#B&D zhT^+oq3gfUf}7}Es|^i{bt}yyrfiH@b$`I5@Vd_;}qB?Y+qg)drBysqw!dJanM}fQH7XKE+Dgh*Hs=y3*#D@AQKQy z3ZM_hh{wu5P%O(9cuFPu3qoU7l~rGzN27QWSmTEMFK$&n5vko~dd<-&PthrA+guaC zUg7r1O?fh#AWya0ZH{y+=-zjG&SgxTJjUxY%4Nh%y6uiqHWj~MRvNDG zHuAca<=Wep(PtogfOGZ7+-aYWj;ewCFFm~ey7cOf;aLf5wx{GYY)9ow@mYURYjkhh zauvmPGn&0*W?sNV49|k@ff5} ze@NXDXEYIl4D|%3R&*+Ed?LBBu)6_{I5NVBVzp+OsSsN@grbGg^-z#OMzYqVuLHc~ zka9>S3mkVcL7UaQ63;`=B)o(>SgMs6TdG~E_4i&Aax0yvn5hgJ3`JLm-|2``aZGbq zxC(xd$lQD=Thm@H9I3xhO+>fi^9wroA!f>mHS#0Z=9t|`hZLxEBD@5^-)-mlWRXzb z6JK}VHLdfQ5C6>7Rz#9pIBTiD1n_r?zC7*`8>*FrRYykQhWhE(fmX-Qeyc^vg->+O zTvKWm6MA92QxQw_BffF#Cmxzsp7xo6#!W3itGBI~Vxjr26Q3f{2Qs@419?X!sg8OO zk=mwp*;SY4W)2<@&AA<8DYoG5;L~`!af7DRh1%vQnrdLId5NcxFfDPLwgGP@bTOzs zDA&LMIBUs8*cg4E#V$4Wbj`#J*YuIZSPNz5N8a9K7sIcvjVx889=^R-d9L9)cpZb> z)E=HEn-8BX{XW^q`G%Q_L%$q4WJ#wV(lq9!X*l3#H?ghLr9?Nrhy`wBf~YgfNh5&* zKoW%ICYnJta!A~ydHu1V+cD4Twj!cu>T)7>8I*GV z#w|*dm+$WGxkeM7O+J*8lH6x5qsT}%J0MLg9Rcz=7daKwGWXHCTT{}?zAE|+<@{T8 zsTmqA)e=oHP6G3C?1b(_u9<^~{D!v8s*v)+y1bfV%F|{=q4Yrf?W|`f;|j+yWCrgW z#S%ii$r-k4qP1Zk%OS;926_#~TH7OYv4`t5D9QW?iFL@Fsh8#Ga4D=nnwD#3@G75m zhxXp5X!RRE?l-a;>Ni3}MdPqh7_V)H>Dif|;NiC|edix#RCb7VLCEA&FmjQ4p6|2} zHSwx`EhIhI$=v+~+ldH1)3T$35QNJ}WNQz2PA)B!yvg>^@4jCWB}k4h%>r%+x7tHI z@JYTmotb>%|UFmZ%2mioDF)`r~ zg+)17Y=wi7t6pJYVL91|MrNx&zYvv~_oyp0f86ja(RxuN%Hoe&o3e|!p`-a&<}Lb? z1OE%Avtf~YbJy(uyBQ}PuLeyH*pa3StPbt&KBqO%s+82xZ-(ri`aIl`@yQUY(b+iJ znjLMPiCDXbtvNNDL1CPPgo zebf22H-zVKMu~nwmlMWVO)ZzwN{Ys66`rE$V@%gII}1zx7Or4Dos0++Z@v|gxFg8P&xG-t;e|)p)?|TE(zI+lQPbwZgL%$>bQ7+R=XWkc+!}! z+0pmC@O@$IoNu}O?TM$S#!>)a@@HQIxSaxoYD zQ)_&St9G&@q0NUA75QtY3ci!!UbV3v88AsFTkudE5iC2mGu+B_*!diK&& zW_*CZV@-Mb$01U*g3EZS9ex+X?LORLLP%(;@JpY(f2t_dx&Dy4O7cU=9N<>jGi@I` zIYsz95LCYJDV(;sMA%&es2clW|oq zP{!I#aHk*Q6%C7_K8vai%Q3zeU)FC9jztY8_gcL4jr_fJ-B(gpo<%gg-*tDSYc_RJ zqqNgT)L!sg;z-{z8g;jQP|G(`;6JLJ}{GGA7A|X8c{DXCrpVq`QM0p51=-)Ze5e^ zb~}d#44B-AWU|R7x^08V(BupTfdGkMM2>C;FiFB9XPOKG0TKuh$u>C&Op?eL5Wz$v za`b%t&pqeVfA6W8x-~O3yOchav`gCcX>0Gb-t|77=`{;-t$`s#m3HfX@}El9q(sy-=?Kd{NXcY3;^6YP$Nc%~Zt^5|tQnT$F8mf3ST^H6 zTwJncqlsPG7_Y!mW2+#!K`JjW4Nw9#rwz4-t>M!V%2C@wCFy-z zeZ(^O{R*#ZU4Rl^VWw`tLsj7Lmg^()O^Eb^xa5HGmiUiGK$IW;NHc0hB_6g`R?ao< zjwbFBEA71byrOqdV1)$9J_@cED2t?)mgdX2tY|_-p=0~eclnF0G`twd1)BimTTOk> zq==PY2oQfJfSn`w_`qUu-Q9VqQ3+dd@Ay_Ud3Wi7DE#bOnZiCL*h#TkNs67JlbT-L z1k;~%P~iPxQ7urH@ARR2bXLms%BnkNhKjaL>>AAFr$aN`U z(e-2~aF=bAZYcJb#BX$T_%p6($wKJ>Rxaihi5`Icg*O%wl9f5~{6Tj+GNG0@5zSYp z1%=kf4cxN(znS3vw-lv+{99+LQ|l)wH4t<2YNE7&VhW^sGQfyjmE$sz@D9y3V-*J| zri-v@N$Dxrx-&Tbf@3r1m8aaOr13BKGig+=NP53*a2*@rcQp!_z{y7zL=RKS%$R!} zXUiP0b_xJGQVBB2nJ^{RH03Vdy_q9E2zRZEJbyf+FIR3jGFc;4nL+G}i+PYn8G?3H zIx&^2i$zmW4{{C%IM_{$A)+->!^L7%w-X4>v>QDiQk*oX3y&7q^faGb!u$ljl{V`! zUV$c_x1Lpf#AuC_7)?oi>;H4nM*F%5-m9~i!tsj*Noq_=Wl6*lvH6V=oZ{rLcT(O}J z-8lxtow^?DDj(nek?RR)B=Uz~Z1JYml0KWXbW?HN(OXI0tYHVerkok>-jngiHo3+^ znomnGz7C^LG;QgfCSO5n>O{tTd&SOw?e2xU(8|i`x0>R7km6WZjt; z)lF>KJsKZRihV3RZBmbogx_H6HW#z4cq^tJvJ4|Pl0~!RhW;6}^)s~l0|K`J(GSEs92WELLJ+8LWnqxBDwQbkEdsSGxj zh_AXx{-N60tG=r>Dv#a!@e?UW@(M@`_!ifofegZ`%PK*}NANYtB&tyJu zCfyze@D-A(p1yg*k?;c1QCE9}ZRf0(K>G>^xfw~l9ZdMrM*+x=-(?}zrf3>3gC-TF z1wvQyyx8iN{-1~Se>%Pk;krbbylSI=wVEImXun)aIQ+vB!A1?4$2GW*rBGHt$3&MM!)SW?~`Q73N()-BTsp)VeYT z3%I&UJs?Z&5xK}M41&VEXpX3+O+8-|6NpklbG4j#ejyBBs>Eeixqc!8znBQS|Hjbqgv5T zv$7`WR6MI#7hm_*OfgLnEu&;XomfRRox{eaqn=p0u^VKQnjAg&D=MG4Omq)N_CuST zx02np%tWpqDyqZLTcMdGfGQqb9BB=a+~@lyP~o@HHdXD6s4;^>py+NR_EFQ><$iBS zte+nhsM#yq|2pII#d@&LW^20O;Ob%kS5|4m)L{;xUGC=Y%4&5xxu?L)TE`QUG$kzS zJyHBqwK1yoMz7#q-mA!v{C;^Mlm33A*^K58CP-qrMaEshpA~FKmyFXbO=Qld%0@3G z{c$-|CP%N=*B2oV_9L@c!W0k+)e8*Yzf*au_QFZ240ctSaX}-4w`;~cPz?!(S z?mNM(zTNK>af8V&+L_*1x4Iofedv8zP(7HK9|rH=JOJ(`V2wskY*u-ko~C}>jyw*JuRf1bROa;?HO zc5EFZIV_UXk?M#3Xu2WC4^z^R*Eg&?+S(eVbVlT{yFb?+Xc+K?MXiy|KI$ChP!~bq z)n`?{*d3!}*Fv-Wf^m1|y0PH(8lC`_(Z(v9Z>P6Y4*U~vE%xsqkL8|lYQ=KNWV)GJ zv^cATP7A<9mI$EF$IIeg8IO7!v;^2Rr0QQu)`zIys+`0rles>qcjxG+fZutBq9B~o zt@sCIOPlD1MBP;)TYReT)`#(qeQ&&RLVInpB2oWHM}z`i%N#;f0zlbDkZT70(z{T$1+Z!R zT@dx;$-RbpG?mExz?bRp`GD(g4{-1+MzL}$A(NnJ|^n6 z%2t)x7#+yBlTU3xnrokbQU24bOTY&9Sil_!s% zw#{_EwNdYv+UD7PE8K?w6apd@@A-T7nai3#wi5AeLPZwVHZzushzbwU)jq#oX_vu- z^D={m`dmLxF>U2yFNx$>$wZWB&a;P0EzWT$r8+H>}$dk}T z>$01&0nQQUE}~yr29r~kzy-5>)?Zo}_}=LEBG)MQYNvTMB;EvfW=5od>a7AgPRUpe z-iBnVUe|$^E%#0B__>8bBXDAkr7cw975iV!zhrVodp|bsV3l;Lo!+HNcXP@t8Az>b zc{EOqMrN2r{N1Z%$O-_O**h%HD|WkO6e{9y+FiXIaXnT(T;2H!RqzC7V7>+%$O!kT zqr=)YI#!+F&&mv{ta&NSc+DbYUw7A`LMhgVBZdMhE-igFm^~x7fP%DpXe6!JXe zqYaJ=gaJ!I{x6M{r?gLhdnm75kxGZV#c1b>kVF$|(McN`One}sr0s%+Q=`iFeeg9~2r86dF(f7bZ%)brKYjH@r9j6{*WZ?wH6xdNM zsFC^yLuS%E^Z&j;2%4=Jns(3qerB%-o4Kw$U@tIa_}j5c+g;}6U}5sS&>}YrO~>qn zm!u5_GM>z34b|%65(6zqaZ9q-(;cFF5;B?t*h|a0*Z$^ji#F6Uw>7pK3;eA>11^}_ zzYJ+4cPI9M=L%xNH^e6)0n|?81P#|oL-}0ZtfMA9nG0&Hw<+KS5iz09f=yTF6@_O@50>3KSx0qTcG@s~F{7M9%N z+$^G1p$S^?#V33KeWqpmjjYeykuY%(fho^g24+uFTRm7G$RZsWDE?qzix8FB-wU|% z{1z*rIOB6 z*RwFuF=--O^`u^aCr@19xw6@ur_3S~t=z-yvu^g&)T)m8sHm3Rbe4*rIOTF8=d9#D z$7D|y%eCeZlEB{OaygCt2M6yGv;quq_ryv{6L$GpT&UCLjt6Nm`6V#nP+pVWl)wM@ zpBCc(d1#Yu{YPd+GEt&_>Am*535A)sFGMxG?$x-Seta`d*pMDwp}T>~vHQ({&U zj?JCybA$gr$u;X(Iwws~pS6@7Va6PSb~Zqu!$SQnH6!!*F|Cn5etzOU``1w_8fn;C zoas77s$DU0^X}F>Q?P3rotXCcn3T3?y5u)>-z#w1>wf$@`*H50KrtY_`j9gI{H$4 zF$ODlAL!gk?r9ViHCY*h6(YwhiNbacPWvgt+v3w)97t`BX!UG@&0 zG8;M)uQk1|YHOVjQk~bOCH@+K)&;oko$+RNZHf0o5g{tI58%2@F(ik|iEgLe!vb~i zkkPUwD2HX6IN-lD%*{T}K0Mq)vRq2g%$Wp*6rf|9DY!n0Y^ZBle#tox|0A)a@kyLP zV6EiKu*`S~JR8y}e^cuzI`Geq`?A%T%^=iIXj=7nkz{!k5Ao=v-XH~ zYtwen+D&|zb7!ajBz^9ivAD)b^2ML_-oL8m)**(pE;yDJv7@T}OIhDw=16o+VJPQ= z#u&6xcZkF+X1&zm#k%{q7edzAdp|AtSWB)2c0Cn zYVq>cX*a^GTu7Ps{=O0yy4rQrjbG)%X!K^ODEH;We;j=Khjd zm{EpKrAWuoi(e6Ri(YVJFGJN9E$yUpzmt3P8Cp`-=VnqQ^$pPTH4p8r?}bPKaH7;B z(At0W|KH#LZ<+xAdnZYa5{xkA8>~)s(MHAC3BO4EwtKtlIfK0h;y_%7S{$mr6J2~C zfH@{ad>iPcZwu==@%| zTFHX?G37N)Iv)9Y;4J+@CkIe4)me*;&IKp(lRP+%`~w_qm0g#+H!p59w!($1gFYJL zQhPhaW%)f5q;jO7;LE$upp8%CqgE+@{QHOg=jeLPK&#YJR_)TEcWGr>WNg_7t_I3c z!UsE1mlvj8A68^N-}jc}IPxag*qTmi7^Eb}Pg=D24^i`(rKdbV+`x&44MZe-?9J{&6b^e^X{tjxI6g0S97@TC8p*ZMN+v zurs-L^ll6>PGKmWG6qiQ77U=WW@0ilNMwc&>31B6sU3@sXILHn4)_}IzcDt{|Bk5CEM}<8oNeuz-VZQTxf7QSSe!rhPrB z%ab((IVj(ots#k?u~Dp7RhL?*`f@82DQTpS)@ysa2{Z7-DT@8LBQ1o5rQdbBJX@fR zGm{1(*SJQTe9v@*8``D~AfJ1=NOn%PYNoHwnYke^J?=%I z|MP@-GecuA_{H4Q-DT$EFP|Gcm<_9g;Gv+wD( zYuZ%7>p2kM>LTP0e3O|}^CmPVD(Z+fZnD#IeTi9S>ULqwH(Stf-t8*5q18k}XDofa zUs-Rztc!xO2dwI^hI#hE4f6NDSJLAZ>T}LIiu2O28|SNchm+De+VOEjS#oUdYq*UI zh&KMN&Hmk}*;?GzhHscmh{xlPkeUm_DZA`RCkab5w z%xy`&qw3GC)@rz+oQ=sT)YSNAm4*T_U>s8-VY6IV$uFvjnfmm_T%+dgC#ZDIM-8EGCFWdtXx^+B|X-A(HGj%$0GNm-VfH z+j9^CWv(eCZ^3H|oIK!JXY^JjZ7!h{AGDY2m_7_^t91V((}7vaW?Mma@{}gA1}3XJ zu-F+>BA#25@$NY~SwF7hp>J#r!Z@}*p(V(j)Q=Rktc3j`;Vn#nNN;$4zCktg7$|6kRdsfDmm4UXIhX=_dLKATagTsa1Qd7k z?p}_vm8kI+R@q3+az0V_M?{=<3dAlX^Uh9-cdR$J{3yVRmKin2A&mOy&U{Xl4@@Azaf>;Sry zDYhXxA}36&RA2X-D~%a9z)WT+u(#auO_6Sp?wx*UEK&l1P<5k>7keTkBjDj;c@pYL zeG?ys%UXorGw91Ket|t3!Se@bC*<>rznSU0O5~W$>B=V<_B4ma^Q(`u9JsvJSF8rC zzv_yHgCv4jNNME7%ev*nta0k9L8wou*$=u78OkkLL5{y+#BqyzT>R8~U#O@3jOomg z3mZrSmDIc?93R2llIOlzmU-~mNGL$73?Y&x77S%B1?(rAIMc#Yb}m=U#bi6w|L|5ULvOLAE;toreT{@_bY~s04k!pm5GkxRDI-Vv4zl@Wy@zxH6+WuIe@RxcTLa!G1|t z`L~w~!r&DDryWR8NSucJjQ5iBb$K(wagy&A)tj(o`MT)|%I5`6M$D(AXGa8r9#FRx z2f<2b0SFSMIu?{Z07)4uYbH18^$=lEjbU*Fi|)I`J9*oWvbp2@gsC}9g)cc@Sw<}; zuaTP(HMlBILd*k;1YYY2Sn3#A+SGt;J?Asy(u{R)H4KlyE_FM8P9@yV)d~!r+>ntv z6EPAT0(K4}6bVsAzqBK2=y;|GCnH0EqPPsAhukQ?qejLwsz$`FQTS6QqiP!58?CcZ zH5|v`SPq{KLXi){W6_$`(2v>HILu=h_IfYVjAxB_gWR zv@C=pK0CgQKiw9Qnb{)ir&W^7g&h{GtWfvgbBacqR%6n|>pl?zTT=!*m96MLK-+{4C$jSYif8?-M^&zR)cn+O5csUU6Dt726Z? z-9R2+nvP2qHWWUlA0>p*-Y!N)u3Y;)kWwh` z`Fw0TVLu>K#|EN+#j4BIFEL=?&^dF03uc{H$(>csEWurD8stDp)DJ{s*oH!r|i)5fo!0P$1jBf`KHW;yizrU5$bKZVs){69n#hM}!{Do)tAA!jj*Ye^jb74%v z%Od1%*R&L`9iA96K@@LVFPjUrSvK7blzFB>omG?{gm}HScWTiM(sA=Br%fu%U6Uk* zb(yimJ12Y}XtL{RaA?Tzj&yF^X3uf1eb3cN{E$HE#~ZUs7qlg_wJC2sPFLdn1j*=^ zz=r0^N)#D`4~bE&qk$&M|KFRFZUPL^5Xn>{t7rt zY1D!_S6QX^?wfucAbPj(TeY#|7kYG+7A7ASD_;FsNb;g) zY-P|hD0eXS<`fIV0r}4ZectH%Y2|_CM*^fSXL)b*{G*Zyg~x~W4JG-Q+@G|3LjmTiflS?O><#3PI|7LO#eBK+c3l9`C6cLrDzT*L1aInTJ^il2uO zgz5_#6FoW}j^s;8Gu90Z*cmB=tp-e;^;fB={`$-`I(BNz;B6`maenn9$Kl~)j+@H| zrYpwX8QO#Nh+hwLQ_Yp={@Tb2?Ay9Q-y5@8Z(O&|^YzQT8st6Kw0RYKyvgP_bIN_z zkj;GD*+iw}l$;t^DK+f!=DDiD?DB$n;7y4L(#rUp0RzBVYI(I}aN}=tsRrYoxhtL< z7r*w#U4=4cjIrdJSjZGvESzkMpY2FnW^Qa|*JZp-a`eA^+7>UTAT3u1mwt#~TenH6 zoJ;w2b>ZR0<^FCcpYeacqhs*Wquh5#n7;X-wwxWC!*sX_kG*rlAz%8WFj`Q$et_5T zd~Rt!^+IzlK7Vq^r}c}+*to?&yyjUzLV}3vEFZ4sOwf*lOYxc#VE~(DTNc8IWA5Ky z!T5@$ynX+44--HZK;$1!GQ6D1^*%R1>NKiiG9|TF>M`BkO(FtGT1k5MU7v`|6l)tw zjYeztYFT#g3LAaMm$G^QsKOuvmz#GpoY!v69E@;l2A-rd54R(s*C0m?;s_73;ei2t zftijzb>+>Jlpl!(RnPX?HzhJ#*P{kBMrcQJc$Gei#8J+V@ zASbBMr!d9M3AoYXSZ&$%$y!EWvWotR5u2Kto0_g*0J=&mlkungKY#)Mr5DJy0L*xx zaYJ||ELmBDdwMRMoWI{h>xeRRD>G=_{?gOykRjNp;Fu!MyOf~tp!ArETth*o{waCurThq5@q;d3tS)y|B0aa#$CcMm z;RhYbqmUF<$fJ!u6}l{mZyLW4{T#pcyjZ#5Nu}-0EV1~h=^827>C^j*Y?1f;^!1GA!awNZ!NpBg_KLt<*MF$C1tq}_JAHr@$UHm$3FO3cjxV*J z^#Q{}Iy$g&hD5p(^DcnW&<`5pYx37Y=oZN&Y^`sm;1inQcvWhmmfy>)H=XUxcWr>wcPYVVj}N8R7g(UKj4XU-rc zPa&ZL?uwq+@$a!y7BeVq4Rusr0FMZJ^YJ&+oUu6AMnP5&FPa2fYaXXpkdT@p_4#H{ zW(ZaV98K7;^u^be0nwGoo9gyKEXGM@oT)s*R=YOH>so9{1jET9AuSdkqa<%lAffS( z;Me|oPm{BM9@6|HbZ-l8XgcW64I&d50g?*^$k=X~+WuCfyG`GR^mMtuDhyB)!1)*; zZ2;24V25`ID9dcv#zJG4Ewq`f7eBcxI97OKvH3V2 zP$>3y&a}GS#wy?S;br0Gj_jLz8)V&8f+E7is9RnP*X>Bu@5P5@3!?7Ml1bDB>z*&= z;!({?%p0EtVo59rOSUa0CMFiW`)6UrQ0{c))We&j#}AuM8K&3;0} z;A`H#Ai*A&{r4FOeeodR-#an*f1{KC??1`zr`}j$#to#D^e$g*Sav*r>VvQvscp5o zY;BIG>8#w&eDS!W2i8m#Cg}%TlniVXMeBFm{SPEI3@qxn5Nmh` zj&ub##5iiEa~qi;U)%_z;A|)Y%>;Ejm%j~#>8?i2>c8xHz@mI2qHZ;xfRt82LXc^hRb`*m~0 zoTp|S?K^7f;clY`;D*Y8RJN)4vX}mY37m?^7S_VpFJYOtSNPTW0EsO7`hgfs!2+-lx`%H-YyGC7aa z8}1&v6$**jRF0sf7~<2+-lZHDV}~kqeRYel9}r-TE?XY#4l!`h{7PZ>7hBfgX5jkf=i!KAX)S1?&BYHzo8svNVyk@ zf^+b>;k3oc3%8TN3-t`lN>}gHOd@{Ci}$$s2i<*nXRaK~bl{-O;dWcSyZgM|gmcRA zK+{#vmoQjgu+|vmC5hi?bAw&!dP0%DjrMVJ;r_P4NLPQSJ$Lk!yB~lxvNm?W_9Z)G z2&tf;4!k`6ycb(oa-1th9z zNNdB$K8X6LE&2*m{{9m}ZG}RXl%t{eZJmdEe`|Y>gLIj#pjIrmqcW|WAC>U&>+-{$ zy^TBzv;FcNm2A>a`i&i|-{r1XKZhzY@td9&ib0&=EkVpbUb9juoxBB-v##46$xIyS~SQf`|Hx)s5t zHdU6C;KWmmdbaLv_Z}2_rL}HsLvlsQ{s!Vh-!$#geZ)qVN0mOl%6}YeiK^X+Nd4Up zF6LOA_{XxkuO~3mHM%utDEZluwkR!}=|p5f*glnLrF5@*+IihG{IJ>zS?TU0?+5t( zshF}|taugh&Ca9b<*Cd?-@c_XilzTN+{}3Ya4${T7%t7(K6rXn6!4|F+N##$JLE); z)2`}Hs}6dn9=u|sg*BI3FA9oVu1oV;uC^H5T;4sVXcHC*&T%-02Y9hytnHa}os7w% z;sbWRxcH!E4FawJZHsY`iM5u-Y1qbZkwF9OzWD|nKTgRjArAE9)JI+PZ_(!R#_b4{|UEJ40Cx0_vG?0>W~cmVZQ2IS|9$?tI6f>bgvi z&V(FyR2K)B%{Ln|L^Nu?ixX~Ql=h8AK{(2=NprT}*rLW(8fp4!X7KA+{c;R(8mpGh zk`vQ}^Y0e)R(TR9T{$}7@yceKIk@UxL8rOw zOzHOe39sg0B8;f(`Vr_G&yh`9$^l~)YK=|>b?5B zT3i}ju3$LSD&nTc9SNOPl(hWv?cQ_mkzyK)Y_*ZnOt(OG3{3agv-PEQ>ubV!v(!ZR zIKO9qB3F(~GEo3h(QUo1#2MK$T`#K8o&T}Y&WDBRNzi>a{&eFYcljVoHYGj4G%EuH zYrK*Yn9go%sqk`1T`QB+U%;5MBWAuRt~4p3SO+B`!-#?C*fo-tUe#8Cg{3j#+MSuy z*nZ3A%2d6FOU6rqzQ?{grHQY&NMh|x);`9@LR|5Yu^L&+Vf>qiAa@a|hUuNAgl^qv z>EO8W1YM_6YN{!szxA}{`wFxYSrMt@i69zAWyj`o7Ux7lZ8*CMO%Pji6_v@A?v|Q~ z>#kW-NSzP7dHzwWt$}4-V=F~%ALp_nJ9f1zlyqFPLOujAS52C7+FovAM~!w*>qWTy zmA-6>e~-i0{EnLL3Cfj3cqp#{{#nn}oe%>mUU!2sB632Jgg6G zGi!!v8MZJZ+CxpM&%@e?zx?HP$2pp&VaN4r^{(g>rq9KFD(S`q)7+1d4ilZSU7fE$ z<+1dC7BAQL)YPOtbu@Mtp7BjMAYiyW;f*_5f$rfVZtjyEn(>{^^QzBk*e%B`^|b^; zD*i;tD;QeZhs$@Z@bYSwpyY7Pvd{h3n%rE5HmNV|O>J`6Bc6@U3eq1sXeMH8LTV}D zP$|tqbA_P<7_D#lG#`Xe@H8e(W}(K}Um1E!Fwdr$WsGKK8q|k5_g2_jSvl9Sqt4>f z;d?8_c3%UeA7-~R7GL~UcTU)|)J8CiGdk<>K}>Ueph}HC4Xb|<(}um_ z?l!ZwCBtbR0=LWSXo{&x$QU|X9c$P=S3}9PsPi?KN!87c?Q{AP*}Td&|XzU6lg5wG_;UR zIZO^VdO$0yOc={4skam!_CWPdl%${^LZ$o{dk6Z3O7LqM?+f^5O* z7<;8)zKkXoXjVST<;tYI?HbLfeF@U%SOLxLPJr$9tSqjWb(|*jtO|xGC8&j8MwPB? ze_NoaEl2awDx{?vJqv8gDoE-k!2;RX<>DNWQz*h#`-zg^ZNOr^-7ai3Ql#`n>wND~ zPWQK8J;id#Wwgyh9ldr9h5jz=HT6=O=e>{@^_8R}Gl=j=Y{JxQrebS*e|NDe=0-*L zn=&Q(8C>q2%F&)O-8ou+Z5A&*8eMa1s=zo(%!Z}W*18ngaJ=@<$VZ1Q7Vz>^KPJW? zM{^LUGO9ENQ&z^u5m*2gWy2_}V-jlgFSf(8&aJ1y+N-LP&RCJ{y@Tpor39%pUXME) zb%z|mLNwliZ0#<$Tzjhf*g)!UgM4MCq)7peXnNhH<~Ls>wB#2t_b|3TYA~h5 ziYXYBui_XHXAY8((Gc-dvvZ9dO0VkMI&lgXh&tigQnns69o>ehZ;qZ?;V&NBf4lyc zvvz()Xa3h$m)k!V*^kp-{-E3Auz1~j`xBl2qccv=#EG3dwOm3Z(s-=2e9HOzj?7l_ zqaBBCzwIY$=Q*sH^wZMHL`>zxv{Aw{F&ewe9p>7=tkX@QhJ7Ogg=qBDRJJ2bvN?xp zYu@V#2>X$y3Zb_a^QQ#|fa-sUMc1SBn~ z#2Xr0z*c$8m=G#5k?Z&88zOcE6a9mZOMF~qa75FA7PG&8wJ4+cSNefWF0}&t!*^|) zBQ^G~%-=B4 zwUtE{7MwL6b})1?DJ*Wg9o70|74BC<6F-eQ!=HxgHrvL(BX zmalf5XEE9+^-UAoyN@;1-i3h`L)KMG&RvL0gCx&8T%Comt{-$LcBFT7Kh_XG{u}zH z5{>;?(FFXw#a+E%5a%QR0AKNV??pYMKvCz;L$7rU6O-tTa`Qx%w(;-s^Xi*=AxcV2 zGI=t=#b+VL1m&AKPa>4VC8C4#4p+*C_RWST6kTAD8c8v9dCjeJ7P+ofcAfA7zOITw zQ!6#W32Pj*OGq+>D)PWUvkL#NVQ+)l8^Qm6rYEJd>3`V`{quy*1?*k@J41f{31nI9 zlVRf&X%535bfIIf3hnYvhc8Qtu6xfdg}-x%C?%63r`UH!?M~fOrnbaRvM`u(Ot14C z4d7Y>&5z@jVMB&%4zuP?`j5a(@cMueor`M$oe~m2)EzufT7F5&s3}0?z+Dl0A{RGE}m zJ^7`gJoN~z!njAd{0-T@*X;VozrNB>XCB>b-gj#WwHt69WW!X_dv@=e{5-Azjxr)o zO$}k!fp40-_# z(QXVg+Pax3eLW)`AC0u`G%w`2h85;|J$&m|n^&(@{L#pM?DEJ?Z#!d+w#@=hZ~tao z&>%T3S3D+5MWIHP#Of@(m5dqF8BEK<_b?V!>0JP$hj^1_UvejyWuZu?=mowUU0IQO zpyvyBHc=k|SC;k$fn+QFW8z^F6j_@wFp+HO56$br- z)AkfycBDUdQ4zT zS&B6*gIfW?Xfc>HFzG;xSku$f;~ziRqy6jL_~+)At%{eE_^QBo96^z{@YOwt=W{sk zH*fkZjyaqi(L1}6I47GP?QtafI{Jgo z2A%+D;y0x?jPlhBM^JPui%w5mgX`r>{zGUYo?XDtV=!d;lA5KA^Qtc^oW!G{KqH1 zuRlI?S?(0od1hM#an_B^^X2|Cw3o%id9@9LYMr)Gx4t1&H5%_jRnoZzPAm2h@xa^F zcuW-AE%Mhn*sO@jpz#-`xbov|%p^UNu;QH#%?2lPNX|r+CYd?K#{^Mz*b(nRV1bX$sGV7WX9cNBU-8XomP{XESmo`|!OhuIsDb z_;?v4LhvX1gJ`*>2JK6oxt;ADgq;;l?#(B`ue6sleltI-OW}UOL}h?VY2yaV2F&+ez-^arzCxXs0J&rF#L83iq6=dhc@?wvx9!%odCpju|qA>I4eC z320$HL|1f^GJ@B|=^L*LOgH}d(#j}#>Y>l1nTN9FmBE8v3aEZsc+xKdP~{UxU{w%G zmVsl1KGF&&+=Vr&rfr7XP$=|gOYkN2RmlGI#v>aA<>?ES;PGwTG;p7rzSF^|g>+VJ3;&K}>pcKWw}9SE*O|ErMX$kvRM6N}IonZ-61Fdo%0 zQ?AJ$Cz;RAh07`3>d-vhSb~8sY_~ol+}ZUwl=S#hY@q#`ebE{fh1eBEg>}TXHWj1dCm)$7UQGhx=DOdyO8195|M+j`m;ZS3E`&am0Jpy*S6aTG{hYyUUiT(sgFJHScvhzHQg` zr%1uSZ9%1(gymVdTCK~pijvdaroHrMH`N}ER*9t>^W2W*5cQdf(-f1nD;=|CL-`m2 zwM6EEs?L{+U=5{g-l-0YtTA)(XiQ6Narq9YYDQk^M95Yl9P9b`B1y7pp&&Wzu1omX z+~wULbcPulrp@PenPJd7hp6818O#Q@v@Vz1Kl~n{TF<#HnkE&Rc%%9KhcRjCX@Sv> z`J%n`BU@Cg1^&=ZLSe1nuwh0)uW3Qz;Z#g_A&XArS|+askCoM-ROVA{tiLX)yC7qI z@>et)mEz~vt>1wNG&MF3Tg$Jh+J6h~U;uR^yX@-~aWmQMiwSQeO%)`@tJ;=f>oG{F zbLEs^KeJDLJ1NBB(a z)JxAyX&fc~-doFzLFwY&NymcvWE|WoV?DdVTy+r$i-{B z6OwgTwXP*8<0dYniwpZK+K04e|3R@?cUI|`<*6}!zs7p5 z%8YhS>B3v6Nvr*BCx_Vt8-G=-VzWg8+zj)jiZfESbhV|L5+3c?wNwxvgj5g3w{v8r zIv&DSDE5BBB7l>T=|zU1{zd#skIZWOi3mMcD)Pi45OSq% z#Rg-chq)>|C7HcBdS1o2`OSTEKA>iBR!5|~@#FqN$L~--%NzLAKN6eiM_;rbZwJ-+EA;zhzR~6#KL_pB9c)oj~uk|LtS_2gbI*g2$HMAlW6 zx5gQIo0A%91V$~Zr;VbcwQMx*^sGJ0G&(xZA-M>8%7VJJ58kra-S7<+B8u==uS)tQ z%bI8q{PX}c<(9&x+y((Umt58&oi%GXGld1v7$K9r1~qBfR>6Mmy1a&DhtR?{uhpgV znnk%VA2u<$mm^;nfaT1G#xwB&FHVKP3SVJaW(8viT&OOITJj)f5mbG)5}7J40rmMm z$a~AEw$^v;m$ka;wy@&RCIN~U2^3$&LeL_?rG)?`5GY=J)hHHdf_saTU

dEf%~; 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%0Aun4VG<`oQrD6_bD`nP*+r+JfL0 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�7|Z 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 literal 0 HcmV?d00001 diff --git a/webstore-assets/v2/little_promotion.jpg b/webstore-assets/v2/little_promotion.jpg new file mode 100644 index 0000000000000000000000000000000000000000..37e0ae6433aa79ac7fbcf7ef5afb304529d62438 GIT binary patch literal 50509 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

p5K<4Nu+=%Gg#4dS6i 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 M-~8uY`n&jl02nG>Q~&?~ literal 0 HcmV?d00001 From 8cb298ac7323e03732c1551aa18cec73bee42c27 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:42:42 -0400 Subject: [PATCH 70/87] websote assets and description --- TODO.md | 1 - webstore-assets/{ => v1}/description.txt | 0 webstore-assets/v2/description.txt | 22 ++++++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) rename webstore-assets/{ => v1}/description.txt (100%) create mode 100644 webstore-assets/v2/description.txt diff --git a/TODO.md b/TODO.md index 77e7caf..cc99596 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,3 @@ # TODO -- Better webstore assets - Do some tests diff --git a/webstore-assets/description.txt b/webstore-assets/v1/description.txt similarity index 100% rename from webstore-assets/description.txt rename to webstore-assets/v1/description.txt diff --git a/webstore-assets/v2/description.txt b/webstore-assets/v2/description.txt new file mode 100644 index 0000000..628275c --- /dev/null +++ b/webstore-assets/v2/description.txt @@ -0,0 +1,22 @@ +MoodleGPT: Transform Your Moodle Quiz Experience + +MoodleGPT is a revolutionary Chrome extension designed to elevate your Moodle quiz-taking experience to new heights. By seamlessly integrating the power of CHAT-GPT, MoodleGPT provides you with an invisible assistant that effortlessly guides you through quiz questions, delivering answers with precision and speed. + +Key Features: +--- +- Versatile Question Support: Whether it's Select, Put in Order, Resolve Equation, One Response, Multiple Responses, True or False, Number, or Text questions, MoodleGPT has you covered. +- Dynamic Modes: Choose from Autocomplete, Clipboard, or Question to Answer modes to interact with answers in a way that suits your style. +- Simple Setup: Load the extension, enter your OpenAI API key, choose a model, and you're ready to conquer your Moodle quizzes. +- Customizable Settings: Tailor the extension to your preferences, including the choice of GPT model, cursor indication, title indication, typing/mouseover effect, include images, create conversation and more. + +Enhance Your Quiz-Taking Experience: +--- +MoodleGPT streamlines the quiz-taking process, providing you with accurate answers and saving you valuable time. It's the perfect tool for students and educators looking to optimize their Moodle experience. + +Support Us: +--- +If you find MoodleGPT helpful, consider supporting the project with a donation. Your support helps us continue improving and adding new features. + +Github: https://github.com/yoannchb-pro/MoodleGPT +Donation: https://www.buymeacoffee.com/yoannchbpro +Icon credits: Mortarboard icons created by itim2101 - Flaticon \ No newline at end of file From a3ec95389c5644e1ba4c75afb69bb021bfbf970a Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:52:26 -0400 Subject: [PATCH 71/87] custom gpt model - select to datalist --- extension/popup/index.html | 3 ++- extension/popup/js/gptVersion.js | 16 +++++++++------- extension/popup/js/index.js | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/extension/popup/index.html b/extension/popup/index.html index 36da2a1..714bde1 100644 --- a/extension/popup/index.html +++ b/extension/popup/index.html @@ -47,7 +47,8 @@

- + +
diff --git a/extension/popup/js/gptVersion.js b/extension/popup/js/gptVersion.js index 8fff3d2..6deb01b 100644 --- a/extension/popup/js/gptVersion.js +++ b/extension/popup/js/gptVersion.js @@ -20,20 +20,22 @@ modelInput.addEventListener('input', checkCanIncludeImages); /** * Get the list of chatgpt versions */ -function getLastChatGPTVersion(selectedModel) { +function getLastChatGPTVersion() { const apiKeySelector = document.querySelector('#apiKey'); - const selectModel = document.querySelector('#model'); + const inputModel = document.querySelector('#model'); + const modelsList = document.querySelector('#models'); let apiKey = apiKeySelector.value?.trim(); // If the api key is set we enable the button to get the last chatgpt version async function getGptVersions() { if (!apiKey) { - selectModel.setAttribute('disabled', true); + inputModel.setAttribute('disabled', true); + modelsList.setAttribute('disabled', true); return; } - selectModel.innerHTML = ''; + inputModel.innerHTML = ''; try { const req = await fetch('https://api.openai.com/v1/models', { @@ -49,8 +51,7 @@ function getLastChatGPTVersion(selectedModel) { const opt = document.createElement('option'); opt.value = model.id; opt.textContent = model.id; - opt.selected = selectedModel && model.id === selectedModel; - selectModel.appendChild(opt); + modelsList.appendChild(opt); } checkCanIncludeImages(); @@ -59,7 +60,8 @@ function getLastChatGPTVersion(selectedModel) { showMessage({ msg: 'Failed to fetch last ChatGPT version', error: true }); } - selectModel.removeAttribute('disabled'); + inputModel.removeAttribute('disabled'); + modelsList.removeAttribute('disabled'); } // Check if the api key is set diff --git a/extension/popup/js/index.js b/extension/popup/js/index.js index 5efa82a..d7c2515 100644 --- a/extension/popup/js/index.js +++ b/extension/popup/js/index.js @@ -84,6 +84,6 @@ chrome.storage.sync.get(['moodleGPT']).then(function (storage) { } handleModeChange(); - getLastChatGPTVersion(config?.model); + getLastChatGPTVersion(); checkCanIncludeImages(); }); From 7e96dbd03dcb54f6957ec33e7c22032fad4c9695 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 22:56:28 -0400 Subject: [PATCH 72/87] Update CHANGELOG.md --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5760213..d78c3d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,11 @@ ## v1.1.0 +- Bugs correction +- Adjusted the abort timeout to 20seconds - `code` is not required anymore - Issue [#9](https://github.com/yoannchb-pro/MoodleGPT/issues/9) resolved -- GPT version button fixed +- GPT model autocompletation - Better algorithm to find the correct answer (levenshtein distance) - Better ChatGPT prompt - Added `history` to the options/configuration From 85548dc9a07be4f51fe570bb957cd1ef11813d5f Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Mon, 18 Mar 2024 23:00:37 -0400 Subject: [PATCH 73/87] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index ffcb381..9df0b03 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Find the extension on the Chrome Webstore right [here](https://chrome.google.com - [Text](#text) - [What about if the question can't be completed ?](#what-about-if-the-question-cant-be-completed-) - [Test](#test) + - [Beta version with advanced features](#beta-version-with-advanced-features) ## Disclaimer ! @@ -152,3 +153,7 @@ To know if the answer has been copied to the clipboard, you can look at the titl - Solution 1: Go on [this moodle test page](https://school.moodledemo.net/login/index.php) (username: `student`, password: `moodle`) and choose any quiz. - Solution 2: Run the `index.html` file located in the `test/fake-moodle` folder. + +## Beta version with advanced features + +If you're interested in accessing advanced features ahead of their official release, please consider downloading the extension from the [dev branch](https://github.com/yoannchb-pro/MoodleGPT/tree/dev). However, please be aware that this branch is under development and may contain bugs. If you encounter any issues, don't hesitate to contact me or create an issue on GitHub. Your feedback is invaluable in helping us improve the extension. From 8a9c73e98cc61f371280bc7f4a1129dcf649ab99 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:04:00 -0400 Subject: [PATCH 74/87] better datalist --- extension/popup/index.html | 2 +- extension/popup/js/gptVersion.js | 78 ++++++++++++-------------------- extension/popup/js/index.js | 1 - 3 files changed, 30 insertions(+), 51 deletions(-) diff --git a/extension/popup/index.html b/extension/popup/index.html index 714bde1..3871c91 100644 --- a/extension/popup/index.html +++ b/extension/popup/index.html @@ -47,7 +47,7 @@
- +
diff --git a/extension/popup/js/gptVersion.js b/extension/popup/js/gptVersion.js index 6deb01b..703f1ec 100644 --- a/extension/popup/js/gptVersion.js +++ b/extension/popup/js/gptVersion.js @@ -1,13 +1,15 @@ 'use strict'; -const modelInput = document.querySelector('#model'); +const apiKeySelector = document.querySelector('#apiKey'); +const inputModel = document.querySelector('#model'); +const modelsList = document.querySelector('#models'); const imagesIntegrationLine = document.querySelector('#includeImages-line'); /** * Check if the gpt version is at least 4 to show the option 'Include images' */ function checkCanIncludeImages() { - const version = modelInput.value; + const version = inputModel.value; if (isCurrentVersionSupportingImages(version)) { imagesIntegrationLine.style.display = 'flex'; } else { @@ -15,60 +17,38 @@ function checkCanIncludeImages() { } } -modelInput.addEventListener('input', checkCanIncludeImages); +inputModel.addEventListener('input', checkCanIncludeImages); -/** - * Get the list of chatgpt versions - */ -function getLastChatGPTVersion() { - const apiKeySelector = document.querySelector('#apiKey'); - const inputModel = document.querySelector('#model'); - const modelsList = document.querySelector('#models'); +// We populate the datalist of the chatgpt model +async function populateDatalistWithGptVersions() { + const apiKey = apiKeySelector.value?.trim(); - let apiKey = apiKeySelector.value?.trim(); + if (!apiKey) return; - // If the api key is set we enable the button to get the last chatgpt version - async function getGptVersions() { - if (!apiKey) { - inputModel.setAttribute('disabled', true); - modelsList.setAttribute('disabled', true); - return; - } + inputModel.innerHTML = ''; - inputModel.innerHTML = ''; - - try { - const req = await fetch('https://api.openai.com/v1/models', { - headers: { - Authorization: `Bearer ${apiKey}` - } - }); - const rep = await req.json(); - rep.data.sort((a, b) => b.id.localeCompare(a.id)); // we sort the model to get the best chatgpt version - const models = rep.data.filter(model => model.id.startsWith('gpt')); - - for (const model of models) { - const opt = document.createElement('option'); - opt.value = model.id; - opt.textContent = model.id; - modelsList.appendChild(opt); + try { + const req = await fetch('https://api.openai.com/v1/models', { + headers: { + Authorization: `Bearer ${apiKey}` } + }); + const rep = await req.json(); + rep.data.sort((a, b) => b.id.localeCompare(a.id)); // we sort the model to get the best chatgpt version first + const models = rep.data.filter(model => model.id.startsWith('gpt')); - checkCanIncludeImages(); - } catch (err) { - console.error(err); - showMessage({ msg: 'Failed to fetch last ChatGPT version', error: true }); + for (const model of models) { + const opt = document.createElement('option'); + opt.value = model.id; + opt.textContent = model.id; + modelsList.appendChild(opt); } - inputModel.removeAttribute('disabled'); - modelsList.removeAttribute('disabled'); + checkCanIncludeImages(); + } catch (err) { + console.error(err); + showMessage({ msg: 'Failed to fetch last ChatGPT versions', error: true }); } - - // Check if the api key is set - apiKeySelector.addEventListener('blur', function () { - apiKey = apiKeySelector.value.trim(); - getGptVersions(); - }); - - getGptVersions(); } + +inputModel.addEventListener('focus', populateDatalistWithGptVersions); diff --git a/extension/popup/js/index.js b/extension/popup/js/index.js index d7c2515..5b69638 100644 --- a/extension/popup/js/index.js +++ b/extension/popup/js/index.js @@ -84,6 +84,5 @@ chrome.storage.sync.get(['moodleGPT']).then(function (storage) { } handleModeChange(); - getLastChatGPTVersion(); checkCanIncludeImages(); }); From c17bc7355fc434099466fe8940fc3ccf85fa5e62 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:06:18 -0400 Subject: [PATCH 75/87] Update CONTRIBUTE.md --- CONTRIBUTE.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md index 115f299..3f2738b 100644 --- a/CONTRIBUTE.md +++ b/CONTRIBUTE.md @@ -11,10 +11,10 @@ See the code of conduct [here](./CODE_OF_CONDUCT.md) ## Pull Request Process -1. Update the README.md with details of changes to the extension. -2. Increase the version numbers in any examples files and the README.md to the new version that this - Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). -3. You may merge the Pull Request in once you have the sign-off of two other developers, or if you +1. Update the README.md with details of changes to the extension and update the screens. +2. Build the project. +3. Select `dev` as the target branch to prepare the futur version. +4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you do not have permission to do that, you may request the second reviewer to merge it for you. ## Setup the project From 2f06370bb787a3ea1e45c189349bdd5ffefd4a0b Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:17:12 -0400 Subject: [PATCH 76/87] fixed question to answer pre-wrap on click --- extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- src/core/modes/question-to-answer.ts | 10 +++------- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index c918fba..c657b4c 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,2 +1,2 @@ -!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,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(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(s,l)}c((o=o.apply(e,t||[])).next())}))}function n(e,t){const n=e.length>t.length?e.length:t.length;return 0===n?1:(n-function(e,t){if(0===e.length)return t.length;if(0===t.length)return e.length;const n=[],o=e.replace(/\s+/,""),r=t.replace(/\s+/,"");for(let e=0;e<=o.length;++e){n.push([e]);for(let t=1;t<=r.length;++t)n[e][t]=0===e?t:Math.min(n[e-1][t]+1,n[e][t-1]+1,n[e-1][t-1]+(o[e-1]===r[t-1]?0:1))}return n[o.length][r.length]}(e,t))/n}function o(e,t){let o={element:null,similarity:0,value:null};for(const r of t){const t=n(r.value,e);if(1===t)return{element:r.element,value:r.value,similarity:t};t>o.similarity&&(o={element:r.element,value:r.value,similarity:t})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,t){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(t)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,t=!0){t&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n- But for the calculation provide this format 'result: '\n- For 'put in order' questions, maintain the answer in the order as presented in the question but assocy the correct order to it by usin this format ':\n:', ignore other rules.\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={role:s.SYSTEM,content:c};function u(e,n,o){return t(this,void 0,void 0,(function*(){const t=n.querySelectorAll("img");if(!e.includeImages||!function(e){const t=e.match(/gpt-(\d+)/);return!!(null==t?void 0:t[1])&&Number(t[1])>=4}(e.model)||0===t.length)return o;const r=[],i=Array.from(t).map((e=>function(e,t=.75){return new Promise(((n,o)=>{const r=document.createElement("canvas"),i=r.getContext("2d");if(!i)return o("Can't get the canvas context, ensure your navigator support canvas"),void r.remove();const s=new Image;s.crossOrigin="Anonymous",s.onload=()=>{r.width=s.width,r.height=s.height,i.drawImage(s,0,0);const e=r.toDataURL("image/png",t);n(e),r.remove()},s.onerror=e=>{o(e),r.remove()},s.src=e.src}))}(e))),s=yield Promise.allSettled(i);for(const t of s)"fulfilled"===t.status?r.push({type:l.IMAGE,image_url:{url:t.value}}):e.logs&&console.error(t.reason);return r.push({type:l.TEXT,text:o}),r}))}function f(e,n,o){return t(this,void 0,void 0,(function*(){const t=yield u(e,n,o),r={role:s.USER,content:t};if(!e.history)return{messages:[a,r]};let i;const l=JSON.parse(null!==(c=sessionStorage.moodleGPTHistory)&&void 0!==c?c:"null");var c;const f=function(){var e,t;const n=new URLSearchParams(document.location.search);return{host:document.location.host,cmid:null!==(e=n.get("cmid"))&&void 0!==e?e:"",attempt:null!==(t=n.get("attempt"))&&void 0!==t?t:"",history:[]}}();return i=null!==l&&function(e,t){const n=["host","cmid","attempt"];for(const o of n)if(e[o]!==t[o])return!1;return!0}(l,f)?l:f,{messages:[a,...i.history,r],saveResponse(t){e.history&&(i.history.push(r),i.history.push({role:s.ASSISTANT,content:t}),sessionStorage.moodleGPTHistory=JSON.stringify(i))}}}))}function m(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,(null==r?void 0:r.length)||0),null!=r?r:""}));t.push(n)}));const r=o.reduce(((e,t)=>e+t))+3*t[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=t.map((e=>"| "+e.map(((e,t)=>e.padEnd(o[t]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function d(t,n){t.title&&e("Copied to clipboard"),navigator.clipboard.writeText(n.response)}function p(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 i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=n.response;return!0}function h(e,t,n){var o,r;const i=t[0];if(1!==t.length||"number"!==i.type)return!1;const s=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(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(t){t.preventDefault(),"Backspace"===t.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function g(e,t,n){const s=null==t?void 0:t[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),c=o(n.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.click()),{once:!0}):a.click(),!0}function v(e,t,n){const s=null==t?void 0:t[0];if(!s||"checkbox"!==s.type)return!1;const l=n.normalizedResponse.split("\n"),c=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value));for(const t of l){const n=o(t,c);e.logs&&n.value&&r.bestAnswer(n.value,n.similarity);const i=n.element;e.mouseover?i.addEventListener("mouseover",(()=>i.click()),{once:!0}):i.click()}return!0}function y(e,t,n){if(0===t.length||"SELECT"!==t[0].tagName)return!1;const s=n.normalizedResponse.split("\n");e.logs&&r.array(s);for(let n=0;n{var t;return{element:e,value:i(null!==(t=e.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),a=o(s[n],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function w(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){t.preventDefault(),"Backspace"===t.key&&(e=n.response.length+1),e>n.response.length||(o.value=n.response.slice(0,++e))}))}else o.value=n.response;return!0}function E(e){return t(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const n=function(e){let t=e.innerText;const n=e.querySelectorAll(".accesshide");for(const e of n)t=t.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)t=t.replace(e.innerText,"\n"+m(e)+"\n");return i(t,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),s=yield function(e,n,o){return t(this,void 0,void 0,(function*(){const t=new AbortController,r=setTimeout((()=>t.abort()),2e4),s=yield f(e,n,o),l=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:s.messages,temperature:.1,top_p:.6,presence_penalty:0,max_tokens:2e3})});clearTimeout(r);const c=(yield l.json()).choices[0].message.content;return"function"==typeof s.saveResponse&&s.saveResponse(c),{question:o,response:c,normalizedResponse:i(c)}}))}(e.config,e.questionElement,n).catch((e=>({error:e}))),l="object"==typeof s&&"error"in s;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||l?"pointer":"initial"),l)console.error(s.error);else switch(e.config.logs&&(r.question(n),r.response(s)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),d(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:s,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const t=e.questionElement;e.removeListener();const n=t.textContent;t.textContent=e.gptAnswer.response,t.style.whiteSpace="pre-wrap";let o=!0;t.addEventListener("click",(function(){t.style.whiteSpace=o?"":"pre-warp",t.textContent=o?n:e.gptAnswer.response,o=!o}))}({gptAnswer:s,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const t=[p,w,h,y,g,v];for(const n of t)if(n(e.config,e.inputList,e.gptAnswer))return;d(e.config,e.gptAnswer)}({config:e.config,gptAnswer:s,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const A=[],S=[];function x(e){const t=S.findIndex((t=>t.element===e));if(-1!==t){const e=S.splice(t,1)[0];e.element.removeEventListener("click",e.fn)}}function q(t){if(S.length>0){for(const e of S)t.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return t.title&&e("Removed"),void(S.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");if(null===o)continue;t.cursor&&(o.style.cursor="pointer");const r=E.bind(null,{config:t,questionElement:o,form:e,inputQuery:n,removeListener:()=>x(o)});S.push({element:o,fn:r}),o.addEventListener("click",r)}t.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const t=e.moodleGPT;if(!t)throw new Error("Please configure MoodleGPT into the extension");t.code?function(e){document.body.addEventListener("keydown",(function(t){A.push(t.key),A.length>e.code.length&&A.shift(),A.join("")===e.code&&(A.length=0,q(e))}))}(t):q(t)}))})); +!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,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(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(s,l)}c((o=o.apply(e,t||[])).next())}))}function n(e,t){const n=e.length>t.length?e.length:t.length;return 0===n?1:(n-function(e,t){if(0===e.length)return t.length;if(0===t.length)return e.length;const n=[],o=e.replace(/\s+/,""),r=t.replace(/\s+/,"");for(let e=0;e<=o.length;++e){n.push([e]);for(let t=1;t<=r.length;++t)n[e][t]=0===e?t:Math.min(n[e-1][t]+1,n[e][t-1]+1,n[e-1][t-1]+(o[e-1]===r[t-1]?0:1))}return n[o.length][r.length]}(e,t))/n}function o(e,t){let o={element:null,similarity:0,value:null};for(const r of t){const t=n(r.value,e);if(1===t)return{element:r.element,value:r.value,similarity:t};t>o.similarity&&(o={element:r.element,value:r.value,similarity:t})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,t){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(t)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,t=!0){t&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n- But for the calculation provide this format 'result: '\n- For 'put in order' questions, maintain the answer in the order as presented in the question but assocy the correct order to it by usin this format ':\n:', ignore other rules.\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={role:s.SYSTEM,content:c};function u(e,n,o){return t(this,void 0,void 0,(function*(){const t=n.querySelectorAll("img");if(!e.includeImages||!function(e){const t=e.match(/gpt-(\d+)/);return!!(null==t?void 0:t[1])&&Number(t[1])>=4}(e.model)||0===t.length)return o;const r=[],i=Array.from(t).map((e=>function(e,t=.75){return new Promise(((n,o)=>{const r=document.createElement("canvas"),i=r.getContext("2d");if(!i)return o("Can't get the canvas context, ensure your navigator support canvas"),void r.remove();const s=new Image;s.crossOrigin="Anonymous",s.onload=()=>{r.width=s.width,r.height=s.height,i.drawImage(s,0,0);const e=r.toDataURL("image/png",t);n(e),r.remove()},s.onerror=e=>{o(e),r.remove()},s.src=e.src}))}(e))),s=yield Promise.allSettled(i);for(const t of s)"fulfilled"===t.status?r.push({type:l.IMAGE,image_url:{url:t.value}}):e.logs&&console.error(t.reason);return r.push({type:l.TEXT,text:o}),r}))}function f(e,n,o){return t(this,void 0,void 0,(function*(){const t=yield u(e,n,o),r={role:s.USER,content:t};if(!e.history)return{messages:[a,r]};let i;const l=JSON.parse(null!==(c=sessionStorage.moodleGPTHistory)&&void 0!==c?c:"null");var c;const f=function(){var e,t;const n=new URLSearchParams(document.location.search);return{host:document.location.host,cmid:null!==(e=n.get("cmid"))&&void 0!==e?e:"",attempt:null!==(t=n.get("attempt"))&&void 0!==t?t:"",history:[]}}();return i=null!==l&&function(e,t){const n=["host","cmid","attempt"];for(const o of n)if(e[o]!==t[o])return!1;return!0}(l,f)?l:f,{messages:[a,...i.history,r],saveResponse(t){e.history&&(i.history.push(r),i.history.push({role:s.ASSISTANT,content:t}),sessionStorage.moodleGPTHistory=JSON.stringify(i))}}}))}function m(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,(null==r?void 0:r.length)||0),null!=r?r:""}));t.push(n)}));const r=o.reduce(((e,t)=>e+t))+3*t[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=t.map((e=>"| "+e.map(((e,t)=>e.padEnd(o[t]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function d(t,n){t.title&&e("Copied to clipboard"),navigator.clipboard.writeText(n.response)}function p(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 i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=n.response;return!0}function h(e,t,n){var o,r;const i=t[0];if(1!==t.length||"number"!==i.type)return!1;const s=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(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(t){t.preventDefault(),"Backspace"===t.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function g(e,t,n){const s=null==t?void 0:t[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),c=o(n.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.click()),{once:!0}):a.click(),!0}function v(e,t,n){const s=null==t?void 0:t[0];if(!s||"checkbox"!==s.type)return!1;const l=n.normalizedResponse.split("\n"),c=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value));for(const t of l){const n=o(t,c);e.logs&&n.value&&r.bestAnswer(n.value,n.similarity);const i=n.element;e.mouseover?i.addEventListener("mouseover",(()=>i.click()),{once:!0}):i.click()}return!0}function y(e,t,n){if(0===t.length||"SELECT"!==t[0].tagName)return!1;const s=n.normalizedResponse.split("\n");e.logs&&r.array(s);for(let n=0;n{var t;return{element:e,value:i(null!==(t=e.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),a=o(s[n],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function w(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){t.preventDefault(),"Backspace"===t.key&&(e=n.response.length+1),e>n.response.length||(o.value=n.response.slice(0,++e))}))}else o.value=n.response;return!0}function A(e){return t(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const n=function(e){let t=e.innerText;const n=e.querySelectorAll(".accesshide");for(const e of n)t=t.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)t=t.replace(e.innerText,"\n"+m(e)+"\n");return i(t,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),s=yield function(e,n,o){return t(this,void 0,void 0,(function*(){const t=new AbortController,r=setTimeout((()=>t.abort()),2e4),s=yield f(e,n,o),l=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:s.messages,temperature:.1,top_p:.6,presence_penalty:0,max_tokens:2e3})});clearTimeout(r);const c=(yield l.json()).choices[0].message.content;return"function"==typeof s.saveResponse&&s.saveResponse(c),{question:o,response:c,normalizedResponse:i(c)}}))}(e.config,e.questionElement,n).catch((e=>({error:e}))),l="object"==typeof s&&"error"in s;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||l?"pointer":"initial"),l)console.error(s.error);else switch(e.config.logs&&(r.question(n),r.response(s)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),d(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:s,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const t=e.questionElement;e.removeListener();const n=t.textContent;t.textContent=e.gptAnswer.response,t.style.whiteSpace="pre-wrap",t.addEventListener("click",(function(){const o=t.textContent===e.gptAnswer.response;t.style.whiteSpace=o?"initial":"pre-wrap",t.textContent=o?n:e.gptAnswer.response}))}({gptAnswer:s,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const t=[p,w,h,y,g,v];for(const n of t)if(n(e.config,e.inputList,e.gptAnswer))return;d(e.config,e.gptAnswer)}({config:e.config,gptAnswer:s,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const E=[],S=[];function x(e){const t=S.findIndex((t=>t.element===e));if(-1!==t){const e=S.splice(t,1)[0];e.element.removeEventListener("click",e.fn)}}function q(t){if(S.length>0){for(const e of S)t.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return t.title&&e("Removed"),void(S.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");if(null===o)continue;t.cursor&&(o.style.cursor="pointer");const r=A.bind(null,{config:t,questionElement:o,form:e,inputQuery:n,removeListener:()=>x(o)});S.push({element:o,fn:r}),o.addEventListener("click",r)}t.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const t=e.moodleGPT;if(!t)throw new Error("Please configure MoodleGPT into the extension");t.code?function(e){document.body.addEventListener("keydown",(function(t){E.push(t.key),E.length>e.code.length&&E.shift(),E.join("")===e.code&&(E.length=0,q(e))}))}(t):q(t)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index 5750f20..68430fd 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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/types/message.ts","../src/core/get-content-with-history.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/get-response.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gpt-answer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","export enum ROLE {\r\n SYSTEM = 'system',\r\n USER = 'user',\r\n ASSISTANT = 'assistant'\r\n}\r\n\r\nexport enum CONTENT_TYPE {\r\n TEXT = 'text',\r\n IMAGE = 'image_url'\r\n}\r\n\r\nexport type MessageContent =\r\n | string\r\n | Array<\r\n | {\r\n type: CONTENT_TYPE.TEXT;\r\n text: string;\r\n }\r\n | {\r\n type: CONTENT_TYPE.IMAGE;\r\n image_url: { url: string };\r\n }\r\n >;\r\n\r\nexport type Message = {\r\n role: ROLE;\r\n content: MessageContent;\r\n};\r\n","import type Config from '@typing/config';\r\nimport { ROLE, CONTENT_TYPE, type MessageContent, type Message } from '@typing/message';\r\nimport imageToBase64 from '@utils/image-to-base64';\r\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\r\n\r\n// The attempt and the cmid allow us to identify a quiz\r\ntype History = {\r\n host: string;\r\n cmid: string; // The id of the quiz\r\n attempt: string; // The attempt of the current quiz\r\n history: { role: ROLE; content: MessageContent }[];\r\n};\r\n\r\nconst INSTRUCTION: string = `\r\nAct as a quiz solver for the best notation with the following rules:\r\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \r\n- But for the calculation provide this format 'result: '\r\n- For 'put in order' questions, maintain the answer in the order as presented in the question but assocy the correct order to it by usin this format ':\\n:', ignore other rules.\r\n- Always reply in the format: '\\n\\n...'.\r\n- Retain only the correct answer(s).\r\n- Maintain the same order for the answers as in the text.\r\n- Retain all text from the answer with its description, content or definition.\r\n- Only provide answers that exactly match the given answer in the text.\r\n- The question always has the correct answer(s), so you should always provide an answer.\r\n- Always respond in the same language as the user's question.\r\n`.trim();\r\n\r\nconst SYSTEM_INSTRUCTION_MESSAGE = {\r\n role: ROLE.SYSTEM,\r\n content: INSTRUCTION\r\n} as const satisfies Message;\r\n\r\n/**\r\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\r\n * @param config\r\n */\r\nasync function getContent(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise {\r\n const imagesElements = questionElement.querySelectorAll('img');\r\n\r\n if (\r\n !config.includeImages ||\r\n !isGPTModelGreaterOrEqualTo4(config.model) ||\r\n imagesElements.length === 0\r\n ) {\r\n return question;\r\n }\r\n\r\n const contentWithImages: MessageContent = [];\r\n\r\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\r\n const base64ImagesResolved = await Promise.allSettled(base64Images);\r\n\r\n for (const result of base64ImagesResolved) {\r\n if (result.status === 'fulfilled') {\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.IMAGE,\r\n image_url: { url: result.value }\r\n });\r\n } else if (config.logs) {\r\n console.error(result.reason);\r\n }\r\n }\r\n\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.TEXT,\r\n text: question\r\n });\r\n\r\n return contentWithImages;\r\n}\r\n\r\n/**\r\n * Create a new history object from the current page\r\n * @returns\r\n */\r\nfunction createNewHistory(): History {\r\n const urlParams = new URLSearchParams(document.location.search);\r\n\r\n return {\r\n host: document.location.host,\r\n cmid: urlParams.get('cmid') ?? '',\r\n attempt: urlParams.get('attempt') ?? '',\r\n history: []\r\n };\r\n}\r\n\r\n/**\r\n * Load the past history from the session storage otherwise return the default history object\r\n * @returns\r\n */\r\nfunction loadPastHistory(): History | null {\r\n return JSON.parse(sessionStorage.moodleGPTHistory ?? 'null');\r\n}\r\n\r\n/**\r\n * Check if two history are from the same origin\r\n * @param a\r\n * @param b\r\n * @returns\r\n */\r\nfunction areHistoryFromSameQuiz(a: History, b: History): boolean {\r\n const KEYS_TO_COMPARE: (keyof History)[] = ['host', 'cmid', 'attempt'];\r\n\r\n for (const key of KEYS_TO_COMPARE) {\r\n if (a[key] !== b[key]) return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Return the content to send to chatgpt api with history if needed\r\n * @param config\r\n * @param questionElement\r\n * @param question\r\n * @returns\r\n */\r\nasync function getContentWithHistory(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise<{\r\n messages: [typeof SYSTEM_INSTRUCTION_MESSAGE, ...Message[]];\r\n saveResponse?: (response: string) => void;\r\n}> {\r\n const content = await getContent(config, questionElement, question);\r\n const message = { role: ROLE.USER, content };\r\n\r\n if (!config.history) return { messages: [SYSTEM_INSTRUCTION_MESSAGE, message] };\r\n\r\n let history: History;\r\n\r\n const pastHistory: History | null = loadPastHistory();\r\n const newHistory: History = createNewHistory();\r\n\r\n if (pastHistory === null || !areHistoryFromSameQuiz(pastHistory, newHistory)) {\r\n history = newHistory;\r\n } else {\r\n history = pastHistory;\r\n }\r\n\r\n return {\r\n messages: [SYSTEM_INSTRUCTION_MESSAGE, ...history.history, message],\r\n saveResponse(response: string) {\r\n // Register the conversation\r\n if (config.history) {\r\n history.history.push(message);\r\n history.history.push({ role: ROLE.ASSISTANT, content: response });\r\n sessionStorage.moodleGPTHistory = JSON.stringify(history);\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default getContentWithHistory;\r\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @param quality (default: 0.75 -> 75%)\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n reject(\"Can't get the canvas context, ensure your navigator support canvas\");\r\n canvas.remove();\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png', quality);\r\n resolve(base64);\r\n\r\n canvas.remove();\r\n };\r\n\r\n img.onerror = err => {\r\n reject(err);\r\n canvas.remove();\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .slice(1) // We remove the first option which correspond to \"Choose...\"\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport normalizeText from '@utils/normalize-text';\nimport getContentWithHistory from './get-content-with-history';\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n // Get the content to send to chatgpt\n // Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true\n const contentHandler = await getContentWithHistory(config, questionElement, question);\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: contentHandler.messages,\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 0.6, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Save the response into the history\n if (typeof contentHandler.saveResponse === 'function') contentHandler.saveResponse(response);\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gpt-answer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gpt-answer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","SYSTEM_INSTRUCTION_MESSAGE","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","contentWithImages","base64Images","Array","from","map","imgEl","imageElement","quality","canvas","createElement","ctx","getContext","remove","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","err","src","imageToBase64","base64ImagesResolved","allSettled","status","type","IMAGE","image_url","url","logs","error","reason","TEXT","getContentWithHistory","message","USER","history","messages","pastHistory","JSON","parse","_a","sessionStorage","moodleGPTHistory","newHistory","urlParams","URLSearchParams","location","search","host","cmid","get","attempt","_b","createNewHistory","a","b","KEYS_TO_COMPARE","key","areHistoryFromSameQuiz","saveResponse","ASSISTANT","stringify","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","textContent","max","lineSeparationSize","reduce","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","filter","correctInput","mouseover","click","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","controller","AbortController","timeoutControler","abort","contentHandler","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","moodleGPT","Error","code","codeListener"],"mappings":"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","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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/types/message.ts","../src/core/get-content-with-history.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/get-response.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gpt-answer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","export enum ROLE {\r\n SYSTEM = 'system',\r\n USER = 'user',\r\n ASSISTANT = 'assistant'\r\n}\r\n\r\nexport enum CONTENT_TYPE {\r\n TEXT = 'text',\r\n IMAGE = 'image_url'\r\n}\r\n\r\nexport type MessageContent =\r\n | string\r\n | Array<\r\n | {\r\n type: CONTENT_TYPE.TEXT;\r\n text: string;\r\n }\r\n | {\r\n type: CONTENT_TYPE.IMAGE;\r\n image_url: { url: string };\r\n }\r\n >;\r\n\r\nexport type Message = {\r\n role: ROLE;\r\n content: MessageContent;\r\n};\r\n","import type Config from '@typing/config';\r\nimport { ROLE, CONTENT_TYPE, type MessageContent, type Message } from '@typing/message';\r\nimport imageToBase64 from '@utils/image-to-base64';\r\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\r\n\r\n// The attempt and the cmid allow us to identify a quiz\r\ntype History = {\r\n host: string;\r\n cmid: string; // The id of the quiz\r\n attempt: string; // The attempt of the current quiz\r\n history: { role: ROLE; content: MessageContent }[];\r\n};\r\n\r\nconst INSTRUCTION: string = `\r\nAct as a quiz solver for the best notation with the following rules:\r\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \r\n- But for the calculation provide this format 'result: '\r\n- For 'put in order' questions, maintain the answer in the order as presented in the question but assocy the correct order to it by usin this format ':\\n:', ignore other rules.\r\n- Always reply in the format: '\\n\\n...'.\r\n- Retain only the correct answer(s).\r\n- Maintain the same order for the answers as in the text.\r\n- Retain all text from the answer with its description, content or definition.\r\n- Only provide answers that exactly match the given answer in the text.\r\n- The question always has the correct answer(s), so you should always provide an answer.\r\n- Always respond in the same language as the user's question.\r\n`.trim();\r\n\r\nconst SYSTEM_INSTRUCTION_MESSAGE = {\r\n role: ROLE.SYSTEM,\r\n content: INSTRUCTION\r\n} as const satisfies Message;\r\n\r\n/**\r\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\r\n * @param config\r\n */\r\nasync function getContent(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise {\r\n const imagesElements = questionElement.querySelectorAll('img');\r\n\r\n if (\r\n !config.includeImages ||\r\n !isGPTModelGreaterOrEqualTo4(config.model) ||\r\n imagesElements.length === 0\r\n ) {\r\n return question;\r\n }\r\n\r\n const contentWithImages: MessageContent = [];\r\n\r\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\r\n const base64ImagesResolved = await Promise.allSettled(base64Images);\r\n\r\n for (const result of base64ImagesResolved) {\r\n if (result.status === 'fulfilled') {\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.IMAGE,\r\n image_url: { url: result.value }\r\n });\r\n } else if (config.logs) {\r\n console.error(result.reason);\r\n }\r\n }\r\n\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.TEXT,\r\n text: question\r\n });\r\n\r\n return contentWithImages;\r\n}\r\n\r\n/**\r\n * Create a new history object from the current page\r\n * @returns\r\n */\r\nfunction createNewHistory(): History {\r\n const urlParams = new URLSearchParams(document.location.search);\r\n\r\n return {\r\n host: document.location.host,\r\n cmid: urlParams.get('cmid') ?? '',\r\n attempt: urlParams.get('attempt') ?? '',\r\n history: []\r\n };\r\n}\r\n\r\n/**\r\n * Load the past history from the session storage otherwise return the default history object\r\n * @returns\r\n */\r\nfunction loadPastHistory(): History | null {\r\n return JSON.parse(sessionStorage.moodleGPTHistory ?? 'null');\r\n}\r\n\r\n/**\r\n * Check if two history are from the same origin\r\n * @param a\r\n * @param b\r\n * @returns\r\n */\r\nfunction areHistoryFromSameQuiz(a: History, b: History): boolean {\r\n const KEYS_TO_COMPARE: (keyof History)[] = ['host', 'cmid', 'attempt'];\r\n\r\n for (const key of KEYS_TO_COMPARE) {\r\n if (a[key] !== b[key]) return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Return the content to send to chatgpt api with history if needed\r\n * @param config\r\n * @param questionElement\r\n * @param question\r\n * @returns\r\n */\r\nasync function getContentWithHistory(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise<{\r\n messages: [typeof SYSTEM_INSTRUCTION_MESSAGE, ...Message[]];\r\n saveResponse?: (response: string) => void;\r\n}> {\r\n const content = await getContent(config, questionElement, question);\r\n const message = { role: ROLE.USER, content };\r\n\r\n if (!config.history) return { messages: [SYSTEM_INSTRUCTION_MESSAGE, message] };\r\n\r\n let history: History;\r\n\r\n const pastHistory: History | null = loadPastHistory();\r\n const newHistory: History = createNewHistory();\r\n\r\n if (pastHistory === null || !areHistoryFromSameQuiz(pastHistory, newHistory)) {\r\n history = newHistory;\r\n } else {\r\n history = pastHistory;\r\n }\r\n\r\n return {\r\n messages: [SYSTEM_INSTRUCTION_MESSAGE, ...history.history, message],\r\n saveResponse(response: string) {\r\n // Register the conversation\r\n if (config.history) {\r\n history.history.push(message);\r\n history.history.push({ role: ROLE.ASSISTANT, content: response });\r\n sessionStorage.moodleGPTHistory = JSON.stringify(history);\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default getContentWithHistory;\r\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @param quality (default: 0.75 -> 75%)\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n reject(\"Can't get the canvas context, ensure your navigator support canvas\");\r\n canvas.remove();\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png', quality);\r\n resolve(base64);\r\n\r\n canvas.remove();\r\n };\r\n\r\n img.onerror = err => {\r\n reject(err);\r\n canvas.remove();\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .slice(1) // We remove the first option which correspond to \"Choose...\"\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport normalizeText from '@utils/normalize-text';\nimport getContentWithHistory from './get-content-with-history';\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n // Get the content to send to chatgpt\n // Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true\n const contentHandler = await getContentWithHistory(config, questionElement, question);\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: contentHandler.messages,\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 0.6, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Save the response into the history\n if (typeof contentHandler.saveResponse === 'function') contentHandler.saveResponse(response);\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gpt-answer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n questionElement.textContent = props.gptAnswer.response;\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n questionElement.addEventListener('click', function () {\n const contentIsResponse = questionElement.textContent === props.gptAnswer.response;\n\n questionElement.style.whiteSpace = contentIsResponse ? 'initial' : 'pre-wrap';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gpt-answer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","SYSTEM_INSTRUCTION_MESSAGE","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","contentWithImages","base64Images","Array","from","map","imgEl","imageElement","quality","canvas","createElement","ctx","getContext","remove","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","err","src","imageToBase64","base64ImagesResolved","allSettled","status","type","IMAGE","image_url","url","logs","error","reason","TEXT","getContentWithHistory","message","USER","history","messages","pastHistory","JSON","parse","_a","sessionStorage","moodleGPTHistory","newHistory","urlParams","URLSearchParams","location","search","host","cmid","get","attempt","_b","createNewHistory","a","b","KEYS_TO_COMPARE","key","areHistoryFromSameQuiz","saveResponse","ASSISTANT","stringify","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","textContent","max","lineSeparationSize","reduce","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","filter","correctInput","mouseover","click","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","controller","AbortController","timeoutControler","abort","contentHandler","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file diff --git a/src/core/modes/question-to-answer.ts b/src/core/modes/question-to-answer.ts index ccb7c5a..3ab367c 100644 --- a/src/core/modes/question-to-answer.ts +++ b/src/core/modes/question-to-answer.ts @@ -17,19 +17,15 @@ function questionToAnswerMode(props: Props) { props.removeListener(); const questionBackup = questionElement.textContent; - questionElement.textContent = props.gptAnswer.response; - - // Format the content questionElement.style.whiteSpace = 'pre-wrap'; // To go back to the question / answer - let contentIsResponse = true; questionElement.addEventListener('click', function () { - questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp'; - questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response; + const contentIsResponse = questionElement.textContent === props.gptAnswer.response; - contentIsResponse = !contentIsResponse; + questionElement.style.whiteSpace = contentIsResponse ? 'initial' : 'pre-wrap'; + questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response; }); } From 7bcff24641b8bad198fcafd274008fda0bf17552 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:17:54 -0400 Subject: [PATCH 77/87] Update TODO.md --- TODO.md | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO.md b/TODO.md index cc99596..6ab9281 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,4 @@ # TODO +- Read back/Fix README - Do some tests From e703efe2ad03916fbe117784d569ac9b63448544 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:27:23 -0400 Subject: [PATCH 78/87] Update README.md --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 9df0b03..6d85f23 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ title="Mortarboard icons created by itim2101 - Flaticon" >Mortarboard icons created by itim2101 - Flaticon @@ -52,13 +52,13 @@ See the [changelog](./CHANGELOG.md) to see every updates ! ## Set up -> NOTE: This extension only works on Chromium-based browsers like Edge, Chrome, etc. Unfortunately, Firefox requires a click on the extension, which is not very discreet. +> NOTE: This extension only works on Chromium-based browsers like Edge, Chrome, etc.

Popup

-Go to "Manage my extensions" on your browser, then click on "Load unpacked extension" and select the "extension" folder. Afterwards, click on the extension icon and enter the ApiKey obtained from [openai api](https://platform.openai.com/api-keys). Finally, select a gpt model (ensure it work with completion api). +Go to "Manage my extensions" on your browser, then click on "Load unpacked extension" and select the "extension" folder. Afterwards, click on the extension icon and enter the ApiKey obtained from [openai api](https://platform.openai.com/api-keys). Finally, select a [gpt model](https://platform.openai.com/docs/models) (ensure it work with completion api). ## Mode @@ -66,7 +66,7 @@ Go to "Manage my extensions" on your browser, then click on "Load unpa Popup

-- Autocomplete: The extension will complete the question for you. +- Autocomplete: The extension will complete the question for you by selecting the correct(s) answer(s). - Clipboard: The response is copied into the clipboard. - Question to answer: The question is converted to the answer and you can click on it to show back the question (or show back the answer).
Question to Answer @@ -77,9 +77,9 @@ Go to "Manage my extensions" on your browser, then click on "Load unpa Popup

-- Api key: the openai api key. +- Api key\*: the [openai api key](https://platform.openai.com/api-keys) from your account (Note you have to put credits by entering a credit card onto your account). +- GPT Model\*: the [gpt model](https://platform.openai.com/docs/models) you want to use. - Code: a code to be more discret for injecting/removing the extension from the page. Simply type your code you entered into the configuration on the keyboard when you are on your moodle quiz and the extension will be inject. If you want to remove the injection just simply type back the code on your keyboard. -- GPT Model: the gpt model you want to use. You can click on the reload button to get the latest version of available gpt model for your account but you need to enter the api key first. - Cursor indication: show a pointer cursor and a hourglass to know when the request is finished. - Title indication: show some informations into the title to know for example if the code have been injected.
![Injected](./assets/title-injected.png) @@ -93,7 +93,7 @@ Go to "Manage my extensions" on your browser, then click on "Load unpa
![Mouseover2](./assets/mouseover2.gif) - Infinite try: click as much as you want on the question (don't forget to reset the question). - Save history: allows you to create a conversation with ChatGPT by saving the previous question with its answer. However, note that it can consume a significant number of tokens. -- Include images (only work with gpt-4): allows you to include the images from the question to be send to the chatgpt api. The quality is reduced to 75% to use less tokens.However, note that it can consume a significant number of tokens. +- Include images (only work with gpt-4): allows you to include the images from the question to be send to the chatgpt api. The quality is reduced to 75% to use less tokens. However, note that it can consume a significant number of tokens.
![Images](./assets/images.gif) ## Internal Features @@ -143,9 +143,9 @@ Table are formated from the question to make it more readable for CHAT-GPT. Exam ![Text](./assets/text.gif) -## What about if the question can't be completed ? +## What about if the question can't be autocompleted ? -To know if the answer has been copied to the clipboard, you can look at the title of the page which will become "Copied to clipboard" for 3 seconds. +To know if the answer has been copied to the clipboard, you can look at the title of the page which will become "Copied to clipboard" for 3 seconds if `Title indication` is on. ![Clipboard](./assets/clipboard.gif) From d4388d175ef40451735483e71e30111819b13448 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:27:35 -0400 Subject: [PATCH 79/87] Update TODO.md --- TODO.md | 1 - 1 file changed, 1 deletion(-) diff --git a/TODO.md b/TODO.md index 6ab9281..cc99596 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,3 @@ # TODO -- Read back/Fix README - Do some tests From 2905127271ebd2a17e9f355a786e04f7d0c7c03c Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:32:32 -0400 Subject: [PATCH 80/87] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6d85f23..5303513 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Find the extension on the Chrome Webstore right [here](https://chrome.google.com - [Set up](#set-up) - [Mode](#mode) - [Settings](#settings) - - [Internal Features](#internal-features) + - [Internal other features](#internal-other-features) - [Support table](#support-table) - [Supported questions type](#supported-questions-type) - [Select](#select) @@ -96,7 +96,7 @@ Go to "Manage my extensions" on your browser, then click on "Load unpa - Include images (only work with gpt-4): allows you to include the images from the question to be send to the chatgpt api. The quality is reduced to 75% to use less tokens. However, note that it can consume a significant number of tokens.
![Images](./assets/images.gif) -## Internal Features +## Internal other features ### Support table From 9d8ce23c97f394c367d32962ceedcf72049eeb6a Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:47:32 -0400 Subject: [PATCH 81/87] fixing question to answer avoiding html --- src/core/modes/question-to-answer.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/modes/question-to-answer.ts b/src/core/modes/question-to-answer.ts index 3ab367c..5a3a8ca 100644 --- a/src/core/modes/question-to-answer.ts +++ b/src/core/modes/question-to-answer.ts @@ -16,16 +16,16 @@ function questionToAnswerMode(props: Props) { props.removeListener(); - const questionBackup = questionElement.textContent; - questionElement.textContent = props.gptAnswer.response; + const questionBackup = questionElement.innerHTML ?? ''; + questionElement.innerHTML = props.gptAnswer.response; questionElement.style.whiteSpace = 'pre-wrap'; // To go back to the question / answer questionElement.addEventListener('click', function () { - const contentIsResponse = questionElement.textContent === props.gptAnswer.response; + const contentIsResponse = questionElement.innerHTML === props.gptAnswer.response; questionElement.style.whiteSpace = contentIsResponse ? 'initial' : 'pre-wrap'; - questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response; + questionElement.innerHTML = contentIsResponse ? questionBackup : props.gptAnswer.response; }); } From c4669d58f57ce808d154a4fc300a7bcbd5d89e92 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:47:49 -0400 Subject: [PATCH 82/87] added table for test --- test/fake-moodle/css/style.css | 21 +++++++++++++++++++++ test/fake-moodle/index.html | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/test/fake-moodle/css/style.css b/test/fake-moodle/css/style.css index 29ded4f..db51b89 100644 --- a/test/fake-moodle/css/style.css +++ b/test/fake-moodle/css/style.css @@ -69,3 +69,24 @@ textarea { img { height: 5rem; } + +table { + width: 100%; + border-collapse: collapse; + margin-bottom: 20px; +} + +th, +td { + border: 1px solid #ddd; + padding: 8px; + text-align: left; +} + +th { + background-color: #f2f2f2; +} + +tr:nth-child(even) { + background-color: #f2f2f2; +} diff --git a/test/fake-moodle/index.html b/test/fake-moodle/index.html index 4bd0d8f..aedbc03 100644 --- a/test/fake-moodle/index.html +++ b/test/fake-moodle/index.html @@ -269,6 +269,40 @@
+ +
+
+

Give me the id of the personn who have a car

+ + + + + + + + + + + + + + + + + + + + + + + +
idnamebirthDatecars
Person 1Yvick15/08/1999yes
Person 2Yann19/01/2000no
+
+
+ +
+
+
From bee19cb4839e22b5241fdf1ec5f30f76f01939c0 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:48:21 -0400 Subject: [PATCH 83/87] less tokens for table --- extension/MoodleGPT.js | 2 +- extension/MoodleGPT.js.map | 2 +- src/utils/html-table-to-string.ts | 10 ++++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/extension/MoodleGPT.js b/extension/MoodleGPT.js index c657b4c..cd2a9d2 100644 --- a/extension/MoodleGPT.js +++ b/extension/MoodleGPT.js @@ -1,2 +1,2 @@ -!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,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(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(s,l)}c((o=o.apply(e,t||[])).next())}))}function n(e,t){const n=e.length>t.length?e.length:t.length;return 0===n?1:(n-function(e,t){if(0===e.length)return t.length;if(0===t.length)return e.length;const n=[],o=e.replace(/\s+/,""),r=t.replace(/\s+/,"");for(let e=0;e<=o.length;++e){n.push([e]);for(let t=1;t<=r.length;++t)n[e][t]=0===e?t:Math.min(n[e-1][t]+1,n[e][t-1]+1,n[e-1][t-1]+(o[e-1]===r[t-1]?0:1))}return n[o.length][r.length]}(e,t))/n}function o(e,t){let o={element:null,similarity:0,value:null};for(const r of t){const t=n(r.value,e);if(1===t)return{element:r.element,value:r.value,similarity:t};t>o.similarity&&(o={element:r.element,value:r.value,similarity:t})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,t){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(t)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,t=!0){t&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n- But for the calculation provide this format 'result: '\n- For 'put in order' questions, maintain the answer in the order as presented in the question but assocy the correct order to it by usin this format ':\n:', ignore other rules.\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={role:s.SYSTEM,content:c};function u(e,n,o){return t(this,void 0,void 0,(function*(){const t=n.querySelectorAll("img");if(!e.includeImages||!function(e){const t=e.match(/gpt-(\d+)/);return!!(null==t?void 0:t[1])&&Number(t[1])>=4}(e.model)||0===t.length)return o;const r=[],i=Array.from(t).map((e=>function(e,t=.75){return new Promise(((n,o)=>{const r=document.createElement("canvas"),i=r.getContext("2d");if(!i)return o("Can't get the canvas context, ensure your navigator support canvas"),void r.remove();const s=new Image;s.crossOrigin="Anonymous",s.onload=()=>{r.width=s.width,r.height=s.height,i.drawImage(s,0,0);const e=r.toDataURL("image/png",t);n(e),r.remove()},s.onerror=e=>{o(e),r.remove()},s.src=e.src}))}(e))),s=yield Promise.allSettled(i);for(const t of s)"fulfilled"===t.status?r.push({type:l.IMAGE,image_url:{url:t.value}}):e.logs&&console.error(t.reason);return r.push({type:l.TEXT,text:o}),r}))}function f(e,n,o){return t(this,void 0,void 0,(function*(){const t=yield u(e,n,o),r={role:s.USER,content:t};if(!e.history)return{messages:[a,r]};let i;const l=JSON.parse(null!==(c=sessionStorage.moodleGPTHistory)&&void 0!==c?c:"null");var c;const f=function(){var e,t;const n=new URLSearchParams(document.location.search);return{host:document.location.host,cmid:null!==(e=n.get("cmid"))&&void 0!==e?e:"",attempt:null!==(t=n.get("attempt"))&&void 0!==t?t:"",history:[]}}();return i=null!==l&&function(e,t){const n=["host","cmid","attempt"];for(const o of n)if(e[o]!==t[o])return!1;return!0}(l,f)?l:f,{messages:[a,...i.history,r],saveResponse(t){e.history&&(i.history.push(r),i.history.push({role:s.ASSISTANT,content:t}),sessionStorage.moodleGPTHistory=JSON.stringify(i))}}}))}function m(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,(null==r?void 0:r.length)||0),null!=r?r:""}));t.push(n)}));const r=o.reduce(((e,t)=>e+t))+3*t[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=t.map((e=>"| "+e.map(((e,t)=>e.padEnd(o[t]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function d(t,n){t.title&&e("Copied to clipboard"),navigator.clipboard.writeText(n.response)}function p(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 i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=n.response;return!0}function h(e,t,n){var o,r;const i=t[0];if(1!==t.length||"number"!==i.type)return!1;const s=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(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(t){t.preventDefault(),"Backspace"===t.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function g(e,t,n){const s=null==t?void 0:t[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),c=o(n.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.click()),{once:!0}):a.click(),!0}function v(e,t,n){const s=null==t?void 0:t[0];if(!s||"checkbox"!==s.type)return!1;const l=n.normalizedResponse.split("\n"),c=Array.from(t).map((e=>{var t,n;return{element:e,value:i(null!==(n=null===(t=null==e?void 0:e.parentElement)||void 0===t?void 0:t.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value));for(const t of l){const n=o(t,c);e.logs&&n.value&&r.bestAnswer(n.value,n.similarity);const i=n.element;e.mouseover?i.addEventListener("mouseover",(()=>i.click()),{once:!0}):i.click()}return!0}function y(e,t,n){if(0===t.length||"SELECT"!==t[0].tagName)return!1;const s=n.normalizedResponse.split("\n");e.logs&&r.array(s);for(let n=0;n{var t;return{element:e,value:i(null!==(t=e.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),a=o(s[n],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function w(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){t.preventDefault(),"Backspace"===t.key&&(e=n.response.length+1),e>n.response.length||(o.value=n.response.slice(0,++e))}))}else o.value=n.response;return!0}function A(e){return t(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const n=function(e){let t=e.innerText;const n=e.querySelectorAll(".accesshide");for(const e of n)t=t.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)t=t.replace(e.innerText,"\n"+m(e)+"\n");return i(t,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),s=yield function(e,n,o){return t(this,void 0,void 0,(function*(){const t=new AbortController,r=setTimeout((()=>t.abort()),2e4),s=yield f(e,n,o),l=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:s.messages,temperature:.1,top_p:.6,presence_penalty:0,max_tokens:2e3})});clearTimeout(r);const c=(yield l.json()).choices[0].message.content;return"function"==typeof s.saveResponse&&s.saveResponse(c),{question:o,response:c,normalizedResponse:i(c)}}))}(e.config,e.questionElement,n).catch((e=>({error:e}))),l="object"==typeof s&&"error"in s;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||l?"pointer":"initial"),l)console.error(s.error);else switch(e.config.logs&&(r.question(n),r.response(s)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),d(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:s,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const t=e.questionElement;e.removeListener();const n=t.textContent;t.textContent=e.gptAnswer.response,t.style.whiteSpace="pre-wrap",t.addEventListener("click",(function(){const o=t.textContent===e.gptAnswer.response;t.style.whiteSpace=o?"initial":"pre-wrap",t.textContent=o?n:e.gptAnswer.response}))}({gptAnswer:s,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const t=[p,w,h,y,g,v];for(const n of t)if(n(e.config,e.inputList,e.gptAnswer))return;d(e.config,e.gptAnswer)}({config:e.config,gptAnswer:s,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const E=[],S=[];function x(e){const t=S.findIndex((t=>t.element===e));if(-1!==t){const e=S.splice(t,1)[0];e.element.removeEventListener("click",e.fn)}}function q(t){if(S.length>0){for(const e of S)t.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return t.title&&e("Removed"),void(S.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");if(null===o)continue;t.cursor&&(o.style.cursor="pointer");const r=A.bind(null,{config:t,questionElement:o,form:e,inputQuery:n,removeListener:()=>x(o)});S.push({element:o,fn:r}),o.addEventListener("click",r)}t.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const t=e.moodleGPT;if(!t)throw new Error("Please configure MoodleGPT into the extension");t.code?function(e){document.body.addEventListener("keydown",(function(t){E.push(t.key),E.length>e.code.length&&E.shift(),E.join("")===e.code&&(E.length=0,q(e))}))}(t):q(t)}))})); +!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n- But for the calculation provide this format 'result: '\n- For 'put in order' questions, maintain the answer in the order as presented in the question but assocy the correct order to it by usin this format ':\n:', ignore other rules.\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={role:s.SYSTEM,content:c};function u(e,t,o){return n(this,void 0,void 0,(function*(){const n=t.querySelectorAll("img");if(!e.includeImages||!function(e){const n=e.match(/gpt-(\d+)/);return!!(null==n?void 0:n[1])&&Number(n[1])>=4}(e.model)||0===n.length)return o;const r=[],i=Array.from(n).map((e=>function(e,n=.75){return new Promise(((t,o)=>{const r=document.createElement("canvas"),i=r.getContext("2d");if(!i)return o("Can't get the canvas context, ensure your navigator support canvas"),void r.remove();const s=new Image;s.crossOrigin="Anonymous",s.onload=()=>{r.width=s.width,r.height=s.height,i.drawImage(s,0,0);const e=r.toDataURL("image/png",n);t(e),r.remove()},s.onerror=e=>{o(e),r.remove()},s.src=e.src}))}(e))),s=yield Promise.allSettled(i);for(const n of s)"fulfilled"===n.status?r.push({type:l.IMAGE,image_url:{url:n.value}}):e.logs&&console.error(n.reason);return r.push({type:l.TEXT,text:o}),r}))}function f(e,t,o){return n(this,void 0,void 0,(function*(){const n=yield u(e,t,o),r={role:s.USER,content:n};if(!e.history)return{messages:[a,r]};let i;const l=JSON.parse(null!==(c=sessionStorage.moodleGPTHistory)&&void 0!==c?c:"null");var c;const f=function(){var e,n;const t=new URLSearchParams(document.location.search);return{host:document.location.host,cmid:null!==(e=t.get("cmid"))&&void 0!==e?e:"",attempt:null!==(n=t.get("attempt"))&&void 0!==n?n:"",history:[]}}();return i=null!==l&&function(e,n){const t=["host","cmid","attempt"];for(const o of t)if(e[o]!==n[o])return!1;return!0}(l,f)?l:f,{messages:[a,...i.history,r],saveResponse(n){e.history&&(i.history.push(r),i.history.push({role:s.ASSISTANT,content:n}),sessionStorage.moodleGPTHistory=JSON.stringify(i))}}}))}function m(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=n[0].length,i=o.reduce(((e,n)=>e+n),0)+3*(r-1),s="\n"+Array(i).fill("-").join("")+"\n",l=n.map((e=>e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")));return l.shift()+s+l.join("\n")}function d(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function p(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function h(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function g(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.click()),{once:!0}):a.click(),!0}function v(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.click()),{once:!0}):i.click()}return!0}function y(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function w(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function A(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+m(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),s=yield function(e,t,o){return n(this,void 0,void 0,(function*(){const n=new AbortController,r=setTimeout((()=>n.abort()),2e4),s=yield f(e,t,o),l=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?n.signal:null,body:JSON.stringify({model:e.model,messages:s.messages,temperature:.1,top_p:.6,presence_penalty:0,max_tokens:2e3})});clearTimeout(r);const c=(yield l.json()).choices[0].message.content;return"function"==typeof s.saveResponse&&s.saveResponse(c),{question:o,response:c,normalizedResponse:i(c)}}))}(e.config,e.questionElement,t).catch((e=>({error:e}))),l="object"==typeof s&&"error"in s;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||l?"pointer":"initial"),l)console.error(s.error);else switch(e.config.logs&&(r.question(t),r.response(s)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),d(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:s,removeListener:e.removeListener});break;case"question-to-answer":!function(e){var n;const t=e.questionElement;e.removeListener();const o=null!==(n=t.innerHTML)&&void 0!==n?n:"";t.innerHTML=e.gptAnswer.response,t.style.whiteSpace="pre-wrap",t.addEventListener("click",(function(){const n=t.innerHTML===e.gptAnswer.response;t.style.whiteSpace=n?"initial":"pre-wrap",t.innerHTML=n?o:e.gptAnswer.response}))}({gptAnswer:s,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[p,w,h,y,g,v];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;d(e.config,e.gptAnswer)}({config:e.config,gptAnswer:s,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const E=[],S=[];function T(e){const n=S.findIndex((n=>n.element===e));if(-1!==n){const e=S.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function q(n){if(S.length>0){for(const e of S)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(S.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=A.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>T(o)});S.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){E.push(n.key),E.length>e.code.length&&E.shift(),E.join("")===e.code&&(E.length=0,q(e))}))}(n):q(n)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index 68430fd..655f9fe 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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/types/message.ts","../src/core/get-content-with-history.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/get-response.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gpt-answer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","export enum ROLE {\r\n SYSTEM = 'system',\r\n USER = 'user',\r\n ASSISTANT = 'assistant'\r\n}\r\n\r\nexport enum CONTENT_TYPE {\r\n TEXT = 'text',\r\n IMAGE = 'image_url'\r\n}\r\n\r\nexport type MessageContent =\r\n | string\r\n | Array<\r\n | {\r\n type: CONTENT_TYPE.TEXT;\r\n text: string;\r\n }\r\n | {\r\n type: CONTENT_TYPE.IMAGE;\r\n image_url: { url: string };\r\n }\r\n >;\r\n\r\nexport type Message = {\r\n role: ROLE;\r\n content: MessageContent;\r\n};\r\n","import type Config from '@typing/config';\r\nimport { ROLE, CONTENT_TYPE, type MessageContent, type Message } from '@typing/message';\r\nimport imageToBase64 from '@utils/image-to-base64';\r\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\r\n\r\n// The attempt and the cmid allow us to identify a quiz\r\ntype History = {\r\n host: string;\r\n cmid: string; // The id of the quiz\r\n attempt: string; // The attempt of the current quiz\r\n history: { role: ROLE; content: MessageContent }[];\r\n};\r\n\r\nconst INSTRUCTION: string = `\r\nAct as a quiz solver for the best notation with the following rules:\r\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \r\n- But for the calculation provide this format 'result: '\r\n- For 'put in order' questions, maintain the answer in the order as presented in the question but assocy the correct order to it by usin this format ':\\n:', ignore other rules.\r\n- Always reply in the format: '\\n\\n...'.\r\n- Retain only the correct answer(s).\r\n- Maintain the same order for the answers as in the text.\r\n- Retain all text from the answer with its description, content or definition.\r\n- Only provide answers that exactly match the given answer in the text.\r\n- The question always has the correct answer(s), so you should always provide an answer.\r\n- Always respond in the same language as the user's question.\r\n`.trim();\r\n\r\nconst SYSTEM_INSTRUCTION_MESSAGE = {\r\n role: ROLE.SYSTEM,\r\n content: INSTRUCTION\r\n} as const satisfies Message;\r\n\r\n/**\r\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\r\n * @param config\r\n */\r\nasync function getContent(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise {\r\n const imagesElements = questionElement.querySelectorAll('img');\r\n\r\n if (\r\n !config.includeImages ||\r\n !isGPTModelGreaterOrEqualTo4(config.model) ||\r\n imagesElements.length === 0\r\n ) {\r\n return question;\r\n }\r\n\r\n const contentWithImages: MessageContent = [];\r\n\r\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\r\n const base64ImagesResolved = await Promise.allSettled(base64Images);\r\n\r\n for (const result of base64ImagesResolved) {\r\n if (result.status === 'fulfilled') {\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.IMAGE,\r\n image_url: { url: result.value }\r\n });\r\n } else if (config.logs) {\r\n console.error(result.reason);\r\n }\r\n }\r\n\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.TEXT,\r\n text: question\r\n });\r\n\r\n return contentWithImages;\r\n}\r\n\r\n/**\r\n * Create a new history object from the current page\r\n * @returns\r\n */\r\nfunction createNewHistory(): History {\r\n const urlParams = new URLSearchParams(document.location.search);\r\n\r\n return {\r\n host: document.location.host,\r\n cmid: urlParams.get('cmid') ?? '',\r\n attempt: urlParams.get('attempt') ?? '',\r\n history: []\r\n };\r\n}\r\n\r\n/**\r\n * Load the past history from the session storage otherwise return the default history object\r\n * @returns\r\n */\r\nfunction loadPastHistory(): History | null {\r\n return JSON.parse(sessionStorage.moodleGPTHistory ?? 'null');\r\n}\r\n\r\n/**\r\n * Check if two history are from the same origin\r\n * @param a\r\n * @param b\r\n * @returns\r\n */\r\nfunction areHistoryFromSameQuiz(a: History, b: History): boolean {\r\n const KEYS_TO_COMPARE: (keyof History)[] = ['host', 'cmid', 'attempt'];\r\n\r\n for (const key of KEYS_TO_COMPARE) {\r\n if (a[key] !== b[key]) return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Return the content to send to chatgpt api with history if needed\r\n * @param config\r\n * @param questionElement\r\n * @param question\r\n * @returns\r\n */\r\nasync function getContentWithHistory(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise<{\r\n messages: [typeof SYSTEM_INSTRUCTION_MESSAGE, ...Message[]];\r\n saveResponse?: (response: string) => void;\r\n}> {\r\n const content = await getContent(config, questionElement, question);\r\n const message = { role: ROLE.USER, content };\r\n\r\n if (!config.history) return { messages: [SYSTEM_INSTRUCTION_MESSAGE, message] };\r\n\r\n let history: History;\r\n\r\n const pastHistory: History | null = loadPastHistory();\r\n const newHistory: History = createNewHistory();\r\n\r\n if (pastHistory === null || !areHistoryFromSameQuiz(pastHistory, newHistory)) {\r\n history = newHistory;\r\n } else {\r\n history = pastHistory;\r\n }\r\n\r\n return {\r\n messages: [SYSTEM_INSTRUCTION_MESSAGE, ...history.history, message],\r\n saveResponse(response: string) {\r\n // Register the conversation\r\n if (config.history) {\r\n history.history.push(message);\r\n history.history.push({ role: ROLE.ASSISTANT, content: response });\r\n sessionStorage.moodleGPTHistory = JSON.stringify(history);\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default getContentWithHistory;\r\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @param quality (default: 0.75 -> 75%)\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n reject(\"Can't get the canvas context, ensure your navigator support canvas\");\r\n canvas.remove();\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png', quality);\r\n resolve(base64);\r\n\r\n canvas.remove();\r\n };\r\n\r\n img.onerror = err => {\r\n reject(err);\r\n canvas.remove();\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .slice(1) // We remove the first option which correspond to \"Choose...\"\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport normalizeText from '@utils/normalize-text';\nimport getContentWithHistory from './get-content-with-history';\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n // Get the content to send to chatgpt\n // Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true\n const contentHandler = await getContentWithHistory(config, questionElement, question);\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: contentHandler.messages,\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 0.6, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Save the response into the history\n if (typeof contentHandler.saveResponse === 'function') contentHandler.saveResponse(response);\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gpt-answer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n questionElement.textContent = props.gptAnswer.response;\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n questionElement.addEventListener('click', function () {\n const contentIsResponse = questionElement.textContent === props.gptAnswer.response;\n\n questionElement.style.whiteSpace = contentIsResponse ? 'initial' : 'pre-wrap';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gpt-answer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","SYSTEM_INSTRUCTION_MESSAGE","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","contentWithImages","base64Images","Array","from","map","imgEl","imageElement","quality","canvas","createElement","ctx","getContext","remove","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","err","src","imageToBase64","base64ImagesResolved","allSettled","status","type","IMAGE","image_url","url","logs","error","reason","TEXT","getContentWithHistory","message","USER","history","messages","pastHistory","JSON","parse","_a","sessionStorage","moodleGPTHistory","newHistory","urlParams","URLSearchParams","location","search","host","cmid","get","attempt","_b","createNewHistory","a","b","KEYS_TO_COMPARE","key","areHistoryFromSameQuiz","saveResponse","ASSISTANT","stringify","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","textContent","max","lineSeparationSize","reduce","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","filter","correctInput","mouseover","click","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","controller","AbortController","timeoutControler","abort","contentHandler","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","moodleGPT","Error","code","codeListener"],"mappings":"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","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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/types/message.ts","../src/core/get-content-with-history.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/get-response.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gpt-answer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","export enum ROLE {\r\n SYSTEM = 'system',\r\n USER = 'user',\r\n ASSISTANT = 'assistant'\r\n}\r\n\r\nexport enum CONTENT_TYPE {\r\n TEXT = 'text',\r\n IMAGE = 'image_url'\r\n}\r\n\r\nexport type MessageContent =\r\n | string\r\n | Array<\r\n | {\r\n type: CONTENT_TYPE.TEXT;\r\n text: string;\r\n }\r\n | {\r\n type: CONTENT_TYPE.IMAGE;\r\n image_url: { url: string };\r\n }\r\n >;\r\n\r\nexport type Message = {\r\n role: ROLE;\r\n content: MessageContent;\r\n};\r\n","import type Config from '@typing/config';\r\nimport { ROLE, CONTENT_TYPE, type MessageContent, type Message } from '@typing/message';\r\nimport imageToBase64 from '@utils/image-to-base64';\r\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\r\n\r\n// The attempt and the cmid allow us to identify a quiz\r\ntype History = {\r\n host: string;\r\n cmid: string; // The id of the quiz\r\n attempt: string; // The attempt of the current quiz\r\n history: { role: ROLE; content: MessageContent }[];\r\n};\r\n\r\nconst INSTRUCTION: string = `\r\nAct as a quiz solver for the best notation with the following rules:\r\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \r\n- But for the calculation provide this format 'result: '\r\n- For 'put in order' questions, maintain the answer in the order as presented in the question but assocy the correct order to it by usin this format ':\\n:', ignore other rules.\r\n- Always reply in the format: '\\n\\n...'.\r\n- Retain only the correct answer(s).\r\n- Maintain the same order for the answers as in the text.\r\n- Retain all text from the answer with its description, content or definition.\r\n- Only provide answers that exactly match the given answer in the text.\r\n- The question always has the correct answer(s), so you should always provide an answer.\r\n- Always respond in the same language as the user's question.\r\n`.trim();\r\n\r\nconst SYSTEM_INSTRUCTION_MESSAGE = {\r\n role: ROLE.SYSTEM,\r\n content: INSTRUCTION\r\n} as const satisfies Message;\r\n\r\n/**\r\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\r\n * @param config\r\n */\r\nasync function getContent(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise {\r\n const imagesElements = questionElement.querySelectorAll('img');\r\n\r\n if (\r\n !config.includeImages ||\r\n !isGPTModelGreaterOrEqualTo4(config.model) ||\r\n imagesElements.length === 0\r\n ) {\r\n return question;\r\n }\r\n\r\n const contentWithImages: MessageContent = [];\r\n\r\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\r\n const base64ImagesResolved = await Promise.allSettled(base64Images);\r\n\r\n for (const result of base64ImagesResolved) {\r\n if (result.status === 'fulfilled') {\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.IMAGE,\r\n image_url: { url: result.value }\r\n });\r\n } else if (config.logs) {\r\n console.error(result.reason);\r\n }\r\n }\r\n\r\n contentWithImages.push({\r\n type: CONTENT_TYPE.TEXT,\r\n text: question\r\n });\r\n\r\n return contentWithImages;\r\n}\r\n\r\n/**\r\n * Create a new history object from the current page\r\n * @returns\r\n */\r\nfunction createNewHistory(): History {\r\n const urlParams = new URLSearchParams(document.location.search);\r\n\r\n return {\r\n host: document.location.host,\r\n cmid: urlParams.get('cmid') ?? '',\r\n attempt: urlParams.get('attempt') ?? '',\r\n history: []\r\n };\r\n}\r\n\r\n/**\r\n * Load the past history from the session storage otherwise return the default history object\r\n * @returns\r\n */\r\nfunction loadPastHistory(): History | null {\r\n return JSON.parse(sessionStorage.moodleGPTHistory ?? 'null');\r\n}\r\n\r\n/**\r\n * Check if two history are from the same origin\r\n * @param a\r\n * @param b\r\n * @returns\r\n */\r\nfunction areHistoryFromSameQuiz(a: History, b: History): boolean {\r\n const KEYS_TO_COMPARE: (keyof History)[] = ['host', 'cmid', 'attempt'];\r\n\r\n for (const key of KEYS_TO_COMPARE) {\r\n if (a[key] !== b[key]) return false;\r\n }\r\n\r\n return true;\r\n}\r\n\r\n/**\r\n * Return the content to send to chatgpt api with history if needed\r\n * @param config\r\n * @param questionElement\r\n * @param question\r\n * @returns\r\n */\r\nasync function getContentWithHistory(\r\n config: Config,\r\n questionElement: HTMLElement,\r\n question: string\r\n): Promise<{\r\n messages: [typeof SYSTEM_INSTRUCTION_MESSAGE, ...Message[]];\r\n saveResponse?: (response: string) => void;\r\n}> {\r\n const content = await getContent(config, questionElement, question);\r\n const message = { role: ROLE.USER, content };\r\n\r\n if (!config.history) return { messages: [SYSTEM_INSTRUCTION_MESSAGE, message] };\r\n\r\n let history: History;\r\n\r\n const pastHistory: History | null = loadPastHistory();\r\n const newHistory: History = createNewHistory();\r\n\r\n if (pastHistory === null || !areHistoryFromSameQuiz(pastHistory, newHistory)) {\r\n history = newHistory;\r\n } else {\r\n history = pastHistory;\r\n }\r\n\r\n return {\r\n messages: [SYSTEM_INSTRUCTION_MESSAGE, ...history.history, message],\r\n saveResponse(response: string) {\r\n // Register the conversation\r\n if (config.history) {\r\n history.history.push(message);\r\n history.history.push({ role: ROLE.ASSISTANT, content: response });\r\n sessionStorage.moodleGPTHistory = JSON.stringify(history);\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default getContentWithHistory;\r\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @param quality (default: 0.75 -> 75%)\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement, quality = 0.75): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n reject(\"Can't get the canvas context, ensure your navigator support canvas\");\r\n canvas.remove();\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png', quality);\r\n resolve(base64);\r\n\r\n canvas.remove();\r\n };\r\n\r\n img.onerror = err => {\r\n reject(err);\r\n canvas.remove();\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const jointure = ' | ';\n const headerLineLength = tab[0].length;\n const lineSeparationSize =\n maxColumnsLength.reduce((a, b) => a + b, 0) + (headerLineLength - 1) * jointure.length;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return mappedLine.join(jointure);\n });\n\n const head = mappedTab.shift();\n\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => correctInput.click(), {\n once: true\n });\n } else {\n correctInput.click();\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .slice(1) // We remove the first option which correspond to \"Choose...\"\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport normalizeText from '@utils/normalize-text';\nimport getContentWithHistory from './get-content-with-history';\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n // Get the content to send to chatgpt\n // Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true\n const contentHandler = await getContentWithHistory(config, questionElement, question);\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: contentHandler.messages,\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 0.6, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Save the response into the history\n if (typeof contentHandler.saveResponse === 'function') contentHandler.saveResponse(response);\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gpt-answer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gpt-answer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.innerHTML ?? '';\n questionElement.innerHTML = props.gptAnswer.response;\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n questionElement.addEventListener('click', function () {\n const contentIsResponse = questionElement.innerHTML === props.gptAnswer.response;\n\n questionElement.style.whiteSpace = contentIsResponse ? 'initial' : 'pre-wrap';\n questionElement.innerHTML = contentIsResponse ? questionBackup : props.gptAnswer.response;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gpt-answer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","SYSTEM_INSTRUCTION_MESSAGE","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","contentWithImages","base64Images","Array","from","map","imgEl","imageElement","quality","canvas","createElement","ctx","getContext","remove","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","err","src","imageToBase64","base64ImagesResolved","allSettled","status","type","IMAGE","image_url","url","logs","error","reason","TEXT","getContentWithHistory","message","USER","history","messages","pastHistory","JSON","parse","_a","sessionStorage","moodleGPTHistory","newHistory","urlParams","URLSearchParams","location","search","host","cmid","get","attempt","_b","createNewHistory","a","b","KEYS_TO_COMPARE","key","areHistoryFromSameQuiz","saveResponse","ASSISTANT","stringify","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","textContent","max","headerLineLength","lineSeparationSize","reduce","jointure","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","filter","correctInput","mouseover","click","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","controller","AbortController","timeoutControler","abort","contentHandler","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","innerHTML","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","moodleGPT","Error","code","codeListener"],"mappings":"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","x_google_ignoreList":[1]} \ No newline at end of file diff --git a/src/utils/html-table-to-string.ts b/src/utils/html-table-to-string.ts index 507e794..6578181 100644 --- a/src/utils/html-table-to-string.ts +++ b/src/utils/html-table-to-string.ts @@ -7,6 +7,7 @@ function htmlTableToString(table: HTMLTableElement) { const tab: string[][] = []; const lines = Array.from(table.querySelectorAll('tr')); const maxColumnsLength: number[] = []; + lines.map(line => { const cells = Array.from(line.querySelectorAll('td, th')); const cellsContent = cells.map((cell, index) => { @@ -17,7 +18,10 @@ function htmlTableToString(table: HTMLTableElement) { tab.push(cellsContent); }); - const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1; + const jointure = ' | '; + const headerLineLength = tab[0].length; + const lineSeparationSize = + maxColumnsLength.reduce((a, b) => a + b, 0) + (headerLineLength - 1) * jointure.length; const lineSeparation = '\n' + Array(lineSeparationSize).fill('-').join('') + '\n'; const mappedTab = tab.map(line => { @@ -27,9 +31,11 @@ function htmlTableToString(table: HTMLTableElement) { '\u00A0' // For no matching with \s ) ); - return '| ' + mappedLine.join(' | ') + ' |'; + return mappedLine.join(jointure); }); + const head = mappedTab.shift(); + return head + lineSeparation + mappedTab.join('\n'); } From 55e26fc7c9d18d3c4b6d6844a805111bc53f645d Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:50:45 -0400 Subject: [PATCH 84/87] table asset --- README.md | 10 ++++++---- assets/table.gif | Bin 0 -> 70775 bytes 2 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 assets/table.gif diff --git a/README.md b/README.md index 5303513..1a5318d 100644 --- a/README.md +++ b/README.md @@ -103,12 +103,14 @@ Go to "Manage my extensions" on your browser, then click on "Load unpa Table are formated from the question to make it more readable for CHAT-GPT. Example of formatted table output: ``` -| id | name | birthDate | cars | ----------------------------------------- -| Person 1 | Yvick | 15/08/1999 | yes | -| Person 2 | Yann | 19/01/2000 | no | +id       | name  | birthDate  | cars +------------------------------------ +Person 1 | Yvick | 15/08/1999 | yes  +Person 2 | Yann  | 19/01/2000 | no ``` +![Table](./assets/table.gif) + ## Supported questions type ### Select diff --git a/assets/table.gif b/assets/table.gif new file mode 100644 index 0000000000000000000000000000000000000000..f26bf2db5fb75e16c46d8b7bd3626b4aea0dd0a1 GIT binary patch literal 70775 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%0A|)&^b7P8eo(U$x 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 literal 0 HcmV?d00001 From 32370b8bbcbcaec2916ed8a6568e9d02db20322a Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 21 Mar 2024 19:53:22 -0400 Subject: [PATCH 85/87] Update TODO.md --- TODO.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/TODO.md b/TODO.md index cc99596..4640904 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1 @@ # TODO - -- Do some tests From bda60ce81324c822f1048225416ae66dabcc8557 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 21 Mar 2024 19:57:38 -0400 Subject: [PATCH 86/87] fixed table css --- test/fake-moodle/css/style.css | 10 +++++----- test/fake-moodle/index.html | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/fake-moodle/css/style.css b/test/fake-moodle/css/style.css index db51b89..0a36ffc 100644 --- a/test/fake-moodle/css/style.css +++ b/test/fake-moodle/css/style.css @@ -70,23 +70,23 @@ img { height: 5rem; } -table { +.style-table { width: 100%; border-collapse: collapse; margin-bottom: 20px; } -th, -td { +.style-table th, +.style-table td { border: 1px solid #ddd; padding: 8px; text-align: left; } -th { +.style-table th { background-color: #f2f2f2; } -tr:nth-child(even) { +.style-table tr:nth-child(even) { background-color: #f2f2f2; } diff --git a/test/fake-moodle/index.html b/test/fake-moodle/index.html index aedbc03..6053122 100644 --- a/test/fake-moodle/index.html +++ b/test/fake-moodle/index.html @@ -273,7 +273,7 @@

Give me the id of the personn who have a car

- +
From 4ee6b6a74578b2a07e3170a20e2a316be0649102 Mon Sep 17 00:00:00 2001 From: yoannchb-pro <71560747+yoannchb-pro@users.noreply.github.com> Date: Thu, 21 Mar 2024 20:04:19 -0400 Subject: [PATCH 87/87] fixing assets size --- webstore-assets/v2/banner2.png | Bin 259412 -> 78313 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/webstore-assets/v2/banner2.png b/webstore-assets/v2/banner2.png index 39b7405540b541e8636f997ab4d59fdff6487ba2..b160a720e76b568820698b0f306f079acd7b4c94 100644 GIT binary patch literal 78313 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�(?l(=XMt>U7n*6`tKHoGYDaI$0RP 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%0DHjTx9Re5eoBiBP6g2x%~JI9m)hw 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 >`jqrY!rnzQg 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

6EY9B` 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 a^Y=E+wCPTQBw8-okbJ!SHx_#AJMjnPeJ&LM

id

|J(Rl4Da3)deG6queuWy(#T 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 literal 219082 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 emsEQ8PR^_WZoaOp#*W_3&K@Rrue!Madocument.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: explenation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={url:null,system:{role:s.SYSTEM,content:c},history:[]};function u(e,t,o){return n(this,void 0,void 0,(function*(){const n=t.querySelectorAll("img");if(e.includeImages&&function(e){const n=e.match(/gpt-(\d+)/);return!!(null==n?void 0:n[1])&&Number(n[1])>=4}(e.model)&&0===n.length)return o;let r=[];const i=Array.from(n).map((e=>{return n=e,new Promise(((e,t)=>{const o=document.createElement("canvas"),r=o.getContext("2d");if(!r)return void e(null);const i=new Image;i.crossOrigin="Anonymous",i.onload=()=>{o.width=i.width,o.height=i.height,r.drawImage(i,0,0);const n=o.toDataURL("image/png");e(n)},i.onerror=e=>{t(e)},i.src=n.src}));var n})),s=(yield Promise.all(i)).filter((e=>null!==e));for(const e of s)r.push({type:l.IMAGE,image_url:{url:e}});return r.length>0?r.push({type:l.TEXT,text:o}):r=o,r}))}function f(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function m(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function d(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function p(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function h(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function g(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function v(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function y(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function w(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+f(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),l=yield function(e,t,o){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&a.url===n||(a.url=n,a.history=[]);const r=new AbortController,l=setTimeout((()=>r.abort()),2e4),c=yield u(e,t,o),f={role:s.USER,content:c},m=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?r.signal:null,body:JSON.stringify({model:e.model,messages:[a.system,...a.history,f],temperature:.1,top_p:1,presence_penalty:0,max_tokens:2e3,stop:[".","!","?"]})});clearTimeout(l);const d=(yield m.json()).choices[0].message.content;return e.history&&(a.history.push(f),a.history.push({role:s.ASSISTANT,content:d})),{question:o,response:d,normalizedResponse:i(d)}}))}(e.config,e.questionElement,t).catch((e=>({error:e}))),c="object"==typeof l&&"error"in l;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||c?"pointer":"initial"),c)console.error(l.error);else switch(e.config.logs&&(r.question(t),r.response(l)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),m(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:l,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:l,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[d,y,p,v,h,g];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;m(e.config,e.gptAnswer)}({config:e.config,gptAnswer:l,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const A=[],E=[];function x(e){const n=E.findIndex((n=>n.element===e));if(-1!==n){const e=E.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function S(n){if(E.length>0){for(const e of E)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(E.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=w.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>x(o)});E.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){A.push(n.key),A.length>e.code.length&&A.shift(),A.join("")===e.code&&(A.length=0,S(e))}))}(n):S(n)}))})); +!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){"use strict";function e(e){const n=document.title;document.title=e,setTimeout((()=>document.title=n),3e3)}function n(e,n,t,o){return new(t||(t=Promise))((function(r,i){function s(e){try{c(o.next(e))}catch(e){i(e)}}function l(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var n;e.done?r(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(s,l)}c((o=o.apply(e,n||[])).next())}))}function t(e,n){const t=e.length>n.length?e.length:n.length;return 0===t?1:(t-function(e,n){if(0===e.length)return n.length;if(0===n.length)return e.length;const t=[],o=e.replace(/\s+/,""),r=n.replace(/\s+/,"");for(let e=0;e<=o.length;++e){t.push([e]);for(let n=1;n<=r.length;++n)t[e][n]=0===e?n:Math.min(t[e-1][n]+1,t[e][n-1]+1,t[e-1][n-1]+(o[e-1]===r[n-1]?0:1))}return t[o.length][r.length]}(e,n))/t}function o(e,n){let o={element:null,similarity:0,value:null};for(const r of n){const n=t(r.value,e);if(1===n)return{element:r.element,value:r.value,similarity:n};n>o.similarity&&(o={element:r.element,value:r.value,similarity:n})}return o}"function"==typeof SuppressedError&&SuppressedError;class r{static question(e){console.log("%c[QUESTION]: %s","color: cyan",e)}static bestAnswer(e,n){console.log("%c[BEST ANSWER]: %s","color: green",`"${e}" with a similarity of ${function(e){return Math.round(100*e*100)/100+"%"}(n)}`)}static array(e){console.log("[CORRECTS] ",e)}static response(e){console.log("Original:\n"+e.response),console.log("Normalized:\n"+e.normalizedResponse)}}function i(e,n=!0){n&&(e=e.toLowerCase());return e.replace(/\n+/gi,"\n").replace(/(\n\s*\n)+/g,"\n").replace(/[ \t]+/gi," ").trim().replace(/^[a-z\d]\.\s/gi,"").replace(/\n[a-z\d]\.\s/gi,"\n")}var s,l;!function(e){e.SYSTEM="system",e.USER="user",e.ASSISTANT="assistant"}(s||(s={})),function(e){e.TEXT="text",e.IMAGE="image_url"}(l||(l={}));const c="\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: \nexplanation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...'\n- Always reply in the format: '\n\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n".trim(),a={url:null,system:{role:s.SYSTEM,content:c},history:[]};function u(e,t,o){return n(this,void 0,void 0,(function*(){const n=t.querySelectorAll("img");if(e.includeImages&&function(e){const n=e.match(/gpt-(\d+)/);return!!(null==n?void 0:n[1])&&Number(n[1])>=4}(e.model)&&0===n.length)return o;let r=[];const i=Array.from(n).map((e=>{return n=e,new Promise((e=>{const t=document.createElement("canvas"),o=t.getContext("2d");if(!o)return e(null),void t.remove();const r=new Image;r.crossOrigin="Anonymous",r.onload=()=>{t.width=r.width,t.height=r.height,o.drawImage(r,0,0);const n=t.toDataURL("image/png");e(n),t.remove()},r.onerror=()=>{e(null),t.remove()},r.src=n.src}));var n})),s=(yield Promise.all(i)).filter((e=>null!==e));for(const e of s)r.push({type:l.IMAGE,image_url:{url:e}});return r.length>0?r.push({type:l.TEXT,text:o}):r=o,r}))}function f(e){const n=[],t=Array.from(e.querySelectorAll("tr")),o=[];t.map((e=>{const t=Array.from(e.querySelectorAll("td, th")).map(((e,n)=>{var t;const r=null===(t=e.textContent)||void 0===t?void 0:t.trim();return o[n]=Math.max(o[n]||0,(null==r?void 0:r.length)||0),null!=r?r:""}));n.push(t)}));const r=o.reduce(((e,n)=>e+n))+3*n[0].length+1,i="\n"+Array(r).fill("-").join("")+"\n",s=n.map((e=>"| "+e.map(((e,n)=>e.padEnd(o[n]," "))).join(" | ")+" |"));return s.shift()+i+s.join("\n")}function m(n,t){n.title&&e("Copied to clipboard"),navigator.clipboard.writeText(t.response)}function d(e,n,t){const o=n[0];if(1!==n.length||"true"!==o.getAttribute("contenteditable"))return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){if("Backspace"===n.key&&(e=t.response.length+1),e>t.response.length)return;n.preventDefault(),o.textContent=t.response.slice(0,++e),o.focus();const r=document.createRange();r.selectNodeContents(o),r.collapse(!1);const i=window.getSelection();null!==i&&(i.removeAllRanges(),i.addRange(r))}))}else o.textContent=t.response;return!0}function p(e,n,t){var o,r;const i=n[0];if(1!==n.length||"number"!==i.type)return!1;const s=null===(r=null===(o=t.normalizedResponse.match(/\d+([,.]\d+)?/gi))||void 0===o?void 0:o[0])||void 0===r?void 0:r.replace(",",".");if(void 0===s)return!1;if(e.typing){let e=0;i.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=s.length+1),e>s.length||("."===s.slice(e,e+1)&&++e,i.value=s.slice(0,++e))}))}else i.value=s;return!0}function h(e,n,t){const s=null==n?void 0:n[0];if(!s||"radio"!==s.type)return!1;const l=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value)),c=o(t.normalizedResponse,l);e.logs&&c.value&&r.bestAnswer(c.value,c.similarity);const a=c.element;return e.mouseover?a.addEventListener("mouseover",(()=>a.checked=!0),{once:!0}):a.checked=!0,!0}function g(e,n,t){const s=null==n?void 0:n[0];if(!s||"checkbox"!==s.type)return!1;const l=t.normalizedResponse.split("\n"),c=Array.from(n).map((e=>{var n,t;return{element:e,value:i(null!==(t=null===(n=null==e?void 0:e.parentElement)||void 0===n?void 0:n.textContent)&&void 0!==t?t:"")}})).filter((e=>""!==e.value));for(const n of l){const t=o(n,c);e.logs&&t.value&&r.bestAnswer(t.value,t.similarity);const i=t.element;e.mouseover?i.addEventListener("mouseover",(()=>i.checked=!0),{once:!0}):i.checked=!0}return!0}function v(e,n,t){if(0===n.length||"SELECT"!==n[0].tagName)return!1;const s=t.normalizedResponse.split("\n");e.logs&&r.array(s);for(let t=0;t{var n;return{element:e,value:i(null!==(n=e.textContent)&&void 0!==n?n:"")}})).filter((e=>""!==e.value)),a=o(s[t],c);e.logs&&a.value&&r.bestAnswer(a.value,a.similarity);const u=a.element,f=u.closest("select");null!==f&&(e.mouseover?f.addEventListener("click",(()=>u.selected=!0),{once:!0}):u.selected=!0)}return!0}function y(e,n,t){const o=n[0];if(1!==n.length||"TEXTAREA"!==o.tagName&&"text"!==o.type)return!1;if(e.typing){let e=0;o.addEventListener("keydown",(function(n){n.preventDefault(),"Backspace"===n.key&&(e=t.response.length+1),e>t.response.length||(o.value=t.response.slice(0,++e))}))}else o.value=t.response;return!0}function w(e){return n(this,void 0,void 0,(function*(){e.config.cursor&&(e.questionElement.style.cursor="wait");const t=function(e){let n=e.innerText;const t=e.querySelectorAll(".accesshide");for(const e of t)n=n.replace(e.innerText,"");const o=e.querySelectorAll(".qtext table");for(const e of o)n=n.replace(e.innerText,"\n"+f(e)+"\n");return i(n,!1)}(e.form),o=e.form.querySelectorAll(e.inputQuery),l=yield function(e,t,o){return n(this,void 0,void 0,(function*(){const n=location.hostname+location.pathname;e.history&&a.url===n||(a.url=n,a.history=[]);const r=new AbortController,l=setTimeout((()=>r.abort()),2e4),c=yield u(e,t,o),f={role:s.USER,content:c},m=yield fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.apiKey}`},signal:e.timeout?r.signal:null,body:JSON.stringify({model:e.model,messages:[a.system,...a.history,f],temperature:.1,top_p:1,presence_penalty:0,max_tokens:2e3})});clearTimeout(l);const d=(yield m.json()).choices[0].message.content;return e.history&&(a.history.push(f),a.history.push({role:s.ASSISTANT,content:d})),{question:o,response:d,normalizedResponse:i(d)}}))}(e.config,e.questionElement,t).catch((e=>({error:e}))),c="object"==typeof l&&"error"in l;if(e.config.cursor&&(e.questionElement.style.cursor=e.config.infinite||c?"pointer":"initial"),c)console.error(l.error);else switch(e.config.logs&&(r.question(t),r.response(l)),e.config.mode){case"clipboard":!function(e){e.config.infinite||e.removeListener(),m(e.config,e.gptAnswer)}({config:e.config,questionElement:e.questionElement,gptAnswer:l,removeListener:e.removeListener});break;case"question-to-answer":!function(e){const n=e.questionElement;e.removeListener();const t=n.textContent;n.textContent=e.gptAnswer.response,n.style.whiteSpace="pre-wrap";let o=!0;n.addEventListener("click",(function(){n.style.whiteSpace=o?"":"pre-warp",n.textContent=o?t:e.gptAnswer.response,o=!o}))}({gptAnswer:l,questionElement:e.questionElement,removeListener:e.removeListener});break;case"autocomplete":!function(e){e.config.infinite||e.removeListener();const n=[d,y,p,v,h,g];for(const t of n)if(t(e.config,e.inputList,e.gptAnswer))return;m(e.config,e.gptAnswer)}({config:e.config,gptAnswer:l,inputList:o,questionElement:e.questionElement,removeListener:e.removeListener})}}))}const A=[],E=[];function x(e){const n=E.findIndex((n=>n.element===e));if(-1!==n){const e=E.splice(n,1)[0];e.element.removeEventListener("click",e.fn)}}function S(n){if(E.length>0){for(const e of E)n.cursor&&(e.element.style.cursor="initial"),e.element.removeEventListener("click",e.fn);return n.title&&e("Removed"),void(E.length=0)}const t=["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");if(null===o)continue;n.cursor&&(o.style.cursor="pointer");const r=w.bind(null,{config:n,questionElement:o,form:e,inputQuery:t,removeListener:()=>x(o)});E.push({element:o,fn:r}),o.addEventListener("click",r)}n.title&&e("Injected")}chrome.storage.sync.get(["moodleGPT"]).then((function(e){const n=e.moodleGPT;if(!n)throw new Error("Please configure MoodleGPT into the extension");n.code?function(e){document.body.addEventListener("keydown",(function(n){A.push(n.key),A.length>e.code.length&&A.shift(),A.join("")===e.code&&(A.length=0,S(e))}))}(n):S(n)}))})); //# sourceMappingURL=MoodleGPT.js.map diff --git a/extension/MoodleGPT.js.map b/extension/MoodleGPT.js.map index 7edee76..ecf9c7e 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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/core/get-response.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport imageToBase64 from '@utils/image-to-base64';\nimport normalizeText from '@utils/normalize-text';\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\n\ntype Content =\n | string\n | Array<\n | {\n type: CONTENT_TYPE.TEXT;\n text: string;\n }\n | {\n type: CONTENT_TYPE.IMAGE;\n image_url: { url: string };\n }\n >;\n\ntype History = {\n url: string | null;\n system: { role: ROLE; content: Content };\n history: { role: ROLE; content: Content }[];\n};\n\nenum ROLE {\n SYSTEM = 'system',\n USER = 'user',\n ASSISTANT = 'assistant'\n}\n\nenum CONTENT_TYPE {\n TEXT = 'text',\n IMAGE = 'image_url'\n}\n\nconst INSTRUCTION: string = `\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: explenation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\n- Always reply in the format: '\\n\\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n`.trim();\n\nconst history: History = {\n url: null,\n system: {\n role: ROLE.SYSTEM,\n content: INSTRUCTION\n },\n history: []\n};\n\n/**\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\n * @param config\n */\nasync function getContent(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const imagesElements = questionElement.querySelectorAll('img');\n\n if (\n config.includeImages &&\n isGPTModelGreaterOrEqualTo4(config.model) &&\n imagesElements.length === 0\n ) {\n return question;\n }\n\n let content: Content = [];\n\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\n const results = await Promise.all(base64Images);\n const filteredResults = results.filter(value => value !== null) as string[];\n\n for (const result of filteredResults) {\n content.push({\n type: CONTENT_TYPE.IMAGE,\n image_url: { url: result }\n });\n }\n\n if (content.length > 0) {\n content.push({\n type: CONTENT_TYPE.TEXT,\n text: question\n });\n } else {\n content = question;\n }\n\n return content;\n}\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const URL = location.hostname + location.pathname;\n\n // We reset the history when we enter a new moodle quiz or when it's desactivate\n if (!config.history || history.url !== URL) {\n history.url = URL;\n history.history = [];\n }\n\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n const content = await getContent(config, questionElement, question);\n const message = { role: ROLE.USER, content };\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: [history.system, ...history.history, message],\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 1, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000, // Maximum length of the response\n stop: ['.', '!', '?'] // Stop on the ponctuation to do not cut the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Register the conversation\n if (config.history) {\n history.history.push(message);\n history.history.push({ role: ROLE.ASSISTANT, content: response });\n }\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement): Promise {\r\n return new Promise((resolve, reject) => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n resolve(null);\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png');\r\n resolve(base64);\r\n };\r\n img.onerror = error => {\r\n reject(error);\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","history","url","system","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","base64Images","Array","from","map","imgEl","imageToBase64","imageElement","canvas","createElement","ctx","getContext","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","error","src","filteredResults","all","filter","type","IMAGE","image_url","TEXT","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","_b","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","messages","temperature","top_p","presence_penalty","max_tokens","stop","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"2FAIA,SAASA,EAAiBC,GACxB,MAAMC,EAAYC,SAASC,MAC3BD,SAASC,MAAQH,EACjBI,YAAW,IAAOF,SAASC,MAAQF,GAAY,IACjD,CC0GO,SAASI,EAAUC,EAASC,EAAYC,EAAGC,GAE9C,OAAO,IAAKD,IAAMA,EAAIE,WAAU,SAAUC,EAASC,GAC/C,SAASC,EAAUC,GAAS,IAAMC,EAAKN,EAAUO,KAAKF,GAAQ,CAAG,MAAOG,GAAKL,EAAOK,GAAO,CAC3F,SAASC,EAASJ,GAAS,IAAMC,EAAKN,EAAiB,MAAEK,GAAU,CAAC,MAAOG,GAAKL,EAAOK,GAAO,CAC9F,SAASF,EAAKI,GAJlB,IAAeL,EAIaK,EAAOC,KAAOT,EAAQQ,EAAOL,QAJ1CA,EAIyDK,EAAOL,MAJhDA,aAAiBN,EAAIM,EAAQ,IAAIN,GAAE,SAAUG,GAAWA,EAAQG,EAAO,KAIhBO,KAAKR,EAAWK,EAAY,CAC9GH,GAAMN,EAAYA,EAAUa,MAAMhB,EAASC,GAAc,KAAKS,OACtE,GACA,CCzEA,SAASO,EAAmBC,EAAcC,GACxC,MAAMC,EAAeF,EAAKG,OAASF,EAAKE,OAASH,EAAKG,OAASF,EAAKE,OACpE,OAAqB,IAAjBD,EAA2B,GACvBA,EAlCV,SAA6BF,EAAcC,GACzC,GAAoB,IAAhBD,EAAKG,OAAc,OAAOF,EAAKE,OACnC,GAAoB,IAAhBF,EAAKE,OAAc,OAAOH,EAAKG,OAEnC,MAAMC,EAAqB,GACrBC,EAAoBL,EAAKM,QAAQ,MAAO,IACxCC,EAAoBN,EAAKK,QAAQ,MAAO,IAE9C,IAAK,IAAIE,EAAI,EAAGA,GAAKH,EAAkBF,SAAUK,EAAG,CAClDJ,EAAOK,KAAK,CAACD,IACb,IAAK,IAAIE,EAAI,EAAGA,GAAKH,EAAkBJ,SAAUO,EAC/CN,EAAOI,GAAGE,GACF,IAANF,EACIE,EACAC,KAAKC,IACHR,EAAOI,EAAI,GAAGE,GAAK,EACnBN,EAAOI,GAAGE,EAAI,GAAK,EACnBN,EAAOI,EAAI,GAAGE,EAAI,IAAML,EAAkBG,EAAI,KAAOD,EAAkBG,EAAI,GAAK,EAAI,GAG/F,CAED,OAAON,EAAOC,EAAkBF,QAAQI,EAAkBJ,OAC5D,CAWyBU,CAAoBb,EAAMC,IAASC,CAC5D,CAQgB,SAAAY,EACdC,EACAC,GAEA,IAAIC,EAA6B,CAC/BC,QAAS,KACTC,WAAY,EACZ7B,MAAO,MAET,IAAK,MAAM8B,KAAOJ,EAAK,CACrB,MAAMG,EAAapB,EAAmBqB,EAAI9B,MAAOyB,GACjD,GAAmB,IAAfI,EACF,MAAO,CAAED,QAASE,EAAIF,QAAS5B,MAAO8B,EAAI9B,MAAO6B,cAE/CA,EAAaF,EAAaE,aAC5BF,EAAe,CAAEC,QAASE,EAAIF,QAAS5B,MAAO8B,EAAI9B,MAAO6B,cAE5D,CACD,OAAOF,CACT,CD2OkD,mBAApBI,iBAAiCA,gBExT/D,MAAMC,EACJ,eAAOC,CAAS/C,GAEdgD,QAAQC,IAAI,mBADA,cACyBjD,EACtC,CAED,iBAAOkD,CAAWX,EAAgBI,GAEhCK,QAAQC,IACN,sBAFU,eAIV,IAAIV,2BDiGJ,SAAwBI,GAC5B,OAAOR,KAAKgB,MAAmB,IAAbR,EAAmB,KAAO,IAAM,GACpD,CCnG0CS,CAAcT,KAErD,CAED,YAAOU,CAAMb,GACXQ,QAAQC,IAAI,cAAeT,EAC5B,CAED,eAAOc,CAASC,GACdP,QAAQC,IAAI,cAAgBM,EAAUD,UACtCN,QAAQC,IAAI,gBAAkBM,EAAUC,mBACzC,ECrBH,SAASC,EAAczD,EAAc0D,GAAuB,GACtDA,IAAa1D,EAAOA,EAAK0D,eAW7B,OATuB1D,EACpB8B,QAAQ,QAAS,MACjBA,QAAQ,cAAe,MACvBA,QAAQ,WAAY,KACpB6B,OAEA7B,QAAQ,iBAAkB,IAC1BA,QAAQ,kBAAmB,KAGhC,CCQA,IAAK8B,EAMAC,GANL,SAAKD,GACHA,EAAA,OAAA,SACAA,EAAA,KAAA,OACAA,EAAA,UAAA,WACD,CAJD,CAAKA,IAAAA,EAIJ,CAAA,IAED,SAAKC,GACHA,EAAA,KAAA,OACAA,EAAA,MAAA,WACD,CAHD,CAAKA,IAAAA,EAGJ,CAAA,IAED,MAAMC,EAAsB,q+BAY1BH,OAEII,EAAmB,CACvBC,IAAK,KACLC,OAAQ,CACNC,KAAMN,EAAKO,OACXC,QAASN,GAEXC,QAAS,IAOX,SAAeM,EACbC,EACAC,EACAxB,4CAEA,MAAMyB,EAAiBD,EAAgBE,iBAAiB,OAExD,GACEH,EAAOI,eClEX,SAAqCC,GACnC,MAAMC,EAAgBD,EAAQE,MAAM,aACpC,SAAKD,aAAa,EAAbA,EAAgB,KAGdE,OAAOF,EAAc,KAAO,CACrC,CD6DIG,CAA4BT,EAAOU,QACT,IAA1BR,EAAe7C,OAEf,OAAOoB,EAGT,IAAIqB,EAAmB,GAEvB,MAAMa,EAAeC,MAAMC,KAAKX,GAAgBY,KAAIC,IAASC,OE3ExCC,EF2EsDF,EE1EpE,IAAI3E,SAAQ,CAACC,EAASC,KAC3B,MAAM4E,EAAStF,SAASuF,cAAc,UAChCC,EAAMF,EAAOG,WAAW,MAE9B,IAAKD,EAEH,YADA/E,EAAQ,MAIV,MAAMiF,EAAM,IAAIC,MAChBD,EAAIE,YAAc,YAClBF,EAAIG,OAAS,KACXP,EAAOQ,MAAQJ,EAAII,MACnBR,EAAOS,OAASL,EAAIK,OACpBP,EAAIQ,UAAUN,EAAK,EAAG,GAEtB,MAAMO,EAASX,EAAOY,UAAU,aAChCzF,EAAQwF,EAAO,EAEjBP,EAAIS,QAAUC,IACZ1F,EAAO0F,EAAM,EAGfV,EAAIW,IAAMhB,EAAagB,GAAG,IAxB9B,IAAuBhB,CF2E4D,IAE3EiB,SADgB9F,QAAQ+F,IAAIxB,IACFyB,QAAO5F,GAAmB,OAAVA,IAEhD,IAAK,MAAMK,KAAUqF,EACnBpC,EAAQnC,KAAK,CACX0E,KAAM9C,EAAa+C,MACnBC,UAAW,CAAE7C,IAAK7C,KAatB,OATIiD,EAAQzC,OAAS,EACnByC,EAAQnC,KAAK,CACX0E,KAAM9C,EAAaiD,KACnB9G,KAAM+C,IAGRqB,EAAUrB,EAGLqB,IACR,CGhGD,SAAS2C,EAAkBC,GACzB,MAAMC,EAAkB,GAClBC,EAAQhC,MAAMC,KAAK6B,EAAMvC,iBAAiB,OAC1C0C,EAA6B,GACnCD,EAAM9B,KAAIgC,IACR,MACMC,EADQnC,MAAMC,KAAKiC,EAAK3C,iBAAiB,WACpBW,KAAI,CAACkC,EAAMC,WACpC,MAAMnD,EAA0B,QAAhBoD,EAAAF,EAAKG,mBAAW,IAAAD,OAAA,EAAAA,EAAE7D,OAElC,OADAwD,EAAiBI,GAASpF,KAAKuF,IAAIP,EAAiBI,IAAU,GAAGnD,aAAO,EAAPA,EAASzC,SAAU,GAC7EyC,QAAAA,EAAW,EAAE,IAEtB6C,EAAIhF,KAAKoF,EAAa,IAGxB,MAAMM,EAAqBR,EAAiBS,QAAO,CAACC,EAAGC,IAAMD,EAAIC,IAAqB,EAAhBb,EAAI,GAAGtF,OAAa,EACpFoG,EAAiB,KAAO7C,MAAMyC,GAAoBK,KAAK,KAAKC,KAAK,IAAM,KAEvEC,EAAYjB,EAAI7B,KAAIgC,GAOjB,KANYA,EAAKhC,KAAI,CAAChB,EAASmD,IACpCnD,EAAQ+D,OACNhB,EAAiBI,GACjB,OAGqBU,KAAK,OAAS,OAGzC,OADaC,EAAUE,QACTL,EAAiBG,EAAUD,KAAK,KAChD,CCxBA,SAASI,EAAgB/D,EAAgBf,GACnCe,EAAOnE,OAAOJ,EAAiB,uBACnCuI,UAAUC,UAAUC,UAAUjF,EAAUD,SAC1C,CCFA,SAASmF,EACPnE,EACAoE,EACAnF,GAEA,MAAMoF,EAAQD,EAAU,GAExB,GACuB,IAArBA,EAAU/G,QACgC,SAA1CgH,EAAMC,aAAa,mBAEnB,OAAO,EAGT,GAAItE,EAAOuE,OAAQ,CACjB,IAAItB,EAAQ,EACZoB,EAAMG,iBAAiB,WAAW,SAAUC,GAE1C,GADkB,cAAdA,EAAMC,MAAqBzB,EAAQhE,EAAUD,SAAS3B,OAAS,GAC/D4F,EAAQhE,EAAUD,SAAS3B,OAAQ,OACvCoH,EAAME,iBACNN,EAAMlB,YAAclE,EAAUD,SAAS4F,MAAM,IAAK3B,GAGlDoB,EAAMQ,QACN,MAAMC,EAAQlJ,SAASmJ,cACvBD,EAAME,mBAAmBX,GACzBS,EAAMG,UAAS,GACf,MAAMC,EAAYC,OAAOC,eACP,OAAdF,IACFA,EAAUG,kBACVH,EAAUI,SAASR,GAEvB,GACD,MACCT,EAAMlB,YAAclE,EAAUD,SAGhC,OAAO,CACT,CCtCA,SAASuG,EACPvF,EACAoE,EACAnF,WAEA,MAAMoF,EAAQD,EAAU,GAExB,GACuB,IAArBA,EAAU/G,QACK,WAAfgH,EAAMhC,KAEN,OAAO,EAGT,MAAMmD,EAAqE,QAA5DC,EAAwD,QAAxDvC,EAAAjE,EAAUC,mBAAmBqB,MAAM,0BAAqB,IAAA2C,OAAA,EAAAA,EAAA,UAAI,IAAAuC,OAAA,EAAAA,EAAAjI,QAAQ,IAAK,KAExF,QAAekI,IAAXF,EAAsB,OAAO,EAEjC,GAAIxF,EAAOuE,OAAQ,CACjB,IAAItB,EAAQ,EACZoB,EAAMG,iBAAiB,WAAW,SAAUC,GAC1CA,EAAME,iBAC6B,cAAfF,EAAOC,MAAqBzB,EAAQuC,EAAOnI,OAAS,GACpE4F,EAAQuC,EAAOnI,SACoB,MAAnCmI,EAAOZ,MAAM3B,EAAOA,EAAQ,MAAcA,EAC9CoB,EAAM7H,MAAQgJ,EAAOZ,MAAM,IAAK3B,GAClC,GACD,MACCoB,EAAM7H,MAAQgJ,EAGhB,OAAO,CACT,CC9BA,SAASG,EACP3F,EACAoE,EACAnF,GAEA,MAAM2G,EAAaxB,eAAAA,EAAY,GAG/B,IAAKwB,GAAkC,UAApBA,EAAWvD,KAC5B,OAAO,EAGT,MAAMwD,EAAkBjF,MAAMC,KAAKuD,GAChCtD,KAAIgF,YAAO,MAAC,CACX1H,QAAS0H,EACTtJ,MAAO2C,EAA6C,QAA/BsG,EAAkB,QAAlBvC,EAAA4C,aAAA,EAAAA,EAAKC,qBAAa,IAAA7C,OAAA,EAAAA,EAAEC,mBAAW,IAAAsC,EAAAA,EAAI,IACxD,IACDrD,QAAO9D,GAAqB,KAAdA,EAAI9B,QAEfoC,EAAaZ,EAAgBiB,EAAUC,mBAAoB2G,GAE7D7F,EAAOgG,MAAQpH,EAAWpC,OAC5BgC,EAAKI,WAAWA,EAAWpC,MAAOoC,EAAWP,YAG/C,MAAM4H,EAAerH,EAAWR,QAShC,OARI4B,EAAOkG,UACTD,EAAazB,iBAAiB,aAAa,IAAOyB,EAAaE,SAAU,GAAO,CAC9EC,MAAM,IAGRH,EAAaE,SAAU,GAGlB,CACT,CCnCA,SAASE,EACPrG,EACAoE,EACAnF,GAEA,MAAM2G,EAAaxB,eAAAA,EAAY,GAG/B,IAAKwB,GAAkC,aAApBA,EAAWvD,KAC5B,OAAO,EAGT,MAAMiE,EAAWrH,EAAUC,mBAAmBqH,MAAM,MAE9CV,EAAkBjF,MAAMC,KAAKuD,GAChCtD,KAAIgF,YAAO,MAAC,CACX1H,QAAS0H,EACTtJ,MAAO2C,EAA6C,QAA/BsG,EAAkB,QAAlBvC,EAAA4C,aAAA,EAAAA,EAAKC,qBAAa,IAAA7C,OAAA,EAAAA,EAAEC,mBAAW,IAAAsC,EAAAA,EAAI,IACxD,IACDrD,QAAO9D,GAAqB,KAAdA,EAAI9B,QAErB,IAAK,MAAMgK,KAAWF,EAAU,CAC9B,MAAM1H,EAAaZ,EAAgBwI,EAASX,GAExC7F,EAAOgG,MAAQpH,EAAWpC,OAC5BgC,EAAKI,WAAWA,EAAWpC,MAAOoC,EAAWP,YAG/C,MAAM4H,EAAerH,EAAWR,QAC5B4B,EAAOkG,UACTD,EAAazB,iBAAiB,aAAa,IAAOyB,EAAaE,SAAU,GAAO,CAC9EC,MAAM,IAGRH,EAAaE,SAAU,CAE1B,CAED,OAAO,CACT,CCtCA,SAASM,EACPzG,EACAoE,EACAnF,GAEA,GAAyB,IAArBmF,EAAU/G,QAAyC,WAAzB+G,EAAU,GAAGsC,QAAsB,OAAO,EAExE,MAAMJ,EAAWrH,EAAUC,mBAAmBqH,MAAM,MAEhDvG,EAAOgG,MAAMxH,EAAKO,MAAMuH,GAE5B,IAAK,IAAI5I,EAAI,EAAGA,EAAI0G,EAAU/G,QACvBiJ,EAAS5I,KADwBA,EAAG,CAGzC,MAAMiJ,EAAUvC,EAAU1G,GAAGyC,iBAAiB,UAExC0F,EAAkBjF,MAAMC,KAAK8F,GAChC7F,KAAI8F,UAAO,MAAC,CACXxI,QAASwI,EACTpK,MAAO2C,EAAiC,QAAnB+D,EAAA0D,EAAIzD,mBAAe,IAAAD,EAAAA,EAAA,IACxC,IACDd,QAAO9D,GAAqB,KAAdA,EAAI9B,QAEfoC,EAAaZ,EAAgBsI,EAAS5I,GAAImI,GAE5C7F,EAAOgG,MAAQpH,EAAWpC,OAC5BgC,EAAKI,WAAWA,EAAWpC,MAAOoC,EAAWP,YAG/C,MAAMwI,EAAgBjI,EAAWR,QAC3B0I,EAAgBD,EAAcE,QAAQ,UAEtB,OAAlBD,IAEA9G,EAAOkG,UACTY,EAActC,iBAAiB,SAAS,IAAOqC,EAAcG,UAAW,GAAO,CAC7EZ,MAAM,IAGRS,EAAcG,UAAW,EAE5B,CAED,OAAO,CACT,CC/CA,SAASC,EACPjH,EACAoE,EACAnF,GAEA,MAAMoF,EAAQD,EAAU,GAExB,GACuB,IAArBA,EAAU/G,QACS,aAAlBgH,EAAMqC,SAAyC,SAAfrC,EAAMhC,KAEvC,OAAO,EAGT,GAAIrC,EAAOuE,OAAQ,CACjB,IAAItB,EAAQ,EACZoB,EAAMG,iBAAiB,WAAW,SAAUC,GAC1CA,EAAME,iBAC6B,cAAfF,EAAOC,MACzBzB,EAAQhE,EAAUD,SAAS3B,OAAS,GAElC4F,EAAQhE,EAAUD,SAAS3B,SAC/BgH,EAAM7H,MAAQyC,EAAUD,SAAS4F,MAAM,IAAK3B,GAC9C,GACD,MACCoB,EAAM7H,MAAQyC,EAAUD,SAG1B,OAAO,CACT,CClBA,SAAekI,EAAMC,4CACfA,EAAMnH,OAAOoH,SAAQD,EAAMlH,gBAAgBoH,MAAMD,OAAS,QAE9D,MAAM3I,ECfR,SAAoC6I,GAClC,IAAI7I,EAAW6I,EAAkBC,UAGjC,MAAMC,EACJF,EAAkBnH,iBAAiB,eACrC,IAAK,MAAMsH,KAAWD,EACpB/I,EAAWA,EAASjB,QAAQiK,EAAQF,UAAW,IAIjD,MAAMG,EAAuCJ,EAAkBnH,iBAAiB,gBAChF,IAAK,MAAMuC,KAASgF,EAClBjJ,EAAWA,EAASjB,QAAQkF,EAAM6E,UAAW,KAAO9E,EAAkBC,GAAS,MAGjF,OAAOvD,EAAcV,GAAU,EACjC,CDFmBkJ,CAA2BR,EAAMS,MAC5CxD,EAAqC+C,EAAMS,KAAKzH,iBAAiBgH,EAAMU,YAEvE5I,QXkFR,SACEe,EACAC,EACAxB,4CAEA,MAAMqJ,EAAMC,SAASC,SAAWD,SAASE,SAGpCjI,EAAOP,SAAWA,EAAQC,MAAQoI,IACrCrI,EAAQC,IAAMoI,EACdrI,EAAQA,QAAU,IAGpB,MAAMyI,EAAa,IAAIC,gBACjBC,EAAmBtM,YAAW,IAAMoM,EAAWG,SAAS,KAExDvI,QAAgBC,EAAWC,EAAQC,EAAiBxB,GACpD6J,EAAU,CAAE1I,KAAMN,EAAKiJ,KAAMzI,WAE7B0I,QAAYC,MAAM,6CAA8C,CACpEC,OAAQ,OACRC,QAAS,CACP,eAAgB,mBAChBC,cAAe,UAAU5I,EAAO6I,UAElCC,OAAQ9I,EAAO+I,QAAUb,EAAWY,OAAS,KAC7CE,KAAMC,KAAKC,UAAU,CACnBxI,MAAOV,EAAOU,MACdyI,SAAU,CAAC1J,EAAQE,UAAWF,EAAQA,QAAS6I,GAE/Cc,YAAa,GACbC,MAAO,EACPC,iBAAkB,EAClBC,WAAY,IACZC,KAAM,CAAC,IAAK,IAAK,SAIrBC,aAAarB,GAEb,MACMpJ,SADYwJ,EAAIkB,QACDC,QAAQ,GAAGrB,QAAQxI,QAQxC,OALIE,EAAOP,UACTA,EAAQA,QAAQ9B,KAAK2K,GACrB7I,EAAQA,QAAQ9B,KAAK,CAAEiC,KAAMN,EAAKsK,UAAW9J,QAASd,KAGjD,CACLP,WACAO,WACAE,mBAAoBC,EAAcH,MAErC,CWxIyB6K,CAAmB1C,EAAMnH,OAAQmH,EAAMlH,gBAAiBxB,GAAUqL,OACxF9H,IAAU,CACRA,YAIE+H,EAAiC,iBAAd9K,GAA0B,UAAWA,EAM9D,GAJIkI,EAAMnH,OAAOoH,SACfD,EAAMlH,gBAAgBoH,MAAMD,OAASD,EAAMnH,OAAOgK,UAAYD,EAAY,UAAY,WAGpFA,EACFrL,QAAQsD,MAAM/C,EAAU+C,YAS1B,OALImF,EAAMnH,OAAOgG,OACfxH,EAAKC,SAASA,GACdD,EAAKQ,SAASC,IAGRkI,EAAMnH,OAAOiK,MACnB,IAAK,aElCT,SAAuB9C,GAChBA,EAAMnH,OAAOgK,UAAU7C,EAAM+C,iBAClCnG,EAAgBoD,EAAMnH,OAAQmH,EAAMlI,UACtC,CFgCMkL,CAAc,CACZnK,OAAQmH,EAAMnH,OACdC,gBAAiBkH,EAAMlH,gBACvBhB,YACAiL,eAAgB/C,EAAM+C,iBAExB,MACF,IAAK,sBG7CT,SAA8B/C,GAC5B,MAAMlH,EAAkBkH,EAAMlH,gBAE9BkH,EAAM+C,iBAEN,MAAME,EAAiBnK,EAAgBkD,YAEvClD,EAAgBkD,YAAcgE,EAAMlI,UAAUD,SAG9CiB,EAAgBoH,MAAMgD,WAAa,WAGnC,IAAIC,GAAoB,EACxBrK,EAAgBuE,iBAAiB,SAAS,WACxCvE,EAAgBoH,MAAMgD,WAAaC,EAAoB,GAAK,WAC5DrK,EAAgBkD,YAAcmH,EAAoBF,EAAiBjD,EAAMlI,UAAUD,SAEnFsL,GAAqBA,CACvB,GACF,CH0BMC,CAAqB,CACnBtL,YACAgB,gBAAiBkH,EAAMlH,gBACvBiK,eAAgB/C,EAAM+C,iBAExB,MACF,IAAK,gBIzCT,SAA0B/C,GACnBA,EAAMnH,OAAOgK,UAAU7C,EAAM+C,iBAElC,MAAMM,EAAW,CACfrG,EACA8C,EACA1B,EACAkB,EACAd,EACAU,GAGF,IAAK,MAAMoE,KAAWD,EACpB,GAAIC,EAAQtD,EAAMnH,OAAQmH,EAAM/C,UAAW+C,EAAMlI,WAAY,OAI/D8E,EAAgBoD,EAAMnH,OAAQmH,EAAMlI,UACtC,CJwBMyL,CAAiB,CACf1K,OAAQmH,EAAMnH,OACdf,YACAmF,YACAnE,gBAAiBkH,EAAMlH,gBACvBiK,eAAgB/C,EAAM+C,oBAI7B,CKlED,MAAMS,EAAwB,GACxBC,EAAwB,GAqB9B,SAASV,EAAe9L,GACtB,MAAM6E,EAAQ2H,EAAUC,WAAUC,GAAYA,EAAS1M,UAAYA,IACnE,IAAe,IAAX6E,EAAc,CAChB,MAAM6H,EAAWF,EAAUG,OAAO9H,EAAO,GAAG,GAC5C6H,EAAS1M,QAAQ4M,oBAAoB,QAASF,EAASG,GACxD,CACH,CAOA,SAASC,EAAelL,GAEtB,GAAI4K,EAAUvN,OAAS,EAAG,CACxB,IAAK,MAAMyN,KAAYF,EACjB5K,EAAOoH,SAAQ0D,EAAS1M,QAAQiJ,MAAMD,OAAS,WACnD0D,EAAS1M,QAAQ4M,oBAAoB,QAASF,EAASG,IAIzD,OAFIjL,EAAOnE,OAAOJ,EAAiB,gBACnCmP,EAAUvN,OAAS,EAEpB,CAGD,MAGMwK,EAHiB,CAAC,WAAY,QAAS,OAAQ,UAClD/G,KAAInE,GAAK,eAAeA,QACxBgH,KAAK,KAC4B,wCAC9BwH,EAAQvP,SAASuE,iBAAiB,gBAGxC,IAAK,MAAMyH,KAAQuD,EAAO,CACxB,MAAMlL,EAAsC2H,EAAKwD,cAAc,UAE/D,GAAwB,OAApBnL,EAA0B,SAE1BD,EAAOoH,SAAQnH,EAAgBoH,MAAMD,OAAS,WAElD,MAAMiE,EAAoBnE,EAAMoE,KAAK,KAAM,CACzCtL,SACAC,kBACA2H,KAAMA,EACNC,aACAqC,eAAgB,IAAMA,EAAejK,KAGvC2K,EAAUjN,KAAK,CAAES,QAAS6B,EAAiBgL,GAAII,IAC/CpL,EAAgBuE,iBAAiB,QAAS6G,EAC3C,CAEGrL,EAAOnE,OAAOJ,EAAiB,WACrC,CCjFA8P,OAAOC,QAAQC,KAAKC,IAAI,CAAC,cAAc3O,MAAK,SAAUyO,GACpD,MAAMxL,EAAiBwL,EAAQG,UAE/B,IAAK3L,EAAQ,MAAM,IAAI4L,MAAM,iDAEzB5L,EAAO6L,KDQb,SAAsB7L,GACpBpE,SAASoN,KAAKxE,iBAAiB,WAAW,SAAUC,GAClDkG,EAAYhN,KAAK8G,EAAMC,KACnBiG,EAAYtN,OAAS2C,EAAO6L,KAAMxO,QAAQsN,EAAY7G,QACtD6G,EAAYhH,KAAK,MAAQ3D,EAAO6L,OAClClB,EAAYtN,OAAS,EACrB6N,EAAelL,GAEnB,GACF,CChBI8L,CAAa9L,GAEbkL,EAAelL,EAEnB","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/pick-best-response.ts","../src/utils/logs.ts","../src/utils/normalize-text.ts","../src/core/get-response.ts","../src/utils/version-support-images.ts","../src/utils/image-to-base64.ts","../src/utils/html-table-to-string.ts","../src/core/questions/clipboard.ts","../src/core/questions/contenteditable.ts","../src/core/questions/number.ts","../src/core/questions/radio.ts","../src/core/questions/checkbox.ts","../src/core/questions/select.ts","../src/core/questions/textbox.ts","../src/core/reply.ts","../src/core/create-question.ts","../src/core/modes/clipboard.ts","../src/core/modes/question-to-answer.ts","../src/core/modes/autocomplete.ts","../src/core/code-listener.ts","../src/index.ts"],"sourcesContent":["/**\n * Show some informations into the document title and remove it after 3000ms\n * @param text\n */\nfunction titleIndications(text: string) {\n const backTitle = document.title;\n document.title = text;\n setTimeout(() => (document.title = backTitle), 3000);\n}\n\nexport default titleIndications;\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, SuppressedError, Symbol */\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.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\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\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n function next() {\r\n while (env.stack.length) {\r\n var rec = env.stack.pop();\r\n try {\r\n var result = rec.dispose && rec.dispose.call(rec.value);\r\n if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n};\r\n","type BestResponse = {\n similarity: number;\n value: string | null;\n element: HTMLElement | null;\n};\n\ntype ResponsesBySimilarity = {\n similarity: number;\n value: string;\n element: HTMLElement;\n};\n\n/**\n * Calculate the levenshtein distance between two sentence\n * @param str1\n * @param str2\n * @returns\n */\nfunction levenshteinDistance(str1: string, str2: string) {\n if (str1.length === 0) return str2.length;\n if (str2.length === 0) return str1.length;\n\n const matrix: number[][] = [];\n const str1WithoutSpaces = str1.replace(/\\s+/, '');\n const str2WithoutSpaces = str2.replace(/\\s+/, '');\n\n for (let i = 0; i <= str1WithoutSpaces.length; ++i) {\n matrix.push([i]);\n for (let j = 1; j <= str2WithoutSpaces.length; ++j) {\n matrix[i][j] =\n i === 0\n ? j\n : Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + (str1WithoutSpaces[i - 1] === str2WithoutSpaces[j - 1] ? 0 : 1)\n );\n }\n }\n\n return matrix[str1WithoutSpaces.length][str2WithoutSpaces.length];\n}\n\n/**\n * Calculate the similarity between two sentences from 0 to 1 (best)\n * @param str1\n * @param str2\n * @returns\n */\nfunction sentenceSimilarity(str1: string, str2: string) {\n const longerLength = str1.length > str2.length ? str1.length : str2.length;\n if (longerLength === 0) return 1;\n return (longerLength - levenshteinDistance(str1, str2)) / longerLength;\n}\n\n/**\n * Pick the best sentence that correspond to the answer\n * @param arr\n * @param answer\n * @returns\n */\nexport function pickBestReponse(\n answer: string,\n arr: { element: HTMLElement; value: string }[]\n): BestResponse {\n let bestResponse: BestResponse = {\n element: null,\n similarity: 0,\n value: null\n };\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity === 1) {\n return { element: obj.element, value: obj.value, similarity };\n }\n if (similarity > bestResponse.similarity) {\n bestResponse = { element: obj.element, value: obj.value, similarity };\n }\n }\n return bestResponse;\n}\n\n/**\n * Return the sentences sorted by score with a score superior or equal to what is asked\n * @param answer\n * @param arr\n * @param score\n * @returns\n */\nexport function pickResponsesWithSimilarityGreaterThan(\n answer: string,\n arr: { element: HTMLElement; value: string }[],\n score: number\n): ResponsesBySimilarity[] {\n const responses: ResponsesBySimilarity[] = [];\n for (const obj of arr) {\n const similarity = sentenceSimilarity(obj.value, answer);\n if (similarity >= score)\n responses.push({\n similarity,\n value: obj.value,\n element: obj.element\n });\n }\n return responses.sort((a, b) => a.similarity - b.similarity);\n}\n\n/**\n * Convert a number to a readable string pourcentage\n * @param similarity\n */\nexport function toPourcentage(similarity: number): string {\n return Math.round(similarity * 100 * 100) / 100 + '%';\n}\n","import GPTAnswer from '@typing/gptAnswer';\nimport { toPourcentage } from './pick-best-response';\n\nclass Logs {\n static question(text: string) {\n const css = 'color: cyan';\n console.log('%c[QUESTION]: %s', css, text);\n }\n\n static bestAnswer(answer: string, similarity: number) {\n const css = 'color: green';\n console.log(\n '%c[BEST ANSWER]: %s',\n css,\n `\"${answer}\" with a similarity of ${toPourcentage(similarity)}`\n );\n }\n\n static array(arr: unknown[]) {\n console.log('[CORRECTS] ', arr);\n }\n\n static response(gptAnswer: GPTAnswer) {\n console.log('Original:\\n' + gptAnswer.response);\n console.log('Normalized:\\n' + gptAnswer.normalizedResponse);\n }\n}\n\nexport default Logs;\n","/**\n * Normlize text\n * @param text\n */\nfunction normalizeText(text: string, toLowerCase: boolean = true) {\n if (toLowerCase) text = text.toLowerCase();\n\n const normalizedText = text\n .replace(/\\n+/gi, '\\n') //remove duplicate new lines\n .replace(/(\\n\\s*\\n)+/g, '\\n') //remove useless white space from textcontent\n .replace(/[ \\t]+/gi, ' ') //replace multiples space or tabs by a space\n .trim()\n // We remove the following content because sometimes ChatGPT will reply: \"answer d\"\n .replace(/^[a-z\\d]\\.\\s/gi, '') //a. text, b. text, c. text, 1. text, 2. text, 3.text\n .replace(/\\n[a-z\\d]\\.\\s/gi, '\\n'); //same but with new line\n\n return normalizedText;\n}\n\nexport default normalizeText;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport imageToBase64 from '@utils/image-to-base64';\nimport normalizeText from '@utils/normalize-text';\nimport isGPTModelGreaterOrEqualTo4 from '@utils/version-support-images';\n\ntype Content =\n | string\n | Array<\n | {\n type: CONTENT_TYPE.TEXT;\n text: string;\n }\n | {\n type: CONTENT_TYPE.IMAGE;\n image_url: { url: string };\n }\n >;\n\ntype History = {\n url: string | null;\n system: { role: ROLE; content: Content };\n history: { role: ROLE; content: Content }[];\n};\n\nenum ROLE {\n SYSTEM = 'system',\n USER = 'user',\n ASSISTANT = 'assistant'\n}\n\nenum CONTENT_TYPE {\n TEXT = 'text',\n IMAGE = 'image_url'\n}\n\nconst INSTRUCTION: string = `\nAct as a quiz solver for the best notation with the following rules:\n- If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. \n But for the calculation provide this format 'result: \\nexplanation: '\n- For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\\n3\\n2') and ignore other rules.- Always reply in this format: '\\n\\n...'\n- Always reply in the format: '\\n\\n...'.\n- Retain only the correct answer(s).\n- Maintain the same order for the answers as in the text.\n- Retain all text from the answer with its description, content or definition.\n- Only provide answers that exactly match the given answer in the text.\n- The question always has the correct answer(s), so you should always provide an answer.\n- Always respond in the same language as the user's question.\n`.trim();\n\nconst history: History = {\n url: null,\n system: {\n role: ROLE.SYSTEM,\n content: INSTRUCTION\n },\n history: []\n};\n\n/**\n * Get the content to send to ChatGPT API (it allows to includes images if supported)\n * @param config\n */\nasync function getContent(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const imagesElements = questionElement.querySelectorAll('img');\n\n if (\n config.includeImages &&\n isGPTModelGreaterOrEqualTo4(config.model) &&\n imagesElements.length === 0\n ) {\n return question;\n }\n\n let content: Content = [];\n\n const base64Images = Array.from(imagesElements).map(imgEl => imageToBase64(imgEl));\n const results = await Promise.all(base64Images);\n const filteredResults = results.filter(value => value !== null) as string[];\n\n for (const result of filteredResults) {\n content.push({\n type: CONTENT_TYPE.IMAGE,\n image_url: { url: result }\n });\n }\n\n if (content.length > 0) {\n content.push({\n type: CONTENT_TYPE.TEXT,\n text: question\n });\n } else {\n content = question;\n }\n\n return content;\n}\n\n/**\n * Get the response from chatGPT api\n * @param config\n * @param question\n * @returns\n */\nasync function getChatGPTResponse(\n config: Config,\n questionElement: HTMLElement,\n question: string\n): Promise {\n const URL = location.hostname + location.pathname;\n\n // We reset the history when we enter a new moodle quiz or when it's desactivate\n if (!config.history || history.url !== URL) {\n history.url = URL;\n history.history = [];\n }\n\n const controller = new AbortController();\n const timeoutControler = setTimeout(() => controller.abort(), 20 * 1000);\n\n const content = await getContent(config, questionElement, question);\n const message = { role: ROLE.USER, content };\n\n const req = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`\n },\n signal: config.timeout ? controller.signal : null,\n body: JSON.stringify({\n model: config.model,\n messages: [history.system, ...history.history, message],\n\n temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity.\n top_p: 1, // Determines the diversity of the generated responses\n presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text.\n max_tokens: 2000 // Maximum length of the response\n })\n });\n\n clearTimeout(timeoutControler);\n\n const rep = await req.json();\n const response = rep.choices[0].message.content;\n\n // Register the conversation\n if (config.history) {\n history.history.push(message);\n history.history.push({ role: ROLE.ASSISTANT, content: response });\n }\n\n return {\n question,\n response,\n normalizedResponse: normalizeText(response)\n };\n}\n\nexport default getChatGPTResponse;\n","/**\r\n * Check if the current ChatGPT version is greater or equal to 4\r\n * @param version\r\n * @returns\r\n */\r\nfunction isGPTModelGreaterOrEqualTo4(version: string): boolean {\r\n const versionNumber = version.match(/gpt-(\\d+)/);\r\n if (!versionNumber?.[1]) {\r\n return false;\r\n }\r\n return Number(versionNumber[1]) >= 4;\r\n}\r\n\r\nexport default isGPTModelGreaterOrEqualTo4;\r\n","/**\r\n * Convert an image html element into a base64 image string\r\n * @param imageElement\r\n * @returns\r\n */\r\nfunction imageToBase64(imageElement: HTMLImageElement): Promise {\r\n return new Promise(resolve => {\r\n const canvas = document.createElement('canvas');\r\n const ctx = canvas.getContext('2d');\r\n\r\n if (!ctx) {\r\n resolve(null);\r\n canvas.remove();\r\n return;\r\n }\r\n\r\n const img = new Image();\r\n img.crossOrigin = 'Anonymous';\r\n img.onload = () => {\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n ctx.drawImage(img, 0, 0);\r\n\r\n const base64 = canvas.toDataURL('image/png');\r\n resolve(base64);\r\n\r\n canvas.remove();\r\n };\r\n\r\n img.onerror = () => {\r\n resolve(null);\r\n canvas.remove();\r\n };\r\n\r\n img.src = imageElement.src;\r\n });\r\n}\r\n\r\nexport default imageToBase64;\r\n","/**\n * Convert table to representating string table\n * @param table\n * @returns\n */\nfunction htmlTableToString(table: HTMLTableElement) {\n const tab: string[][] = [];\n const lines = Array.from(table.querySelectorAll('tr'));\n const maxColumnsLength: number[] = [];\n lines.map(line => {\n const cells = Array.from(line.querySelectorAll('td, th'));\n const cellsContent = cells.map((cell, index) => {\n const content = cell.textContent?.trim();\n maxColumnsLength[index] = Math.max(maxColumnsLength[index] || 0, content?.length || 0);\n return content ?? '';\n });\n tab.push(cellsContent);\n });\n\n const lineSeparationSize = maxColumnsLength.reduce((a, b) => a + b) + tab[0].length * 3 + 1;\n const lineSeparation = '\\n' + Array(lineSeparationSize).fill('-').join('') + '\\n';\n\n const mappedTab = tab.map(line => {\n const mappedLine = line.map((content, index) =>\n content.padEnd(\n maxColumnsLength[index],\n '\\u00A0' // For no matching with \\s\n )\n );\n return '| ' + mappedLine.join(' | ') + ' |';\n });\n const head = mappedTab.shift();\n return head + lineSeparation + mappedTab.join('\\n');\n}\n\nexport default htmlTableToString;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport titleIndications from '@utils/title-indications';\n\n/**\n * Copy the response in the clipboard if we can automaticaly fill the question\n * @param config\n * @param gptAnswer\n */\nfunction handleClipboard(config: Config, gptAnswer: GPTAnswer) {\n if (config.title) titleIndications('Copied to clipboard');\n navigator.clipboard.writeText(gptAnswer.response);\n}\n\nexport default handleClipboard;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Hanlde contenteditable elements\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleContentEditable(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0];\n\n if (\n inputList.length !== 1 || // for now we don't handle many input for editable textcontent\n input.getAttribute('contenteditable') !== 'true'\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: KeyboardEvent) {\n if (event.key === 'Backspace') index = gptAnswer.response.length + 1;\n if (index > gptAnswer.response.length) return;\n event.preventDefault();\n input.textContent = gptAnswer.response.slice(0, ++index);\n\n // Put the cursor at the end of the typed text\n input.focus();\n const range = document.createRange();\n range.selectNodeContents(input);\n range.collapse(false);\n const selection = window.getSelection();\n if (selection !== null) {\n selection.removeAllRanges();\n selection.addRange(range);\n }\n });\n } else {\n input.textContent = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleContentEditable;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle number input\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleNumber(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input number\n input.type !== 'number'\n ) {\n return false;\n }\n\n const number = gptAnswer.normalizedResponse.match(/\\d+([,.]\\d+)?/gi)?.[0]?.replace(',', '.');\n\n if (number === undefined) return false;\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') index = number.length + 1;\n if (index > number.length) return;\n if (number.slice(index, index + 1) === '.') ++index;\n input.value = number.slice(0, ++index);\n });\n } else {\n input.value = number;\n }\n\n return true;\n}\n\nexport default handleNumber;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input radio elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleRadio(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a radio\n if (!firstInput || firstInput.type !== 'radio') {\n return false;\n }\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(gptAnswer.normalizedResponse, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n\n return true;\n}\n\nexport default handleRadio;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle input checkbox elements\n * @param config\n * @param inputList\n * @param gptAnswer\n */\nfunction handleCheckbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const firstInput = inputList?.[0] as HTMLInputElement;\n\n // Handle the case the input is not a checkbox\n if (!firstInput || firstInput.type !== 'checkbox') {\n return false;\n }\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n const possibleAnswers = Array.from(inputList)\n .map(inp => ({\n element: inp,\n value: normalizeText(inp?.parentElement?.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n for (const correct of corrects) {\n const bestAnswer = pickBestReponse(correct, possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctInput = bestAnswer.element as HTMLInputElement;\n if (config.mouseover) {\n correctInput.addEventListener('mouseover', () => (correctInput.checked = true), {\n once: true\n });\n } else {\n correctInput.checked = true;\n }\n }\n\n return true;\n}\n\nexport default handleCheckbox;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport Logs from '@utils/logs';\nimport normalizeText from '@utils/normalize-text';\nimport { pickBestReponse } from '@utils/pick-best-response';\n\n/**\n * Handle select elements (and put in order select)\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleSelect(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n if (inputList.length === 0 || inputList[0].tagName !== 'SELECT') return false;\n\n const corrects = gptAnswer.normalizedResponse.split('\\n');\n\n if (config.logs) Logs.array(corrects);\n\n for (let i = 0; i < inputList.length; ++i) {\n if (!corrects[i]) break;\n\n const options = inputList[i].querySelectorAll('option');\n\n const possibleAnswers = Array.from(options)\n .map(opt => ({\n element: opt,\n value: normalizeText(opt.textContent ?? '')\n }))\n .filter(obj => obj.value !== '');\n\n const bestAnswer = pickBestReponse(corrects[i], possibleAnswers);\n\n if (config.logs && bestAnswer.value) {\n Logs.bestAnswer(bestAnswer.value, bestAnswer.similarity);\n }\n\n const correctOption = bestAnswer.element as HTMLOptionElement;\n const currentSelect = correctOption.closest('select');\n\n if (currentSelect === null) continue;\n\n if (config.mouseover) {\n currentSelect.addEventListener('click', () => (correctOption.selected = true), {\n once: true\n });\n } else {\n correctOption.selected = true;\n }\n }\n\n return true;\n}\n\nexport default handleSelect;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\n\n/**\n * Handle textbox\n * @param config\n * @param inputList\n * @param gptAnswer\n * @returns\n */\nfunction handleTextbox(\n config: Config,\n inputList: NodeListOf,\n gptAnswer: GPTAnswer\n): boolean {\n const input = inputList[0] as HTMLInputElement | HTMLTextAreaElement;\n\n if (\n inputList.length !== 1 || // for now we don't handle many input text\n (input.tagName !== 'TEXTAREA' && input.type !== 'text')\n ) {\n return false;\n }\n\n if (config.typing) {\n let index = 0;\n input.addEventListener('keydown', function (event: Event) {\n event.preventDefault();\n if ((event).key === 'Backspace') {\n index = gptAnswer.response.length + 1;\n }\n if (index > gptAnswer.response.length) return;\n input.value = gptAnswer.response.slice(0, ++index);\n });\n } else {\n input.value = gptAnswer.response;\n }\n\n return true;\n}\n\nexport default handleTextbox;\n","import type Config from '@typing/config';\nimport Logs from '@utils/logs';\nimport getChatGPTResponse from './get-response';\nimport createAndNormalizeQuestion from './create-question';\nimport clipboardMode from './modes/clipboard';\nimport questionToAnswerMode from './modes/question-to-answer';\nimport autoCompleteMode from './modes/autocomplete';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n form: HTMLElement;\n inputQuery: string;\n removeListener: () => void;\n};\n\n/**\n * Reply to the question\n * @param props\n * @returns\n */\nasync function reply(props: Props): Promise {\n if (props.config.cursor) props.questionElement.style.cursor = 'wait';\n\n const question = createAndNormalizeQuestion(props.form);\n const inputList: NodeListOf = props.form.querySelectorAll(props.inputQuery);\n\n const gptAnswer = await getChatGPTResponse(props.config, props.questionElement, question).catch(\n error => ({\n error\n })\n );\n\n const haveError = typeof gptAnswer === 'object' && 'error' in gptAnswer;\n\n if (props.config.cursor) {\n props.questionElement.style.cursor = props.config.infinite || haveError ? 'pointer' : 'initial';\n }\n\n if (haveError) {\n console.error(gptAnswer.error);\n return;\n }\n\n if (props.config.logs) {\n Logs.question(question);\n Logs.response(gptAnswer);\n }\n\n switch (props.config.mode) {\n case 'clipboard':\n clipboardMode({\n config: props.config,\n questionElement: props.questionElement,\n gptAnswer,\n removeListener: props.removeListener\n });\n break;\n case 'question-to-answer':\n questionToAnswerMode({\n gptAnswer,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n case 'autocomplete':\n autoCompleteMode({\n config: props.config,\n gptAnswer,\n inputList,\n questionElement: props.questionElement,\n removeListener: props.removeListener\n });\n break;\n }\n}\n\nexport default reply;\n","import normalizeText from '@utils/normalize-text';\nimport htmlTableToString from '@utils/html-table-to-string';\n\n/**\n * Normalize the question as text and add sub informations\n * @param langage\n * @param question\n * @returns\n */\nfunction createAndNormalizeQuestion(questionContainer: HTMLElement) {\n let question = questionContainer.innerText;\n\n // We remove unnecessary information\n const accesshideElements: NodeListOf =\n questionContainer.querySelectorAll('.accesshide');\n for (const useless of accesshideElements) {\n question = question.replace(useless.innerText, '');\n }\n\n // Make tables more readable for chat-gpt\n const tables: NodeListOf = questionContainer.querySelectorAll('.qtext table');\n for (const table of tables) {\n question = question.replace(table.innerText, '\\n' + htmlTableToString(table) + '\\n');\n }\n\n return normalizeText(question, false);\n}\n\nexport default createAndNormalizeQuestion;\n","import type Config from '@typing/config';\nimport type GPTAnswer from '@typing/gptAnswer';\nimport handleClipboard from '@core/questions/clipboard';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Clipboard mode:\n * Simply copy the answer into the clipboard\n * @param props\n */\nfunction clipboardMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default clipboardMode;\n","import type GPTAnswer from '@typing/gptAnswer';\n\ntype Props = {\n questionElement: HTMLElement;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Question to answer mode:\n * Simply turn the question into the answer by clicking on it\n * @param props\n */\nfunction questionToAnswerMode(props: Props) {\n const questionElement = props.questionElement;\n\n props.removeListener();\n\n const questionBackup = questionElement.textContent;\n\n questionElement.textContent = props.gptAnswer.response;\n\n // Format the content\n questionElement.style.whiteSpace = 'pre-wrap';\n\n // To go back to the question / answer\n let contentIsResponse = true;\n questionElement.addEventListener('click', function () {\n questionElement.style.whiteSpace = contentIsResponse ? '' : 'pre-warp';\n questionElement.textContent = contentIsResponse ? questionBackup : props.gptAnswer.response;\n\n contentIsResponse = !contentIsResponse;\n });\n}\n\nexport default questionToAnswerMode;\n","import type GPTAnswer from '@typing/gptAnswer';\nimport type Config from '@typing/config';\nimport handleClipboard from '@core/questions/clipboard';\nimport handleContentEditable from '@core/questions/contenteditable';\nimport handleNumber from '@core/questions/number';\nimport handleRadio from '@core/questions/radio';\nimport handleCheckbox from '@core/questions/checkbox';\nimport handleSelect from '@core/questions/select';\nimport handleTextbox from '@core/questions/textbox';\n\ntype Props = {\n config: Config;\n questionElement: HTMLElement;\n inputList: NodeListOf;\n gptAnswer: GPTAnswer;\n removeListener: () => void;\n};\n\n/**\n * Autocomplete mode:\n * Autocomplete the question by checking the good answer\n * @param props\n * @returns\n */\nfunction autoCompleteMode(props: Props) {\n if (!props.config.infinite) props.removeListener();\n\n const handlers = [\n handleContentEditable,\n handleTextbox,\n handleNumber,\n handleSelect,\n handleRadio,\n handleCheckbox\n ];\n\n for (const handler of handlers) {\n if (handler(props.config, props.inputList, props.gptAnswer)) return;\n }\n\n // In the case we can't auto complete the question\n handleClipboard(props.config, props.gptAnswer);\n}\n\nexport default autoCompleteMode;\n","import type Config from '@typing/config';\nimport titleIndications from '@utils/title-indications';\nimport reply from './reply';\n\ntype Listener = {\n element: HTMLElement;\n fn: (this: HTMLElement, ev: MouseEvent) => void;\n};\n\nconst pressedKeys: string[] = [];\nconst listeners: Listener[] = [];\n\n/**\n * Create a listener on the keyboard to inject the code\n * @param config\n */\nfunction codeListener(config: Config) {\n document.body.addEventListener('keydown', function (event) {\n pressedKeys.push(event.key);\n if (pressedKeys.length > config.code!.length) pressedKeys.shift();\n if (pressedKeys.join('') === config.code) {\n pressedKeys.length = 0;\n setUpMoodleGpt(config);\n }\n });\n}\n\n/**\n * Remove the event listener on a specific question\n * @param element\n */\nfunction removeListener(element: HTMLElement) {\n const index = listeners.findIndex(listener => listener.element === element);\n if (index !== -1) {\n const listener = listeners.splice(index, 1)[0];\n listener.element.removeEventListener('click', listener.fn);\n }\n}\n\n/**\n * Setup moodleGPT into the page (remove/injection)\n * @param config\n * @returns\n */\nfunction setUpMoodleGpt(config: Config) {\n // Removing events if there are already declared\n if (listeners.length > 0) {\n for (const listener of listeners) {\n if (config.cursor) listener.element.style.cursor = 'initial';\n listener.element.removeEventListener('click', listener.fn);\n }\n if (config.title) titleIndications('Removed');\n listeners.length = 0;\n return;\n }\n\n // Query to find inputs and forms\n const inputTypeQuery = ['checkbox', 'radio', 'text', 'number']\n .map(e => `input[type=\"${e}\"]`)\n .join(',');\n const inputQuery = inputTypeQuery + ', textarea, select, [contenteditable]';\n const forms = document.querySelectorAll('.formulation');\n\n // For each form we inject a function on the queqtion\n for (const form of forms) {\n const questionElement: HTMLElement | null = form.querySelector('.qtext');\n\n if (questionElement === null) continue;\n\n if (config.cursor) questionElement.style.cursor = 'pointer';\n\n const injectionFunction = reply.bind(null, {\n config,\n questionElement,\n form: form as HTMLElement,\n inputQuery,\n removeListener: () => removeListener(questionElement)\n });\n\n listeners.push({ element: questionElement, fn: injectionFunction });\n questionElement.addEventListener('click', injectionFunction);\n }\n\n if (config.title) titleIndications('Injected');\n}\n\nexport { codeListener, removeListener, setUpMoodleGpt };\n","import type Config from '@typing/config';\nimport { codeListener, setUpMoodleGpt } from './core/code-listener';\n\nchrome.storage.sync.get(['moodleGPT']).then(function (storage) {\n const config: Config = storage.moodleGPT;\n\n if (!config) throw new Error('Please configure MoodleGPT into the extension');\n\n if (config.code) {\n codeListener(config);\n } else {\n setUpMoodleGpt(config);\n }\n});\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","sentenceSimilarity","str1","str2","longerLength","length","matrix","str1WithoutSpaces","replace","str2WithoutSpaces","i","push","j","Math","min","levenshteinDistance","pickBestReponse","answer","arr","bestResponse","element","similarity","obj","SuppressedError","Logs","question","console","log","bestAnswer","round","toPourcentage","array","response","gptAnswer","normalizedResponse","normalizeText","toLowerCase","trim","ROLE","CONTENT_TYPE","INSTRUCTION","history","url","system","role","SYSTEM","content","getContent","config","questionElement","imagesElements","querySelectorAll","includeImages","version","versionNumber","match","Number","isGPTModelGreaterOrEqualTo4","model","base64Images","Array","from","map","imgEl","imageToBase64","imageElement","canvas","createElement","ctx","getContext","remove","img","Image","crossOrigin","onload","width","height","drawImage","base64","toDataURL","onerror","src","filteredResults","all","filter","type","IMAGE","image_url","TEXT","htmlTableToString","table","tab","lines","maxColumnsLength","line","cellsContent","cell","index","_a","textContent","max","lineSeparationSize","reduce","a","b","lineSeparation","fill","join","mappedTab","padEnd","shift","handleClipboard","navigator","clipboard","writeText","handleContentEditable","inputList","input","getAttribute","typing","addEventListener","event","key","preventDefault","slice","focus","range","createRange","selectNodeContents","collapse","selection","window","getSelection","removeAllRanges","addRange","handleNumber","number","_b","undefined","handleRadio","firstInput","possibleAnswers","inp","parentElement","logs","correctInput","mouseover","checked","once","handleCheckbox","corrects","split","correct","handleSelect","tagName","options","opt","correctOption","currentSelect","closest","selected","handleTextbox","reply","props","cursor","style","questionContainer","innerText","accesshideElements","useless","tables","createAndNormalizeQuestion","form","inputQuery","URL","location","hostname","pathname","controller","AbortController","timeoutControler","abort","message","USER","req","fetch","method","headers","Authorization","apiKey","signal","timeout","body","JSON","stringify","messages","temperature","top_p","presence_penalty","max_tokens","clearTimeout","json","choices","ASSISTANT","getChatGPTResponse","catch","error","haveError","infinite","mode","removeListener","clipboardMode","questionBackup","whiteSpace","contentIsResponse","questionToAnswerMode","handlers","handler","autoCompleteMode","pressedKeys","listeners","findIndex","listener","splice","removeEventListener","fn","setUpMoodleGpt","forms","querySelector","injectionFunction","bind","chrome","storage","sync","get","moodleGPT","Error","code","codeListener"],"mappings":"2FAIA,SAASA,EAAiBC,GACxB,MAAMC,EAAYC,SAASC,MAC3BD,SAASC,MAAQH,EACjBI,YAAW,IAAOF,SAASC,MAAQF,GAAY,IACjD,CC0GO,SAASI,EAAUC,EAASC,EAAYC,EAAGC,GAE9C,OAAO,IAAKD,IAAMA,EAAIE,WAAU,SAAUC,EAASC,GAC/C,SAASC,EAAUC,GAAS,IAAMC,EAAKN,EAAUO,KAAKF,GAAQ,CAAG,MAAOG,GAAKL,EAAOK,GAAO,CAC3F,SAASC,EAASJ,GAAS,IAAMC,EAAKN,EAAiB,MAAEK,GAAU,CAAC,MAAOG,GAAKL,EAAOK,GAAO,CAC9F,SAASF,EAAKI,GAJlB,IAAeL,EAIaK,EAAOC,KAAOT,EAAQQ,EAAOL,QAJ1CA,EAIyDK,EAAOL,MAJhDA,aAAiBN,EAAIM,EAAQ,IAAIN,GAAE,SAAUG,GAAWA,EAAQG,EAAO,KAIhBO,KAAKR,EAAWK,EAAY,CAC9GH,GAAMN,EAAYA,EAAUa,MAAMhB,EAASC,GAAc,KAAKS,OACtE,GACA,CCzEA,SAASO,EAAmBC,EAAcC,GACxC,MAAMC,EAAeF,EAAKG,OAASF,EAAKE,OAASH,EAAKG,OAASF,EAAKE,OACpE,OAAqB,IAAjBD,EAA2B,GACvBA,EAlCV,SAA6BF,EAAcC,GACzC,GAAoB,IAAhBD,EAAKG,OAAc,OAAOF,EAAKE,OACnC,GAAoB,IAAhBF,EAAKE,OAAc,OAAOH,EAAKG,OAEnC,MAAMC,EAAqB,GACrBC,EAAoBL,EAAKM,QAAQ,MAAO,IACxCC,EAAoBN,EAAKK,QAAQ,MAAO,IAE9C,IAAK,IAAIE,EAAI,EAAGA,GAAKH,EAAkBF,SAAUK,EAAG,CAClDJ,EAAOK,KAAK,CAACD,IACb,IAAK,IAAIE,EAAI,EAAGA,GAAKH,EAAkBJ,SAAUO,EAC/CN,EAAOI,GAAGE,GACF,IAANF,EACIE,EACAC,KAAKC,IACHR,EAAOI,EAAI,GAAGE,GAAK,EACnBN,EAAOI,GAAGE,EAAI,GAAK,EACnBN,EAAOI,EAAI,GAAGE,EAAI,IAAML,EAAkBG,EAAI,KAAOD,EAAkBG,EAAI,GAAK,EAAI,GAG/F,CAED,OAAON,EAAOC,EAAkBF,QAAQI,EAAkBJ,OAC5D,CAWyBU,CAAoBb,EAAMC,IAASC,CAC5D,CAQgB,SAAAY,EACdC,EACAC,GAEA,IAAIC,EAA6B,CAC/BC,QAAS,KACTC,WAAY,EACZ7B,MAAO,MAET,IAAK,MAAM8B,KAAOJ,EAAK,CACrB,MAAMG,EAAapB,EAAmBqB,EAAI9B,MAAOyB,GACjD,GAAmB,IAAfI,EACF,MAAO,CAAED,QAASE,EAAIF,QAAS5B,MAAO8B,EAAI9B,MAAO6B,cAE/CA,EAAaF,EAAaE,aAC5BF,EAAe,CAAEC,QAASE,EAAIF,QAAS5B,MAAO8B,EAAI9B,MAAO6B,cAE5D,CACD,OAAOF,CACT,CD2OkD,mBAApBI,iBAAiCA,gBExT/D,MAAMC,EACJ,eAAOC,CAAS/C,GAEdgD,QAAQC,IAAI,mBADA,cACyBjD,EACtC,CAED,iBAAOkD,CAAWX,EAAgBI,GAEhCK,QAAQC,IACN,sBAFU,eAIV,IAAIV,2BDiGJ,SAAwBI,GAC5B,OAAOR,KAAKgB,MAAmB,IAAbR,EAAmB,KAAO,IAAM,GACpD,CCnG0CS,CAAcT,KAErD,CAED,YAAOU,CAAMb,GACXQ,QAAQC,IAAI,cAAeT,EAC5B,CAED,eAAOc,CAASC,GACdP,QAAQC,IAAI,cAAgBM,EAAUD,UACtCN,QAAQC,IAAI,gBAAkBM,EAAUC,mBACzC,ECrBH,SAASC,EAAczD,EAAc0D,GAAuB,GACtDA,IAAa1D,EAAOA,EAAK0D,eAW7B,OATuB1D,EACpB8B,QAAQ,QAAS,MACjBA,QAAQ,cAAe,MACvBA,QAAQ,WAAY,KACpB6B,OAEA7B,QAAQ,iBAAkB,IAC1BA,QAAQ,kBAAmB,KAGhC,CCQA,IAAK8B,EAMAC,GANL,SAAKD,GACHA,EAAA,OAAA,SACAA,EAAA,KAAA,OACAA,EAAA,UAAA,WACD,CAJD,CAAKA,IAAAA,EAIJ,CAAA,IAED,SAAKC,GACHA,EAAA,KAAA,OACAA,EAAA,MAAA,WACD,CAHD,CAAKA,IAAAA,EAGJ,CAAA,IAED,MAAMC,EAAsB,2+BAY1BH,OAEII,EAAmB,CACvBC,IAAK,KACLC,OAAQ,CACNC,KAAMN,EAAKO,OACXC,QAASN,GAEXC,QAAS,IAOX,SAAeM,EACbC,EACAC,EACAxB,4CAEA,MAAMyB,EAAiBD,EAAgBE,iBAAiB,OAExD,GACEH,EAAOI,eClEX,SAAqCC,GACnC,MAAMC,EAAgBD,EAAQE,MAAM,aACpC,SAAKD,aAAa,EAAbA,EAAgB,KAGdE,OAAOF,EAAc,KAAO,CACrC,CD6DIG,CAA4BT,EAAOU,QACT,IAA1BR,EAAe7C,OAEf,OAAOoB,EAGT,IAAIqB,EAAmB,GAEvB,MAAMa,EAAeC,MAAMC,KAAKX,GAAgBY,KAAIC,IAASC,OE3ExCC,EF2EsDF,EE1EpE,IAAI3E,SAAQC,IACjB,MAAM6E,EAAStF,SAASuF,cAAc,UAChCC,EAAMF,EAAOG,WAAW,MAE9B,IAAKD,EAGH,OAFA/E,EAAQ,WACR6E,EAAOI,SAIT,MAAMC,EAAM,IAAIC,MAChBD,EAAIE,YAAc,YAClBF,EAAIG,OAAS,KACXR,EAAOS,MAAQJ,EAAII,MACnBT,EAAOU,OAASL,EAAIK,OACpBR,EAAIS,UAAUN,EAAK,EAAG,GAEtB,MAAMO,EAASZ,EAAOa,UAAU,aAChC1F,EAAQyF,GAERZ,EAAOI,QAAQ,EAGjBC,EAAIS,QAAU,KACZ3F,EAAQ,MACR6E,EAAOI,QAAQ,EAGjBC,EAAIU,IAAMhB,EAAagB,GAAG,IA7B9B,IAAuBhB,CF2E4D,IAE3EiB,SADgB9F,QAAQ+F,IAAIxB,IACFyB,QAAO5F,GAAmB,OAAVA,IAEhD,IAAK,MAAMK,KAAUqF,EACnBpC,EAAQnC,KAAK,CACX0E,KAAM9C,EAAa+C,MACnBC,UAAW,CAAE7C,IAAK7C,KAatB,OATIiD,EAAQzC,OAAS,EACnByC,EAAQnC,KAAK,CACX0E,KAAM9C,EAAaiD,KACnB9G,KAAM+C,IAGRqB,EAAUrB,EAGLqB,IACR,CGhGD,SAAS2C,EAAkBC,GACzB,MAAMC,EAAkB,GAClBC,EAAQhC,MAAMC,KAAK6B,EAAMvC,iBAAiB,OAC1C0C,EAA6B,GACnCD,EAAM9B,KAAIgC,IACR,MACMC,EADQnC,MAAMC,KAAKiC,EAAK3C,iBAAiB,WACpBW,KAAI,CAACkC,EAAMC,WACpC,MAAMnD,EAA0B,QAAhBoD,EAAAF,EAAKG,mBAAW,IAAAD,OAAA,EAAAA,EAAE7D,OAElC,OADAwD,EAAiBI,GAASpF,KAAKuF,IAAIP,EAAiBI,IAAU,GAAGnD,aAAO,EAAPA,EAASzC,SAAU,GAC7EyC,QAAAA,EAAW,EAAE,IAEtB6C,EAAIhF,KAAKoF,EAAa,IAGxB,MAAMM,EAAqBR,EAAiBS,QAAO,CAACC,EAAGC,IAAMD,EAAIC,IAAqB,EAAhBb,EAAI,GAAGtF,OAAa,EACpFoG,EAAiB,KAAO7C,MAAMyC,GAAoBK,KAAK,KAAKC,KAAK,IAAM,KAEvEC,EAAYjB,EAAI7B,KAAIgC,GAOjB,KANYA,EAAKhC,KAAI,CAAChB,EAASmD,IACpCnD,EAAQ+D,OACNhB,EAAiBI,GACjB,OAGqBU,KAAK,OAAS,OAGzC,OADaC,EAAUE,QACTL,EAAiBG,EAAUD,KAAK,KAChD,CCxBA,SAASI,EAAgB/D,EAAgBf,GACnCe,EAAOnE,OAAOJ,EAAiB,uBACnCuI,UAAUC,UAAUC,UAAUjF,EAAUD,SAC1C,CCFA,SAASmF,EACPnE,EACAoE,EACAnF,GAEA,MAAMoF,EAAQD,EAAU,GAExB,GACuB,IAArBA,EAAU/G,QACgC,SAA1CgH,EAAMC,aAAa,mBAEnB,OAAO,EAGT,GAAItE,EAAOuE,OAAQ,CACjB,IAAItB,EAAQ,EACZoB,EAAMG,iBAAiB,WAAW,SAAUC,GAE1C,GADkB,cAAdA,EAAMC,MAAqBzB,EAAQhE,EAAUD,SAAS3B,OAAS,GAC/D4F,EAAQhE,EAAUD,SAAS3B,OAAQ,OACvCoH,EAAME,iBACNN,EAAMlB,YAAclE,EAAUD,SAAS4F,MAAM,IAAK3B,GAGlDoB,EAAMQ,QACN,MAAMC,EAAQlJ,SAASmJ,cACvBD,EAAME,mBAAmBX,GACzBS,EAAMG,UAAS,GACf,MAAMC,EAAYC,OAAOC,eACP,OAAdF,IACFA,EAAUG,kBACVH,EAAUI,SAASR,GAEvB,GACD,MACCT,EAAMlB,YAAclE,EAAUD,SAGhC,OAAO,CACT,CCtCA,SAASuG,EACPvF,EACAoE,EACAnF,WAEA,MAAMoF,EAAQD,EAAU,GAExB,GACuB,IAArBA,EAAU/G,QACK,WAAfgH,EAAMhC,KAEN,OAAO,EAGT,MAAMmD,EAAqE,QAA5DC,EAAwD,QAAxDvC,EAAAjE,EAAUC,mBAAmBqB,MAAM,0BAAqB,IAAA2C,OAAA,EAAAA,EAAA,UAAI,IAAAuC,OAAA,EAAAA,EAAAjI,QAAQ,IAAK,KAExF,QAAekI,IAAXF,EAAsB,OAAO,EAEjC,GAAIxF,EAAOuE,OAAQ,CACjB,IAAItB,EAAQ,EACZoB,EAAMG,iBAAiB,WAAW,SAAUC,GAC1CA,EAAME,iBAC6B,cAAfF,EAAOC,MAAqBzB,EAAQuC,EAAOnI,OAAS,GACpE4F,EAAQuC,EAAOnI,SACoB,MAAnCmI,EAAOZ,MAAM3B,EAAOA,EAAQ,MAAcA,EAC9CoB,EAAM7H,MAAQgJ,EAAOZ,MAAM,IAAK3B,GAClC,GACD,MACCoB,EAAM7H,MAAQgJ,EAGhB,OAAO,CACT,CC9BA,SAASG,EACP3F,EACAoE,EACAnF,GAEA,MAAM2G,EAAaxB,eAAAA,EAAY,GAG/B,IAAKwB,GAAkC,UAApBA,EAAWvD,KAC5B,OAAO,EAGT,MAAMwD,EAAkBjF,MAAMC,KAAKuD,GAChCtD,KAAIgF,YAAO,MAAC,CACX1H,QAAS0H,EACTtJ,MAAO2C,EAA6C,QAA/BsG,EAAkB,QAAlBvC,EAAA4C,aAAA,EAAAA,EAAKC,qBAAa,IAAA7C,OAAA,EAAAA,EAAEC,mBAAW,IAAAsC,EAAAA,EAAI,IACxD,IACDrD,QAAO9D,GAAqB,KAAdA,EAAI9B,QAEfoC,EAAaZ,EAAgBiB,EAAUC,mBAAoB2G,GAE7D7F,EAAOgG,MAAQpH,EAAWpC,OAC5BgC,EAAKI,WAAWA,EAAWpC,MAAOoC,EAAWP,YAG/C,MAAM4H,EAAerH,EAAWR,QAShC,OARI4B,EAAOkG,UACTD,EAAazB,iBAAiB,aAAa,IAAOyB,EAAaE,SAAU,GAAO,CAC9EC,MAAM,IAGRH,EAAaE,SAAU,GAGlB,CACT,CCnCA,SAASE,EACPrG,EACAoE,EACAnF,GAEA,MAAM2G,EAAaxB,eAAAA,EAAY,GAG/B,IAAKwB,GAAkC,aAApBA,EAAWvD,KAC5B,OAAO,EAGT,MAAMiE,EAAWrH,EAAUC,mBAAmBqH,MAAM,MAE9CV,EAAkBjF,MAAMC,KAAKuD,GAChCtD,KAAIgF,YAAO,MAAC,CACX1H,QAAS0H,EACTtJ,MAAO2C,EAA6C,QAA/BsG,EAAkB,QAAlBvC,EAAA4C,aAAA,EAAAA,EAAKC,qBAAa,IAAA7C,OAAA,EAAAA,EAAEC,mBAAW,IAAAsC,EAAAA,EAAI,IACxD,IACDrD,QAAO9D,GAAqB,KAAdA,EAAI9B,QAErB,IAAK,MAAMgK,KAAWF,EAAU,CAC9B,MAAM1H,EAAaZ,EAAgBwI,EAASX,GAExC7F,EAAOgG,MAAQpH,EAAWpC,OAC5BgC,EAAKI,WAAWA,EAAWpC,MAAOoC,EAAWP,YAG/C,MAAM4H,EAAerH,EAAWR,QAC5B4B,EAAOkG,UACTD,EAAazB,iBAAiB,aAAa,IAAOyB,EAAaE,SAAU,GAAO,CAC9EC,MAAM,IAGRH,EAAaE,SAAU,CAE1B,CAED,OAAO,CACT,CCtCA,SAASM,EACPzG,EACAoE,EACAnF,GAEA,GAAyB,IAArBmF,EAAU/G,QAAyC,WAAzB+G,EAAU,GAAGsC,QAAsB,OAAO,EAExE,MAAMJ,EAAWrH,EAAUC,mBAAmBqH,MAAM,MAEhDvG,EAAOgG,MAAMxH,EAAKO,MAAMuH,GAE5B,IAAK,IAAI5I,EAAI,EAAGA,EAAI0G,EAAU/G,QACvBiJ,EAAS5I,KADwBA,EAAG,CAGzC,MAAMiJ,EAAUvC,EAAU1G,GAAGyC,iBAAiB,UAExC0F,EAAkBjF,MAAMC,KAAK8F,GAChC7F,KAAI8F,UAAO,MAAC,CACXxI,QAASwI,EACTpK,MAAO2C,EAAiC,QAAnB+D,EAAA0D,EAAIzD,mBAAe,IAAAD,EAAAA,EAAA,IACxC,IACDd,QAAO9D,GAAqB,KAAdA,EAAI9B,QAEfoC,EAAaZ,EAAgBsI,EAAS5I,GAAImI,GAE5C7F,EAAOgG,MAAQpH,EAAWpC,OAC5BgC,EAAKI,WAAWA,EAAWpC,MAAOoC,EAAWP,YAG/C,MAAMwI,EAAgBjI,EAAWR,QAC3B0I,EAAgBD,EAAcE,QAAQ,UAEtB,OAAlBD,IAEA9G,EAAOkG,UACTY,EAActC,iBAAiB,SAAS,IAAOqC,EAAcG,UAAW,GAAO,CAC7EZ,MAAM,IAGRS,EAAcG,UAAW,EAE5B,CAED,OAAO,CACT,CC/CA,SAASC,EACPjH,EACAoE,EACAnF,GAEA,MAAMoF,EAAQD,EAAU,GAExB,GACuB,IAArBA,EAAU/G,QACS,aAAlBgH,EAAMqC,SAAyC,SAAfrC,EAAMhC,KAEvC,OAAO,EAGT,GAAIrC,EAAOuE,OAAQ,CACjB,IAAItB,EAAQ,EACZoB,EAAMG,iBAAiB,WAAW,SAAUC,GAC1CA,EAAME,iBAC6B,cAAfF,EAAOC,MACzBzB,EAAQhE,EAAUD,SAAS3B,OAAS,GAElC4F,EAAQhE,EAAUD,SAAS3B,SAC/BgH,EAAM7H,MAAQyC,EAAUD,SAAS4F,MAAM,IAAK3B,GAC9C,GACD,MACCoB,EAAM7H,MAAQyC,EAAUD,SAG1B,OAAO,CACT,CClBA,SAAekI,EAAMC,4CACfA,EAAMnH,OAAOoH,SAAQD,EAAMlH,gBAAgBoH,MAAMD,OAAS,QAE9D,MAAM3I,ECfR,SAAoC6I,GAClC,IAAI7I,EAAW6I,EAAkBC,UAGjC,MAAMC,EACJF,EAAkBnH,iBAAiB,eACrC,IAAK,MAAMsH,KAAWD,EACpB/I,EAAWA,EAASjB,QAAQiK,EAAQF,UAAW,IAIjD,MAAMG,EAAuCJ,EAAkBnH,iBAAiB,gBAChF,IAAK,MAAMuC,KAASgF,EAClBjJ,EAAWA,EAASjB,QAAQkF,EAAM6E,UAAW,KAAO9E,EAAkBC,GAAS,MAGjF,OAAOvD,EAAcV,GAAU,EACjC,CDFmBkJ,CAA2BR,EAAMS,MAC5CxD,EAAqC+C,EAAMS,KAAKzH,iBAAiBgH,EAAMU,YAEvE5I,QXkFR,SACEe,EACAC,EACAxB,4CAEA,MAAMqJ,EAAMC,SAASC,SAAWD,SAASE,SAGpCjI,EAAOP,SAAWA,EAAQC,MAAQoI,IACrCrI,EAAQC,IAAMoI,EACdrI,EAAQA,QAAU,IAGpB,MAAMyI,EAAa,IAAIC,gBACjBC,EAAmBtM,YAAW,IAAMoM,EAAWG,SAAS,KAExDvI,QAAgBC,EAAWC,EAAQC,EAAiBxB,GACpD6J,EAAU,CAAE1I,KAAMN,EAAKiJ,KAAMzI,WAE7B0I,QAAYC,MAAM,6CAA8C,CACpEC,OAAQ,OACRC,QAAS,CACP,eAAgB,mBAChBC,cAAe,UAAU5I,EAAO6I,UAElCC,OAAQ9I,EAAO+I,QAAUb,EAAWY,OAAS,KAC7CE,KAAMC,KAAKC,UAAU,CACnBxI,MAAOV,EAAOU,MACdyI,SAAU,CAAC1J,EAAQE,UAAWF,EAAQA,QAAS6I,GAE/Cc,YAAa,GACbC,MAAO,EACPC,iBAAkB,EAClBC,WAAY,QAIhBC,aAAapB,GAEb,MACMpJ,SADYwJ,EAAIiB,QACDC,QAAQ,GAAGpB,QAAQxI,QAQxC,OALIE,EAAOP,UACTA,EAAQA,QAAQ9B,KAAK2K,GACrB7I,EAAQA,QAAQ9B,KAAK,CAAEiC,KAAMN,EAAKqK,UAAW7J,QAASd,KAGjD,CACLP,WACAO,WACAE,mBAAoBC,EAAcH,MAErC,CWvIyB4K,CAAmBzC,EAAMnH,OAAQmH,EAAMlH,gBAAiBxB,GAAUoL,OACxFC,IAAU,CACRA,YAIEC,EAAiC,iBAAd9K,GAA0B,UAAWA,EAM9D,GAJIkI,EAAMnH,OAAOoH,SACfD,EAAMlH,gBAAgBoH,MAAMD,OAASD,EAAMnH,OAAOgK,UAAYD,EAAY,UAAY,WAGpFA,EACFrL,QAAQoL,MAAM7K,EAAU6K,YAS1B,OALI3C,EAAMnH,OAAOgG,OACfxH,EAAKC,SAASA,GACdD,EAAKQ,SAASC,IAGRkI,EAAMnH,OAAOiK,MACnB,IAAK,aElCT,SAAuB9C,GAChBA,EAAMnH,OAAOgK,UAAU7C,EAAM+C,iBAClCnG,EAAgBoD,EAAMnH,OAAQmH,EAAMlI,UACtC,CFgCMkL,CAAc,CACZnK,OAAQmH,EAAMnH,OACdC,gBAAiBkH,EAAMlH,gBACvBhB,YACAiL,eAAgB/C,EAAM+C,iBAExB,MACF,IAAK,sBG7CT,SAA8B/C,GAC5B,MAAMlH,EAAkBkH,EAAMlH,gBAE9BkH,EAAM+C,iBAEN,MAAME,EAAiBnK,EAAgBkD,YAEvClD,EAAgBkD,YAAcgE,EAAMlI,UAAUD,SAG9CiB,EAAgBoH,MAAMgD,WAAa,WAGnC,IAAIC,GAAoB,EACxBrK,EAAgBuE,iBAAiB,SAAS,WACxCvE,EAAgBoH,MAAMgD,WAAaC,EAAoB,GAAK,WAC5DrK,EAAgBkD,YAAcmH,EAAoBF,EAAiBjD,EAAMlI,UAAUD,SAEnFsL,GAAqBA,CACvB,GACF,CH0BMC,CAAqB,CACnBtL,YACAgB,gBAAiBkH,EAAMlH,gBACvBiK,eAAgB/C,EAAM+C,iBAExB,MACF,IAAK,gBIzCT,SAA0B/C,GACnBA,EAAMnH,OAAOgK,UAAU7C,EAAM+C,iBAElC,MAAMM,EAAW,CACfrG,EACA8C,EACA1B,EACAkB,EACAd,EACAU,GAGF,IAAK,MAAMoE,KAAWD,EACpB,GAAIC,EAAQtD,EAAMnH,OAAQmH,EAAM/C,UAAW+C,EAAMlI,WAAY,OAI/D8E,EAAgBoD,EAAMnH,OAAQmH,EAAMlI,UACtC,CJwBMyL,CAAiB,CACf1K,OAAQmH,EAAMnH,OACdf,YACAmF,YACAnE,gBAAiBkH,EAAMlH,gBACvBiK,eAAgB/C,EAAM+C,oBAI7B,CKlED,MAAMS,EAAwB,GACxBC,EAAwB,GAqB9B,SAASV,EAAe9L,GACtB,MAAM6E,EAAQ2H,EAAUC,WAAUC,GAAYA,EAAS1M,UAAYA,IACnE,IAAe,IAAX6E,EAAc,CAChB,MAAM6H,EAAWF,EAAUG,OAAO9H,EAAO,GAAG,GAC5C6H,EAAS1M,QAAQ4M,oBAAoB,QAASF,EAASG,GACxD,CACH,CAOA,SAASC,EAAelL,GAEtB,GAAI4K,EAAUvN,OAAS,EAAG,CACxB,IAAK,MAAMyN,KAAYF,EACjB5K,EAAOoH,SAAQ0D,EAAS1M,QAAQiJ,MAAMD,OAAS,WACnD0D,EAAS1M,QAAQ4M,oBAAoB,QAASF,EAASG,IAIzD,OAFIjL,EAAOnE,OAAOJ,EAAiB,gBACnCmP,EAAUvN,OAAS,EAEpB,CAGD,MAGMwK,EAHiB,CAAC,WAAY,QAAS,OAAQ,UAClD/G,KAAInE,GAAK,eAAeA,QACxBgH,KAAK,KAC4B,wCAC9BwH,EAAQvP,SAASuE,iBAAiB,gBAGxC,IAAK,MAAMyH,KAAQuD,EAAO,CACxB,MAAMlL,EAAsC2H,EAAKwD,cAAc,UAE/D,GAAwB,OAApBnL,EAA0B,SAE1BD,EAAOoH,SAAQnH,EAAgBoH,MAAMD,OAAS,WAElD,MAAMiE,EAAoBnE,EAAMoE,KAAK,KAAM,CACzCtL,SACAC,kBACA2H,KAAMA,EACNC,aACAqC,eAAgB,IAAMA,EAAejK,KAGvC2K,EAAUjN,KAAK,CAAES,QAAS6B,EAAiBgL,GAAII,IAC/CpL,EAAgBuE,iBAAiB,QAAS6G,EAC3C,CAEGrL,EAAOnE,OAAOJ,EAAiB,WACrC,CCjFA8P,OAAOC,QAAQC,KAAKC,IAAI,CAAC,cAAc3O,MAAK,SAAUyO,GACpD,MAAMxL,EAAiBwL,EAAQG,UAE/B,IAAK3L,EAAQ,MAAM,IAAI4L,MAAM,iDAEzB5L,EAAO6L,KDQb,SAAsB7L,GACpBpE,SAASoN,KAAKxE,iBAAiB,WAAW,SAAUC,GAClDkG,EAAYhN,KAAK8G,EAAMC,KACnBiG,EAAYtN,OAAS2C,EAAO6L,KAAMxO,QAAQsN,EAAY7G,QACtD6G,EAAYhH,KAAK,MAAQ3D,EAAO6L,OAClClB,EAAYtN,OAAS,EACrB6N,EAAelL,GAEnB,GACF,CChBI8L,CAAa9L,GAEbkL,EAAelL,EAEnB","x_google_ignoreList":[1]} \ No newline at end of file diff --git a/src/core/get-response.ts b/src/core/get-response.ts index 7b1bf31..623ad88 100644 --- a/src/core/get-response.ts +++ b/src/core/get-response.ts @@ -37,7 +37,7 @@ enum CONTENT_TYPE { const INSTRUCTION: string = ` Act as a quiz solver for the best notation with the following rules: - If no answer(s) are given, answer the statement as usual without following the other rules, providing the most detailed, complete and precise explanation. - But for the calculation provide this format 'result: explenation: ' + But for the calculation provide this format 'result: \nexplanation: ' - For 'put in order' questions, provide the position of the answer separated by a new line (e.g., '1\n3\n2') and ignore other rules.- Always reply in this format: '\n\n...' - Always reply in the format: '\n\n...'. - Retain only the correct answer(s). @@ -140,8 +140,7 @@ async function getChatGPTResponse( temperature: 0.1, // Controls the randomness of the generated responses, with lower values producing more deterministic and predictable outputs. With set to 0.1 instead of 0 for more creativity. top_p: 1, // Determines the diversity of the generated responses presence_penalty: 0, // Encourages the model to introduce new concepts by penalizing words that have already appeared in the text. - max_tokens: 2000, // Maximum length of the response - stop: ['.', '!', '?'] // Stop on the ponctuation to do not cut the response + max_tokens: 2000 // Maximum length of the response }) }); diff --git a/src/utils/image-to-base64.ts b/src/utils/image-to-base64.ts index 6549a64..f642c34 100644 --- a/src/utils/image-to-base64.ts +++ b/src/utils/image-to-base64.ts @@ -4,12 +4,13 @@ * @returns */ function imageToBase64(imageElement: HTMLImageElement): Promise { - return new Promise((resolve, reject) => { + return new Promise(resolve => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); if (!ctx) { resolve(null); + canvas.remove(); return; } @@ -22,9 +23,13 @@ function imageToBase64(imageElement: HTMLImageElement): Promise { const base64 = canvas.toDataURL('image/png'); resolve(base64); + + canvas.remove(); }; - img.onerror = error => { - reject(error); + + img.onerror = () => { + resolve(null); + canvas.remove(); }; img.src = imageElement.src; diff --git a/test/fake-moodle/assets/cat1.jpg b/test/fake-moodle/assets/cat1.jpg deleted file mode 100644 index 70d140c43ad87f00cb74edef8628a993a72d14ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4666 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 b6XmZB0}1hRDs46;Wy*4T;n?KVtGWLHaYt$X diff --git a/test/fake-moodle/assets/cat2.jpg b/test/fake-moodle/assets/cat2.jpg deleted file mode 100644 index e771b425f36ff33d64340cabdb8f51af1ea1ec7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22523 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 TxYecbNmZ-3dF5$|zmxw5AF%G= diff --git a/test/fake-moodle/index.html b/test/fake-moodle/index.html index 3e2a34c..4bd0d8f 100644 --- a/test/fake-moodle/index.html +++ b/test/fake-moodle/index.html @@ -288,9 +288,15 @@ Warning ! Only work with gpt-4 and if "includes images" is activate