diff options
Diffstat (limited to 'src')
35 files changed, 716 insertions, 453 deletions
diff --git a/src/background/run-ocr.ts b/src/background/run-ocr.ts index 7975fc0..683f701 100644 --- a/src/background/run-ocr.ts +++ b/src/background/run-ocr.ts @@ -1,7 +1,13 @@ +import { OCRRequest, OCRResponse } from "@/shared/ocr-request"; + const OFFSCREEN_DOCUMENT_PATH = "offscreen/ocr/index.html"; // Function to ensure the offscreen document is open -async function setupOffscreenDocument() { +/** + * Ensures the offscreen OCR document is open. If it already exists + * this is a no-op. + */ +async function setupOffscreenDocument(): Promise<void> { if (await chrome.offscreen.hasDocument()) { return; // Offscreen document already open } @@ -13,25 +19,26 @@ async function setupOffscreenDocument() { } // Listen for messages from content scripts (and popup if applicable) -chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { +/** + * Listens for `"OCR"` messages from content scripts. Forwards the + * image data URL to an offscreen document for Tesseract.js processing + * and sends the recognised text back to the caller. + */ +chrome.runtime.onMessage.addListener(function(message: OCRRequest, _sender, sendResponse): boolean { if (message.type === "OCR" && message.dataURL) { - (async () => { + void (async function(): Promise<void> { try { // Ensure the offscreen document is open await setupOffscreenDocument(); // Send the OCR request to the offscreen document - const offscreenResponse = await chrome.runtime.sendMessage({ + const offscreenResponse = await chrome.runtime.sendMessage<OCRRequest, OCRResponse>({ type: "OFFSCREEN_OCR_REQUEST", dataURL: message.dataURL }); - if (offscreenResponse && offscreenResponse.success) { - sendResponse(offscreenResponse); - } else { - sendResponse({ success: false, error: offscreenResponse?.error || "Unknown OCR error" }); - } - } catch (error) { + sendResponse(offscreenResponse); + } catch(error) { sendResponse({ success: false, error: (error as Error).message }); } })(); diff --git a/src/html.d.ts b/src/html.d.ts index b913216..086f645 100644 --- a/src/html.d.ts +++ b/src/html.d.ts @@ -1,3 +1,4 @@ declare module "*.html" { - export default (replacements: any) => string; + function content(_replacements: Record<string, unknown>): string; + export default content; } diff --git a/src/offscreen/ocr/index.html b/src/offscreen/ocr/index.html index f11b573..920c123 100644 --- a/src/offscreen/ocr/index.html +++ b/src/offscreen/ocr/index.html @@ -5,7 +5,7 @@ <title>Offscreen Document for OCR</title> </head> <body> - <script src="./tesseract.esm.min.js" type="module"></script> + <script src="./static/tesseract.esm.min.js" type="module"></script> <script src="./index.js" type="module"></script> </body> </html> diff --git a/src/offscreen/ocr/index.js b/src/offscreen/ocr/index.js index 432811e..dfe93c9 100644 --- a/src/offscreen/ocr/index.js +++ b/src/offscreen/ocr/index.js @@ -1,20 +1,29 @@ -import Tesseract from "./tesseract.esm.min.js"; +import Tesseract from "./static/tesseract.esm.min.js"; let ocrWorker = null; const WORKER_PATH = chrome.runtime.getURL("offscreen/ocr/static/worker.min.js"); const CORE_PATH = chrome.runtime.getURL("offscreen/ocr/static"); +/** + * Creates (or reuses) a Tesseract.js worker and recognises text from + * the given image data URL. The worker is configured to only recognise + * uppercase alphanumerics (excluding `0`, `O`, `1`, `I`) suitable for + * CAPTCHA text. + * + * @param {string} dataURL - A `data:image/png;base64,…` string. + * @returns {{ text: string, confidence: number }} + */ async function performOcrInOffscreen(dataURL) { if (!ocrWorker) { ocrWorker = await Tesseract.createWorker("eng", 1, { workerPath: WORKER_PATH, corePath: CORE_PATH, - workerBlobURL: false, + workerBlobURL: false }); await ocrWorker.setParameters({ // The only characters that appears - tessedit_char_whitelist: "ABCDEFGHJKLMNPQRSTUVWXYZ23456789", + tessedit_char_whitelist: "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" }); } @@ -23,13 +32,18 @@ async function performOcrInOffscreen(dataURL) { } // Listen for messages from the Service Worker -chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { +/** + * Handles two message types from the background service worker: + * - `"OFFSCREEN_OCR_REQUEST"`: runs OCR on the supplied data URL. + * - `"OFFSCREEN_TERMINATE_OCR_WORKER"`: terminates the worker to free memory. + */ +chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { if (message.type === "OFFSCREEN_OCR_REQUEST" && message.dataURL) { performOcrInOffscreen(message.dataURL) - .then(({ text, confidence }) => { + .then(function({ text, confidence }) { sendResponse({ success: true, text, confidence }); }) - .catch(error => { + .catch(function(error) { sendResponse({ success: false, error: error.message }); }); return true; diff --git a/src/offscreen/ocr/tesseract.esm.min.js b/src/offscreen/ocr/static/tesseract.esm.min.js index c1c4568..ad97d16 100644 --- a/src/offscreen/ocr/tesseract.esm.min.js +++ b/src/offscreen/ocr/static/tesseract.esm.min.js @@ -9,7 +9,7 @@ var tesseract_min$1 = {exports: {}}; (function (module, exports) { !function(t,r){module.exports=r();}(self,(()=>(()=>{var t={30:(t,r,e)=>{function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}var o=function(t){var r,e=Object.prototype,o=e.hasOwnProperty,i=Object.defineProperty||function(t,r,e){t[r]=e.value;},a="function"==typeof Symbol?Symbol:{},c=a.iterator||"@@iterator",u=a.asyncIterator||"@@asyncIterator",f=a.toStringTag||"@@toStringTag";function l(t,r,e){return Object.defineProperty(t,r,{value:e,enumerable:!0,configurable:!0,writable:!0}),t[r]}try{l({},"");}catch(t){l=function(t,r,e){return t[r]=e};}function s(t,r,e,n){var o=r&&r.prototype instanceof m?r:m,a=Object.create(o.prototype),c=new N(n||[]);return i(a,"_invoke",{value:P(t,e,c)}),a}function h(t,r,e){try{return {type:"normal",arg:t.call(r,e)}}catch(t){return {type:"throw",arg:t}}}t.wrap=s;var p="suspendedStart",y="suspendedYield",v="executing",d="completed",g={};function m(){}function b(){}function w(){}var x={};l(x,c,(function(){return this}));var L=Object.getPrototypeOf,O=L&&L(L(A([])));O&&O!==e&&o.call(O,c)&&(x=O);var E=w.prototype=m.prototype=Object.create(x);function S(t){["next","throw","return"].forEach((function(r){l(t,r,(function(t){return this._invoke(r,t)}));}));}function j(t,r){function e(i,a,c,u){var f=h(t[i],t,a);if("throw"!==f.type){var l=f.arg,s=l.value;return s&&"object"===n(s)&&o.call(s,"__await")?r.resolve(s.__await).then((function(t){e("next",t,c,u);}),(function(t){e("throw",t,c,u);})):r.resolve(s).then((function(t){l.value=t,c(l);}),(function(t){return e("throw",t,c,u)}))}u(f.arg);}var a;i(this,"_invoke",{value:function(t,n){function o(){return new r((function(r,o){e(t,n,r,o);}))}return a=a?a.then(o,o):o()}});}function P(t,r,e){var n=p;return function(o,i){if(n===v)throw new Error("Generator is already running");if(n===d){if("throw"===o)throw i;return G()}for(e.method=o,e.arg=i;;){var a=e.delegate;if(a){var c=_(a,e);if(c){if(c===g)continue;return c}}if("next"===e.method)e.sent=e._sent=e.arg;else if("throw"===e.method){if(n===p)throw n=d,e.arg;e.dispatchException(e.arg);}else "return"===e.method&&e.abrupt("return",e.arg);n=v;var u=h(t,r,e);if("normal"===u.type){if(n=e.done?d:y,u.arg===g)continue;return {value:u.arg,done:e.done}}"throw"===u.type&&(n=d,e.method="throw",e.arg=u.arg);}}}function _(t,e){var n=e.method,o=t.iterator[n];if(o===r)return e.delegate=null,"throw"===n&&t.iterator.return&&(e.method="return",e.arg=r,_(t,e),"throw"===e.method)||"return"!==n&&(e.method="throw",e.arg=new TypeError("The iterator does not provide a '"+n+"' method")),g;var i=h(o,t.iterator,e.arg);if("throw"===i.type)return e.method="throw",e.arg=i.arg,e.delegate=null,g;var a=i.arg;return a?a.done?(e[t.resultName]=a.value,e.next=t.nextLoc,"return"!==e.method&&(e.method="next",e.arg=r),e.delegate=null,g):a:(e.method="throw",e.arg=new TypeError("iterator result is not an object"),e.delegate=null,g)}function k(t){var r={tryLoc:t[0]};1 in t&&(r.catchLoc=t[1]),2 in t&&(r.finallyLoc=t[2],r.afterLoc=t[3]),this.tryEntries.push(r);}function T(t){var r=t.completion||{};r.type="normal",delete r.arg,t.completion=r;}function N(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(k,this),this.reset(!0);}function A(t){if(t){var e=t[c];if(e)return e.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var n=-1,i=function e(){for(;++n<t.length;)if(o.call(t,n))return e.value=t[n],e.done=!1,e;return e.value=r,e.done=!0,e};return i.next=i}}return {next:G}}function G(){return {value:r,done:!0}}return b.prototype=w,i(E,"constructor",{value:w,configurable:!0}),i(w,"constructor",{value:b,configurable:!0}),b.displayName=l(w,f,"GeneratorFunction"),t.isGeneratorFunction=function(t){var r="function"==typeof t&&t.constructor;return !!r&&(r===b||"GeneratorFunction"===(r.displayName||r.name))},t.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,w):(t.__proto__=w,l(t,f,"GeneratorFunction")),t.prototype=Object.create(E),t},t.awrap=function(t){return {__await:t}},S(j.prototype),l(j.prototype,u,(function(){return this})),t.AsyncIterator=j,t.async=function(r,e,n,o,i){void 0===i&&(i=Promise);var a=new j(s(r,e,n,o),i);return t.isGeneratorFunction(e)?a:a.next().then((function(t){return t.done?t.value:a.next()}))},S(E),l(E,f,"Generator"),l(E,c,(function(){return this})),l(E,"toString",(function(){return "[object Generator]"})),t.keys=function(t){var r=Object(t),e=[];for(var n in r)e.push(n);return e.reverse(),function t(){for(;e.length;){var n=e.pop();if(n in r)return t.value=n,t.done=!1,t}return t.done=!0,t}},t.values=A,N.prototype={constructor:N,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=r,this.done=!1,this.delegate=null,this.method="next",this.arg=r,this.tryEntries.forEach(T),!t)for(var e in this)"t"===e.charAt(0)&&o.call(this,e)&&!isNaN(+e.slice(1))&&(this[e]=r);},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var e=this;function n(n,o){return c.type="throw",c.arg=t,e.next=n,o&&(e.method="next",e.arg=r),!!o}for(var i=this.tryEntries.length-1;i>=0;--i){var a=this.tryEntries[i],c=a.completion;if("root"===a.tryLoc)return n("end");if(a.tryLoc<=this.prev){var u=o.call(a,"catchLoc"),f=o.call(a,"finallyLoc");if(u&&f){if(this.prev<a.catchLoc)return n(a.catchLoc,!0);if(this.prev<a.finallyLoc)return n(a.finallyLoc)}else if(u){if(this.prev<a.catchLoc)return n(a.catchLoc,!0)}else {if(!f)throw new Error("try statement without catch or finally");if(this.prev<a.finallyLoc)return n(a.finallyLoc)}}}},abrupt:function(t,r){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc<=this.prev&&o.call(n,"finallyLoc")&&this.prev<n.finallyLoc){var i=n;break}}i&&("break"===t||"continue"===t)&&i.tryLoc<=r&&r<=i.finallyLoc&&(i=null);var a=i?i.completion:{};return a.type=t,a.arg=r,i?(this.method="next",this.next=i.finallyLoc,g):this.complete(a)},complete:function(t,r){if("throw"===t.type)throw t.arg;return "break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&r&&(this.next=r),g},finish:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.finallyLoc===t)return this.complete(e.completion,e.afterLoc),T(e),g}},catch:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.tryLoc===t){var n=e.completion;if("throw"===n.type){var o=n.arg;T(e);}return o}}throw new Error("illegal catch attempt")},delegateYield:function(t,e,n){return this.delegate={iterator:A(t),resultName:e,nextLoc:n},"next"===this.method&&(this.arg=r),g}},t}("object"===n(t=e.nmd(t))?t.exports:{});try{regeneratorRuntime=o;}catch(t){"object"===("undefined"==typeof globalThis?"undefined":n(globalThis))?globalThis.regeneratorRuntime=o:Function("r","regeneratorRuntime = r")(o);}},52:(t,r,e)=>{function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}function o(){o=function(){return t};var t={},r=Object.prototype,e=r.hasOwnProperty,i=Object.defineProperty||function(t,r,e){t[r]=e.value;},a="function"==typeof Symbol?Symbol:{},c=a.iterator||"@@iterator",u=a.asyncIterator||"@@asyncIterator",f=a.toStringTag||"@@toStringTag";function l(t,r,e){return Object.defineProperty(t,r,{value:e,enumerable:!0,configurable:!0,writable:!0}),t[r]}try{l({},"");}catch(t){l=function(t,r,e){return t[r]=e};}function s(t,r,e,n){var o=r&&r.prototype instanceof y?r:y,a=Object.create(o.prototype),c=new P(n||[]);return i(a,"_invoke",{value:O(t,e,c)}),a}function h(t,r,e){try{return {type:"normal",arg:t.call(r,e)}}catch(t){return {type:"throw",arg:t}}}t.wrap=s;var p={};function y(){}function v(){}function d(){}var g={};l(g,c,(function(){return this}));var m=Object.getPrototypeOf,b=m&&m(m(_([])));b&&b!==r&&e.call(b,c)&&(g=b);var w=d.prototype=y.prototype=Object.create(g);function x(t){["next","throw","return"].forEach((function(r){l(t,r,(function(t){return this._invoke(r,t)}));}));}function L(t,r){function o(i,a,c,u){var f=h(t[i],t,a);if("throw"!==f.type){var l=f.arg,s=l.value;return s&&"object"==n(s)&&e.call(s,"__await")?r.resolve(s.__await).then((function(t){o("next",t,c,u);}),(function(t){o("throw",t,c,u);})):r.resolve(s).then((function(t){l.value=t,c(l);}),(function(t){return o("throw",t,c,u)}))}u(f.arg);}var a;i(this,"_invoke",{value:function(t,e){function n(){return new r((function(r,n){o(t,e,r,n);}))}return a=a?a.then(n,n):n()}});}function O(t,r,e){var n="suspendedStart";return function(o,i){if("executing"===n)throw new Error("Generator is already running");if("completed"===n){if("throw"===o)throw i;return {value:void 0,done:!0}}for(e.method=o,e.arg=i;;){var a=e.delegate;if(a){var c=E(a,e);if(c){if(c===p)continue;return c}}if("next"===e.method)e.sent=e._sent=e.arg;else if("throw"===e.method){if("suspendedStart"===n)throw n="completed",e.arg;e.dispatchException(e.arg);}else "return"===e.method&&e.abrupt("return",e.arg);n="executing";var u=h(t,r,e);if("normal"===u.type){if(n=e.done?"completed":"suspendedYield",u.arg===p)continue;return {value:u.arg,done:e.done}}"throw"===u.type&&(n="completed",e.method="throw",e.arg=u.arg);}}}function E(t,r){var e=r.method,n=t.iterator[e];if(void 0===n)return r.delegate=null,"throw"===e&&t.iterator.return&&(r.method="return",r.arg=void 0,E(t,r),"throw"===r.method)||"return"!==e&&(r.method="throw",r.arg=new TypeError("The iterator does not provide a '"+e+"' method")),p;var o=h(n,t.iterator,r.arg);if("throw"===o.type)return r.method="throw",r.arg=o.arg,r.delegate=null,p;var i=o.arg;return i?i.done?(r[t.resultName]=i.value,r.next=t.nextLoc,"return"!==r.method&&(r.method="next",r.arg=void 0),r.delegate=null,p):i:(r.method="throw",r.arg=new TypeError("iterator result is not an object"),r.delegate=null,p)}function S(t){var r={tryLoc:t[0]};1 in t&&(r.catchLoc=t[1]),2 in t&&(r.finallyLoc=t[2],r.afterLoc=t[3]),this.tryEntries.push(r);}function j(t){var r=t.completion||{};r.type="normal",delete r.arg,t.completion=r;}function P(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(S,this),this.reset(!0);}function _(t){if(t){var r=t[c];if(r)return r.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var n=-1,o=function r(){for(;++n<t.length;)if(e.call(t,n))return r.value=t[n],r.done=!1,r;return r.value=void 0,r.done=!0,r};return o.next=o}}return {next:k}}function k(){return {value:void 0,done:!0}}return v.prototype=d,i(w,"constructor",{value:d,configurable:!0}),i(d,"constructor",{value:v,configurable:!0}),v.displayName=l(d,f,"GeneratorFunction"),t.isGeneratorFunction=function(t){var r="function"==typeof t&&t.constructor;return !!r&&(r===v||"GeneratorFunction"===(r.displayName||r.name))},t.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,d):(t.__proto__=d,l(t,f,"GeneratorFunction")),t.prototype=Object.create(w),t},t.awrap=function(t){return {__await:t}},x(L.prototype),l(L.prototype,u,(function(){return this})),t.AsyncIterator=L,t.async=function(r,e,n,o,i){void 0===i&&(i=Promise);var a=new L(s(r,e,n,o),i);return t.isGeneratorFunction(e)?a:a.next().then((function(t){return t.done?t.value:a.next()}))},x(w),l(w,f,"Generator"),l(w,c,(function(){return this})),l(w,"toString",(function(){return "[object Generator]"})),t.keys=function(t){var r=Object(t),e=[];for(var n in r)e.push(n);return e.reverse(),function t(){for(;e.length;){var n=e.pop();if(n in r)return t.value=n,t.done=!1,t}return t.done=!0,t}},t.values=_,P.prototype={constructor:P,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=void 0,this.done=!1,this.delegate=null,this.method="next",this.arg=void 0,this.tryEntries.forEach(j),!t)for(var r in this)"t"===r.charAt(0)&&e.call(this,r)&&!isNaN(+r.slice(1))&&(this[r]=void 0);},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var r=this;function n(e,n){return a.type="throw",a.arg=t,r.next=e,n&&(r.method="next",r.arg=void 0),!!n}for(var o=this.tryEntries.length-1;o>=0;--o){var i=this.tryEntries[o],a=i.completion;if("root"===i.tryLoc)return n("end");if(i.tryLoc<=this.prev){var c=e.call(i,"catchLoc"),u=e.call(i,"finallyLoc");if(c&&u){if(this.prev<i.catchLoc)return n(i.catchLoc,!0);if(this.prev<i.finallyLoc)return n(i.finallyLoc)}else if(c){if(this.prev<i.catchLoc)return n(i.catchLoc,!0)}else {if(!u)throw new Error("try statement without catch or finally");if(this.prev<i.finallyLoc)return n(i.finallyLoc)}}}},abrupt:function(t,r){for(var n=this.tryEntries.length-1;n>=0;--n){var o=this.tryEntries[n];if(o.tryLoc<=this.prev&&e.call(o,"finallyLoc")&&this.prev<o.finallyLoc){var i=o;break}}i&&("break"===t||"continue"===t)&&i.tryLoc<=r&&r<=i.finallyLoc&&(i=null);var a=i?i.completion:{};return a.type=t,a.arg=r,i?(this.method="next",this.next=i.finallyLoc,p):this.complete(a)},complete:function(t,r){if("throw"===t.type)throw t.arg;return "break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&r&&(this.next=r),p},finish:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.finallyLoc===t)return this.complete(e.completion,e.afterLoc),j(e),p}},catch:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.tryLoc===t){var n=e.completion;if("throw"===n.type){var o=n.arg;j(e);}return o}}throw new Error("illegal catch attempt")},delegateYield:function(t,r,e){return this.delegate={iterator:_(t),resultName:r,nextLoc:e},"next"===this.method&&(this.arg=void 0),p}},t}function i(t,r,e,n,o,i,a){try{var c=t[i](a),u=c.value;}catch(t){return void e(t)}c.done?r(u):Promise.resolve(u).then(n,o);}function a(t){return function(){var r=this,e=arguments;return new Promise((function(n,o){var a=t.apply(r,e);function c(t){i(a,n,o,c,u,"next",t);}function u(t){i(a,n,o,c,u,"throw",t);}c(void 0);}))}}var c=e(738),u=function(){var t=a(o().mark((function t(r,e,n){var i;return o().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,c(e,1,n);case 2:return i=t.sent,t.abrupt("return",i.recognize(r).finally(a(o().mark((function t(){return o().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,i.terminate();case 2:case"end":return t.stop()}}),t)})))));case 4:case"end":return t.stop()}}),t)})));return function(r,e,n){return t.apply(this,arguments)}}(),f=function(){var t=a(o().mark((function t(r,e){var n;return o().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,c("osd",0,e);case 2:return n=t.sent,t.abrupt("return",n.detect(r).finally(a(o().mark((function t(){return o().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,n.terminate();case 2:case"end":return t.stop()}}),t)})))));case 4:case"end":return t.stop()}}),t)})));return function(r,e){return t.apply(this,arguments)}}();t.exports={recognize:u,detect:f};},287:t=>{t.exports={TESSERACT_ONLY:0,LSTM_ONLY:1,TESSERACT_LSTM_COMBINED:2,DEFAULT:3};},188:t=>{t.exports={OSD_ONLY:"0",AUTO_OSD:"1",AUTO_ONLY:"2",AUTO:"3",SINGLE_COLUMN:"4",SINGLE_BLOCK_VERT_TEXT:"5",SINGLE_BLOCK:"6",SINGLE_LINE:"7",SINGLE_WORD:"8",CIRCLE_WORD:"9",SINGLE_CHAR:"10",SPARSE_TEXT:"11",SPARSE_TEXT_OSD:"12",RAW_LINE:"13"};},491:t=>{t.exports={workerBlobURL:!0,logger:function(){}};},11:t=>{t.exports={AFR:"afr",AMH:"amh",ARA:"ara",ASM:"asm",AZE:"aze",AZE_CYRL:"aze_cyrl",BEL:"bel",BEN:"ben",BOD:"bod",BOS:"bos",BUL:"bul",CAT:"cat",CEB:"ceb",CES:"ces",CHI_SIM:"chi_sim",CHI_TRA:"chi_tra",CHR:"chr",CYM:"cym",DAN:"dan",DEU:"deu",DZO:"dzo",ELL:"ell",ENG:"eng",ENM:"enm",EPO:"epo",EST:"est",EUS:"eus",FAS:"fas",FIN:"fin",FRA:"fra",FRK:"frk",FRM:"frm",GLE:"gle",GLG:"glg",GRC:"grc",GUJ:"guj",HAT:"hat",HEB:"heb",HIN:"hin",HRV:"hrv",HUN:"hun",IKU:"iku",IND:"ind",ISL:"isl",ITA:"ita",ITA_OLD:"ita_old",JAV:"jav",JPN:"jpn",KAN:"kan",KAT:"kat",KAT_OLD:"kat_old",KAZ:"kaz",KHM:"khm",KIR:"kir",KOR:"kor",KUR:"kur",LAO:"lao",LAT:"lat",LAV:"lav",LIT:"lit",MAL:"mal",MAR:"mar",MKD:"mkd",MLT:"mlt",MSA:"msa",MYA:"mya",NEP:"nep",NLD:"nld",NOR:"nor",ORI:"ori",PAN:"pan",POL:"pol",POR:"por",PUS:"pus",RON:"ron",RUS:"rus",SAN:"san",SIN:"sin",SLK:"slk",SLV:"slv",SPA:"spa",SPA_OLD:"spa_old",SQI:"sqi",SRP:"srp",SRP_LATN:"srp_latn",SWA:"swa",SWE:"swe",SYR:"syr",TAM:"tam",TEL:"tel",TGK:"tgk",TGL:"tgl",THA:"tha",TIR:"tir",TUR:"tur",UIG:"uig",UKR:"ukr",URD:"urd",UZB:"uzb",UZB_CYRL:"uzb_cyrl",VIE:"vie",YID:"yid"};},13:(t,r,e)=>{var n=e(857),o=0;t.exports=function(t){var r=t.id,e=t.action,i=t.payload,a=void 0===i?{}:i,c=r;return void 0===c&&(c=n("Job",o),o+=1),{id:c,action:e,payload:a}};},695:function(t,r,e){function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}var o=this;function i(){i=function(){return t};var t={},r=Object.prototype,e=r.hasOwnProperty,o=Object.defineProperty||function(t,r,e){t[r]=e.value;},a="function"==typeof Symbol?Symbol:{},c=a.iterator||"@@iterator",u=a.asyncIterator||"@@asyncIterator",f=a.toStringTag||"@@toStringTag";function l(t,r,e){return Object.defineProperty(t,r,{value:e,enumerable:!0,configurable:!0,writable:!0}),t[r]}try{l({},"");}catch(t){l=function(t,r,e){return t[r]=e};}function s(t,r,e,n){var i=r&&r.prototype instanceof y?r:y,a=Object.create(i.prototype),c=new P(n||[]);return o(a,"_invoke",{value:O(t,e,c)}),a}function h(t,r,e){try{return {type:"normal",arg:t.call(r,e)}}catch(t){return {type:"throw",arg:t}}}t.wrap=s;var p={};function y(){}function v(){}function d(){}var g={};l(g,c,(function(){return this}));var m=Object.getPrototypeOf,b=m&&m(m(_([])));b&&b!==r&&e.call(b,c)&&(g=b);var w=d.prototype=y.prototype=Object.create(g);function x(t){["next","throw","return"].forEach((function(r){l(t,r,(function(t){return this._invoke(r,t)}));}));}function L(t,r){function i(o,a,c,u){var f=h(t[o],t,a);if("throw"!==f.type){var l=f.arg,s=l.value;return s&&"object"==n(s)&&e.call(s,"__await")?r.resolve(s.__await).then((function(t){i("next",t,c,u);}),(function(t){i("throw",t,c,u);})):r.resolve(s).then((function(t){l.value=t,c(l);}),(function(t){return i("throw",t,c,u)}))}u(f.arg);}var a;o(this,"_invoke",{value:function(t,e){function n(){return new r((function(r,n){i(t,e,r,n);}))}return a=a?a.then(n,n):n()}});}function O(t,r,e){var n="suspendedStart";return function(o,i){if("executing"===n)throw new Error("Generator is already running");if("completed"===n){if("throw"===o)throw i;return {value:void 0,done:!0}}for(e.method=o,e.arg=i;;){var a=e.delegate;if(a){var c=E(a,e);if(c){if(c===p)continue;return c}}if("next"===e.method)e.sent=e._sent=e.arg;else if("throw"===e.method){if("suspendedStart"===n)throw n="completed",e.arg;e.dispatchException(e.arg);}else "return"===e.method&&e.abrupt("return",e.arg);n="executing";var u=h(t,r,e);if("normal"===u.type){if(n=e.done?"completed":"suspendedYield",u.arg===p)continue;return {value:u.arg,done:e.done}}"throw"===u.type&&(n="completed",e.method="throw",e.arg=u.arg);}}}function E(t,r){var e=r.method,n=t.iterator[e];if(void 0===n)return r.delegate=null,"throw"===e&&t.iterator.return&&(r.method="return",r.arg=void 0,E(t,r),"throw"===r.method)||"return"!==e&&(r.method="throw",r.arg=new TypeError("The iterator does not provide a '"+e+"' method")),p;var o=h(n,t.iterator,r.arg);if("throw"===o.type)return r.method="throw",r.arg=o.arg,r.delegate=null,p;var i=o.arg;return i?i.done?(r[t.resultName]=i.value,r.next=t.nextLoc,"return"!==r.method&&(r.method="next",r.arg=void 0),r.delegate=null,p):i:(r.method="throw",r.arg=new TypeError("iterator result is not an object"),r.delegate=null,p)}function S(t){var r={tryLoc:t[0]};1 in t&&(r.catchLoc=t[1]),2 in t&&(r.finallyLoc=t[2],r.afterLoc=t[3]),this.tryEntries.push(r);}function j(t){var r=t.completion||{};r.type="normal",delete r.arg,t.completion=r;}function P(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(S,this),this.reset(!0);}function _(t){if(t){var r=t[c];if(r)return r.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var n=-1,o=function r(){for(;++n<t.length;)if(e.call(t,n))return r.value=t[n],r.done=!1,r;return r.value=void 0,r.done=!0,r};return o.next=o}}return {next:k}}function k(){return {value:void 0,done:!0}}return v.prototype=d,o(w,"constructor",{value:d,configurable:!0}),o(d,"constructor",{value:v,configurable:!0}),v.displayName=l(d,f,"GeneratorFunction"),t.isGeneratorFunction=function(t){var r="function"==typeof t&&t.constructor;return !!r&&(r===v||"GeneratorFunction"===(r.displayName||r.name))},t.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,d):(t.__proto__=d,l(t,f,"GeneratorFunction")),t.prototype=Object.create(w),t},t.awrap=function(t){return {__await:t}},x(L.prototype),l(L.prototype,u,(function(){return this})),t.AsyncIterator=L,t.async=function(r,e,n,o,i){void 0===i&&(i=Promise);var a=new L(s(r,e,n,o),i);return t.isGeneratorFunction(e)?a:a.next().then((function(t){return t.done?t.value:a.next()}))},x(w),l(w,f,"Generator"),l(w,c,(function(){return this})),l(w,"toString",(function(){return "[object Generator]"})),t.keys=function(t){var r=Object(t),e=[];for(var n in r)e.push(n);return e.reverse(),function t(){for(;e.length;){var n=e.pop();if(n in r)return t.value=n,t.done=!1,t}return t.done=!0,t}},t.values=_,P.prototype={constructor:P,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=void 0,this.done=!1,this.delegate=null,this.method="next",this.arg=void 0,this.tryEntries.forEach(j),!t)for(var r in this)"t"===r.charAt(0)&&e.call(this,r)&&!isNaN(+r.slice(1))&&(this[r]=void 0);},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var r=this;function n(e,n){return a.type="throw",a.arg=t,r.next=e,n&&(r.method="next",r.arg=void 0),!!n}for(var o=this.tryEntries.length-1;o>=0;--o){var i=this.tryEntries[o],a=i.completion;if("root"===i.tryLoc)return n("end");if(i.tryLoc<=this.prev){var c=e.call(i,"catchLoc"),u=e.call(i,"finallyLoc");if(c&&u){if(this.prev<i.catchLoc)return n(i.catchLoc,!0);if(this.prev<i.finallyLoc)return n(i.finallyLoc)}else if(c){if(this.prev<i.catchLoc)return n(i.catchLoc,!0)}else {if(!u)throw new Error("try statement without catch or finally");if(this.prev<i.finallyLoc)return n(i.finallyLoc)}}}},abrupt:function(t,r){for(var n=this.tryEntries.length-1;n>=0;--n){var o=this.tryEntries[n];if(o.tryLoc<=this.prev&&e.call(o,"finallyLoc")&&this.prev<o.finallyLoc){var i=o;break}}i&&("break"===t||"continue"===t)&&i.tryLoc<=r&&r<=i.finallyLoc&&(i=null);var a=i?i.completion:{};return a.type=t,a.arg=r,i?(this.method="next",this.next=i.finallyLoc,p):this.complete(a)},complete:function(t,r){if("throw"===t.type)throw t.arg;return "break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&r&&(this.next=r),p},finish:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.finallyLoc===t)return this.complete(e.completion,e.afterLoc),j(e),p}},catch:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.tryLoc===t){var n=e.completion;if("throw"===n.type){var o=n.arg;j(e);}return o}}throw new Error("illegal catch attempt")},delegateYield:function(t,r,e){return this.delegate={iterator:_(t),resultName:r,nextLoc:e},"next"===this.method&&(this.arg=void 0),p}},t}function a(t,r){(null==r||r>t.length)&&(r=t.length);for(var e=0,n=new Array(r);e<r;e++)n[e]=t[e];return n}function c(t,r,e,n,o,i,a){try{var c=t[i](a),u=c.value;}catch(t){return void e(t)}c.done?r(u):Promise.resolve(u).then(n,o);}function u(t){return function(){var r=this,e=arguments;return new Promise((function(n,o){var i=t.apply(r,e);function a(t){c(i,n,o,a,u,"next",t);}function u(t){c(i,n,o,a,u,"throw",t);}a(void 0);}))}}var f=e(13),l=e(86).log,s=e(857),h=0;t.exports=function(){var t=s("Scheduler",h),r={},e={},n=[];h+=1;var c=function(){return Object.keys(r).length},p=function(){if(0!==n.length)for(var t=Object.keys(r),o=0;o<t.length;o+=1)if(void 0===e[t[o]]){n[0](r[t[o]]);break}},y=function(r,c){return new Promise((function(s,h){var y=f({action:r,payload:c});n.push(function(){var t=u(i().mark((function t(u){return i().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n.shift(),e[u.id]=y,t.prev=2,t.t0=s,t.next=6,u[r].apply(o,[].concat(function(t){if(Array.isArray(t))return a(t)}(i=c)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(i)||function(t,r){if(t){if("string"==typeof t)return a(t,r);var e=Object.prototype.toString.call(t).slice(8,-1);return "Object"===e&&t.constructor&&(e=t.constructor.name),"Map"===e||"Set"===e?Array.from(t):"Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e)?a(t,r):void 0}}(i)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(),[y.id]));case 6:t.t1=t.sent,(0, t.t0)(t.t1),t.next=13;break;case 10:t.prev=10,t.t2=t.catch(2),h(t.t2);case 13:return t.prev=13,delete e[u.id],p(),t.finish(13);case 17:case"end":return t.stop()}var i;}),t,null,[[2,10,13,17]])})));return function(r){return t.apply(this,arguments)}}()),l("[".concat(t,"]: Add ").concat(y.id," to JobQueue")),l("[".concat(t,"]: JobQueue length=").concat(n.length)),p();}))},v=function(){var r=u(i().mark((function r(e){var n,o,a,u=arguments;return i().wrap((function(r){for(;;)switch(r.prev=r.next){case 0:if(0!==c()){r.next=2;break}throw Error("[".concat(t,"]: You need to have at least one worker before adding jobs"));case 2:for(n=u.length,o=new Array(n>1?n-1:0),a=1;a<n;a++)o[a-1]=u[a];return r.abrupt("return",y(e,o));case 4:case"end":return r.stop()}}),r)})));return function(t){return r.apply(this,arguments)}}(),d=function(){var t=u(i().mark((function t(){return i().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:Object.keys(r).forEach(function(){var t=u(i().mark((function t(e){return i().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,r[e].terminate();case 2:case"end":return t.stop()}}),t)})));return function(r){return t.apply(this,arguments)}}()),n=[];case 2:case"end":return t.stop()}}),t)})));return function(){return t.apply(this,arguments)}}();return {addWorker:function(e){return r[e.id]=e,l("[".concat(t,"]: Add ").concat(e.id)),l("[".concat(t,"]: Number of workers=").concat(c())),p(),e.id},addJob:v,terminate:d,getQueueLen:function(){return n.length},getNumWorkers:c}};},738:(t,r,e)=>{function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}var o=["logger","errorHandler"];function i(){i=function(){return t};var t={},r=Object.prototype,e=r.hasOwnProperty,o=Object.defineProperty||function(t,r,e){t[r]=e.value;},a="function"==typeof Symbol?Symbol:{},c=a.iterator||"@@iterator",u=a.asyncIterator||"@@asyncIterator",f=a.toStringTag||"@@toStringTag";function l(t,r,e){return Object.defineProperty(t,r,{value:e,enumerable:!0,configurable:!0,writable:!0}),t[r]}try{l({},"");}catch(t){l=function(t,r,e){return t[r]=e};}function s(t,r,e,n){var i=r&&r.prototype instanceof y?r:y,a=Object.create(i.prototype),c=new P(n||[]);return o(a,"_invoke",{value:O(t,e,c)}),a}function h(t,r,e){try{return {type:"normal",arg:t.call(r,e)}}catch(t){return {type:"throw",arg:t}}}t.wrap=s;var p={};function y(){}function v(){}function d(){}var g={};l(g,c,(function(){return this}));var m=Object.getPrototypeOf,b=m&&m(m(_([])));b&&b!==r&&e.call(b,c)&&(g=b);var w=d.prototype=y.prototype=Object.create(g);function x(t){["next","throw","return"].forEach((function(r){l(t,r,(function(t){return this._invoke(r,t)}));}));}function L(t,r){function i(o,a,c,u){var f=h(t[o],t,a);if("throw"!==f.type){var l=f.arg,s=l.value;return s&&"object"==n(s)&&e.call(s,"__await")?r.resolve(s.__await).then((function(t){i("next",t,c,u);}),(function(t){i("throw",t,c,u);})):r.resolve(s).then((function(t){l.value=t,c(l);}),(function(t){return i("throw",t,c,u)}))}u(f.arg);}var a;o(this,"_invoke",{value:function(t,e){function n(){return new r((function(r,n){i(t,e,r,n);}))}return a=a?a.then(n,n):n()}});}function O(t,r,e){var n="suspendedStart";return function(o,i){if("executing"===n)throw new Error("Generator is already running");if("completed"===n){if("throw"===o)throw i;return {value:void 0,done:!0}}for(e.method=o,e.arg=i;;){var a=e.delegate;if(a){var c=E(a,e);if(c){if(c===p)continue;return c}}if("next"===e.method)e.sent=e._sent=e.arg;else if("throw"===e.method){if("suspendedStart"===n)throw n="completed",e.arg;e.dispatchException(e.arg);}else "return"===e.method&&e.abrupt("return",e.arg);n="executing";var u=h(t,r,e);if("normal"===u.type){if(n=e.done?"completed":"suspendedYield",u.arg===p)continue;return {value:u.arg,done:e.done}}"throw"===u.type&&(n="completed",e.method="throw",e.arg=u.arg);}}}function E(t,r){var e=r.method,n=t.iterator[e];if(void 0===n)return r.delegate=null,"throw"===e&&t.iterator.return&&(r.method="return",r.arg=void 0,E(t,r),"throw"===r.method)||"return"!==e&&(r.method="throw",r.arg=new TypeError("The iterator does not provide a '"+e+"' method")),p;var o=h(n,t.iterator,r.arg);if("throw"===o.type)return r.method="throw",r.arg=o.arg,r.delegate=null,p;var i=o.arg;return i?i.done?(r[t.resultName]=i.value,r.next=t.nextLoc,"return"!==r.method&&(r.method="next",r.arg=void 0),r.delegate=null,p):i:(r.method="throw",r.arg=new TypeError("iterator result is not an object"),r.delegate=null,p)}function S(t){var r={tryLoc:t[0]};1 in t&&(r.catchLoc=t[1]),2 in t&&(r.finallyLoc=t[2],r.afterLoc=t[3]),this.tryEntries.push(r);}function j(t){var r=t.completion||{};r.type="normal",delete r.arg,t.completion=r;}function P(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(S,this),this.reset(!0);}function _(t){if(t){var r=t[c];if(r)return r.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var n=-1,o=function r(){for(;++n<t.length;)if(e.call(t,n))return r.value=t[n],r.done=!1,r;return r.value=void 0,r.done=!0,r};return o.next=o}}return {next:k}}function k(){return {value:void 0,done:!0}}return v.prototype=d,o(w,"constructor",{value:d,configurable:!0}),o(d,"constructor",{value:v,configurable:!0}),v.displayName=l(d,f,"GeneratorFunction"),t.isGeneratorFunction=function(t){var r="function"==typeof t&&t.constructor;return !!r&&(r===v||"GeneratorFunction"===(r.displayName||r.name))},t.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,d):(t.__proto__=d,l(t,f,"GeneratorFunction")),t.prototype=Object.create(w),t},t.awrap=function(t){return {__await:t}},x(L.prototype),l(L.prototype,u,(function(){return this})),t.AsyncIterator=L,t.async=function(r,e,n,o,i){void 0===i&&(i=Promise);var a=new L(s(r,e,n,o),i);return t.isGeneratorFunction(e)?a:a.next().then((function(t){return t.done?t.value:a.next()}))},x(w),l(w,f,"Generator"),l(w,c,(function(){return this})),l(w,"toString",(function(){return "[object Generator]"})),t.keys=function(t){var r=Object(t),e=[];for(var n in r)e.push(n);return e.reverse(),function t(){for(;e.length;){var n=e.pop();if(n in r)return t.value=n,t.done=!1,t}return t.done=!0,t}},t.values=_,P.prototype={constructor:P,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=void 0,this.done=!1,this.delegate=null,this.method="next",this.arg=void 0,this.tryEntries.forEach(j),!t)for(var r in this)"t"===r.charAt(0)&&e.call(this,r)&&!isNaN(+r.slice(1))&&(this[r]=void 0);},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var r=this;function n(e,n){return a.type="throw",a.arg=t,r.next=e,n&&(r.method="next",r.arg=void 0),!!n}for(var o=this.tryEntries.length-1;o>=0;--o){var i=this.tryEntries[o],a=i.completion;if("root"===i.tryLoc)return n("end");if(i.tryLoc<=this.prev){var c=e.call(i,"catchLoc"),u=e.call(i,"finallyLoc");if(c&&u){if(this.prev<i.catchLoc)return n(i.catchLoc,!0);if(this.prev<i.finallyLoc)return n(i.finallyLoc)}else if(c){if(this.prev<i.catchLoc)return n(i.catchLoc,!0)}else {if(!u)throw new Error("try statement without catch or finally");if(this.prev<i.finallyLoc)return n(i.finallyLoc)}}}},abrupt:function(t,r){for(var n=this.tryEntries.length-1;n>=0;--n){var o=this.tryEntries[n];if(o.tryLoc<=this.prev&&e.call(o,"finallyLoc")&&this.prev<o.finallyLoc){var i=o;break}}i&&("break"===t||"continue"===t)&&i.tryLoc<=r&&r<=i.finallyLoc&&(i=null);var a=i?i.completion:{};return a.type=t,a.arg=r,i?(this.method="next",this.next=i.finallyLoc,p):this.complete(a)},complete:function(t,r){if("throw"===t.type)throw t.arg;return "break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&r&&(this.next=r),p},finish:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.finallyLoc===t)return this.complete(e.completion,e.afterLoc),j(e),p}},catch:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.tryLoc===t){var n=e.completion;if("throw"===n.type){var o=n.arg;j(e);}return o}}throw new Error("illegal catch attempt")},delegateYield:function(t,r,e){return this.delegate={iterator:_(t),resultName:r,nextLoc:e},"next"===this.method&&(this.arg=void 0),p}},t}function a(t,r){(null==r||r>t.length)&&(r=t.length);for(var e=0,n=new Array(r);e<r;e++)n[e]=t[e];return n}function c(t,r){var e=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(t,r).enumerable}))),e.push.apply(e,n);}return e}function u(t){for(var r=1;r<arguments.length;r++){var e=null!=arguments[r]?arguments[r]:{};r%2?c(Object(e),!0).forEach((function(r){f(t,r,e[r]);})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(e)):c(Object(e)).forEach((function(r){Object.defineProperty(t,r,Object.getOwnPropertyDescriptor(e,r));}));}return t}function f(t,r,e){return (r=function(t){var r=function(t){if("object"!==n(t)||null===t)return t;var r=t[Symbol.toPrimitive];if(void 0!==r){var e=r.call(t,"string");if("object"!==n(e))return e;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return "symbol"===n(r)?r:String(r)}(r))in t?Object.defineProperty(t,r,{value:e,enumerable:!0,configurable:!0,writable:!0}):t[r]=e,t}function l(t,r){if(null==t)return {};var e,n,o=function(t,r){if(null==t)return {};var e,n,o={},i=Object.keys(t);for(n=0;n<i.length;n++)e=i[n],r.indexOf(e)>=0||(o[e]=t[e]);return o}(t,r);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(n=0;n<i.length;n++)e=i[n],r.indexOf(e)>=0||Object.prototype.propertyIsEnumerable.call(t,e)&&(o[e]=t[e]);}return o}function s(t,r,e,n,o,i,a){try{var c=t[i](a),u=c.value;}catch(t){return void e(t)}c.done?r(u):Promise.resolve(u).then(n,o);}function h(t){return function(){var r=this,e=arguments;return new Promise((function(n,o){var i=t.apply(r,e);function a(t){s(i,n,o,a,c,"next",t);}function c(t){s(i,n,o,a,c,"throw",t);}a(void 0);}))}}var p=e(898),y=e(13),v=e(86).log,d=e(857),g=e(287),m=e(250),b=m.defaultOptions,w=m.spawnWorker,x=m.terminateWorker,L=m.onMessage,O=m.loadImage,E=m.send,S=0;t.exports=h(i().mark((function t(){var r,e,n,c,f,s,m,j,P,_,k,T,N,A,G,I,F,R,D,M,C,U,Y,B,H,K,W,z,J,V,Z,Q,q,X,$=arguments;return i().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return r=$.length>0&&void 0!==$[0]?$[0]:"eng",e=$.length>1&&void 0!==$[1]?$[1]:g.LSTM_ONLY,n=$.length>2&&void 0!==$[2]?$[2]:{},c=$.length>3&&void 0!==$[3]?$[3]:{},f=d("Worker",S),s=p(u(u({},b),n)),m=s.logger,j=s.errorHandler,P=l(s,o),_={},k="string"==typeof r?r.split("+"):r,T=e,N=c,A=[g.DEFAULT,g.LSTM_ONLY].includes(e)&&!P.legacyCore,F=new Promise((function(t,r){I=t,G=r;})),R=function(t){G(t.message);},(D=w(P)).onerror=R,S+=1,M=function(t){var r=t.id,e=t.action,n=t.payload;return new Promise((function(t,o){v("[".concat(f,"]: Start ").concat(r,", action=").concat(e));var i="".concat(e,"-").concat(r);_[i]={resolve:t,reject:o},E(D,{workerId:f,jobId:r,action:e,payload:n});}))},C=function(){return console.warn("`load` is depreciated and should be removed from code (workers now come pre-loaded)")},U=function(t){return M(y({id:t,action:"load",payload:{options:{lstmOnly:A,corePath:P.corePath,logging:P.logging}}}))},Y=function(t,r,e){return M(y({id:e,action:"FS",payload:{method:"writeFile",args:[t,r]}}))},B=function(t,r){return M(y({id:r,action:"FS",payload:{method:"readFile",args:[t,{encoding:"utf8"}]}}))},H=function(t,r){return M(y({id:r,action:"FS",payload:{method:"unlink",args:[t]}}))},K=function(t,r,e){return M(y({id:e,action:"FS",payload:{method:t,args:r}}))},W=function(t,r){return M(y({id:r,action:"loadLanguage",payload:{langs:t,options:{langPath:P.langPath,dataPath:P.dataPath,cachePath:P.cachePath,cacheMethod:P.cacheMethod,gzip:P.gzip,lstmOnly:[g.DEFAULT,g.LSTM_ONLY].includes(T)&&!P.legacyLang}}}))},z=function(t,r,e,n){return M(y({id:n,action:"initialize",payload:{langs:t,oem:r,config:e}}))},J=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"eng",r=arguments.length>1?arguments[1]:void 0,e=arguments.length>2?arguments[2]:void 0,n=arguments.length>3?arguments[3]:void 0;if(A&&[g.TESSERACT_ONLY,g.TESSERACT_LSTM_COMBINED].includes(r))throw Error("Legacy model requested but code missing.");var o=r||T;T=o;var i=e||N;N=i;var c,u=("string"==typeof t?t.split("+"):t).filter((function(t){return !k.includes(t)}));return k.push.apply(k,function(t){if(Array.isArray(t))return a(t)}(c=u)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(c)||function(t,r){if(t){if("string"==typeof t)return a(t,r);var e=Object.prototype.toString.call(t).slice(8,-1);return "Object"===e&&t.constructor&&(e=t.constructor.name),"Map"===e||"Set"===e?Array.from(t):"Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e)?a(t,r):void 0}}(c)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),u.length>0?W(u,n).then((function(){return z(t,o,i,n)})):z(t,o,i,n)},V=function(){return M(y({id:arguments.length>1?arguments[1]:void 0,action:"setParameters",payload:{params:arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}}}))},Z=function(){var t=h(i().mark((function t(r){var e,n,o,a=arguments;return i().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return e=a.length>1&&void 0!==a[1]?a[1]:{},n=a.length>2&&void 0!==a[2]?a[2]:{text:!0},o=a.length>3?a[3]:void 0,t.t0=M,t.t1=y,t.t2=o,t.next=8,O(r);case 8:return t.t3=t.sent,t.t4=e,t.t5=n,t.t6={image:t.t3,options:t.t4,output:t.t5},t.t7={id:t.t2,action:"recognize",payload:t.t6},t.t8=(0, t.t1)(t.t7),t.abrupt("return",(0, t.t0)(t.t8));case 15:case"end":return t.stop()}}),t)})));return function(r){return t.apply(this,arguments)}}(),Q=function(){var t=h(i().mark((function t(r,e){return i().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if(!A){t.next=2;break}throw Error("`worker.detect` requires Legacy model, which was not loaded.");case 2:return t.t0=M,t.t1=y,t.t2=e,t.next=7,O(r);case 7:return t.t3=t.sent,t.t4={image:t.t3},t.t5={id:t.t2,action:"detect",payload:t.t4},t.t6=(0, t.t1)(t.t5),t.abrupt("return",(0, t.t0)(t.t6));case 12:case"end":return t.stop()}}),t)})));return function(r,e){return t.apply(this,arguments)}}(),q=function(){var t=h(i().mark((function t(){return i().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return null!==D&&(x(D),D=null),t.abrupt("return",Promise.resolve());case 2:case"end":return t.stop()}}),t)})));return function(){return t.apply(this,arguments)}}(),L(D,(function(t){var r=t.workerId,e=t.jobId,n=t.status,o=t.action,i=t.data,a="".concat(o,"-").concat(e);if("resolve"===n)v("[".concat(r,"]: Complete ").concat(e)),_[a].resolve({jobId:e,data:i}),delete _[a];else if("reject"===n){if(_[a].reject(i),delete _[a],"load"===o&&G(i),!j)throw Error(i);j(i);}else "progress"===n&&m(u(u({},i),{},{userJobId:e}));})),X={id:f,worker:D,load:C,writeText:Y,readText:B,removeFile:H,FS:K,reinitialize:J,setParameters:V,recognize:Z,detect:Q,terminate:q},U().then((function(){return W(r)})).then((function(){return z(r,e,c)})).then((function(){return I(X)})).catch((function(){})),t.abrupt("return",F);case 34:case"end":return t.stop()}}),t)})));},954:(t,r,e)=>{function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}function o(t,r){var e=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(t,r).enumerable}))),e.push.apply(e,n);}return e}function i(t,r,e){return (r=function(t){var r=function(t){if("object"!==n(t)||null===t)return t;var r=t[Symbol.toPrimitive];if(void 0!==r){var e=r.call(t,"string");if("object"!==n(e))return e;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return "symbol"===n(r)?r:String(r)}(r))in t?Object.defineProperty(t,r,{value:e,enumerable:!0,configurable:!0,writable:!0}):t[r]=e,t}e(30);var a=e(695),c=e(738),u=e(52),f=e(11),l=e(287),s=e(188),h=e(86).setLogging;t.exports=function(t){for(var r=1;r<arguments.length;r++){var e=null!=arguments[r]?arguments[r]:{};r%2?o(Object(e),!0).forEach((function(r){i(t,r,e[r]);})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(e)):o(Object(e)).forEach((function(r){Object.defineProperty(t,r,Object.getOwnPropertyDescriptor(e,r));}));}return t}({languages:f,OEM:l,PSM:s,createScheduler:a,createWorker:c,setLogging:h},u);},827:t=>{function r(t){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},r(t)}t.exports=function(t){var e={};return "undefined"!=typeof WorkerGlobalScope?e.type="webworker":"object"===("undefined"==typeof document?"undefined":r(document))?e.type="browser":"object"===("undefined"==typeof process?"undefined":r(process))&&(e.type="node"),void 0===t?e:e[t]};},857:t=>{t.exports=function(t,r){return "".concat(t,"-").concat(r,"-").concat(Math.random().toString(16).slice(3,8))};},86:function(t,r){var e=this,n=!1;r.logging=n,r.setLogging=function(t){n=t;},r.log=function(){for(var t=arguments.length,r=new Array(t),o=0;o<t;o++)r[o]=arguments[o];return n?console.log.apply(e,r):null};},898:(t,r,e)=>{function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}function o(t,r){var e=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(t,r).enumerable}))),e.push.apply(e,n);}return e}function i(t,r,e){return (r=function(t){var r=function(t){if("object"!==n(t)||null===t)return t;var r=t[Symbol.toPrimitive];if(void 0!==r){var e=r.call(t,"string");if("object"!==n(e))return e;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return "symbol"===n(r)?r:String(r)}(r))in t?Object.defineProperty(t,r,{value:e,enumerable:!0,configurable:!0,writable:!0}):t[r]=e,t}var a="browser"===e(827)("type")?function(t){return new URL(t,window.location.href).href}:function(t){return t};t.exports=function(t){var r=function(t){for(var r=1;r<arguments.length;r++){var e=null!=arguments[r]?arguments[r]:{};r%2?o(Object(e),!0).forEach((function(r){i(t,r,e[r]);})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(e)):o(Object(e)).forEach((function(r){Object.defineProperty(t,r,Object.getOwnPropertyDescriptor(e,r));}));}return t}({},t);return ["corePath","workerPath","langPath"].forEach((function(e){t[e]&&(r[e]=a(r[e]));})),r};},989:(t,r,e)=>{function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}function o(t,r){var e=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);r&&(n=n.filter((function(r){return Object.getOwnPropertyDescriptor(t,r).enumerable}))),e.push.apply(e,n);}return e}function i(t){for(var r=1;r<arguments.length;r++){var e=null!=arguments[r]?arguments[r]:{};r%2?o(Object(e),!0).forEach((function(r){a(t,r,e[r]);})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(e)):o(Object(e)).forEach((function(r){Object.defineProperty(t,r,Object.getOwnPropertyDescriptor(e,r));}));}return t}function a(t,r,e){return (r=function(t){var r=function(t){if("object"!==n(t)||null===t)return t;var r=t[Symbol.toPrimitive];if(void 0!==r){var e=r.call(t,"string");if("object"!==n(e))return e;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return "symbol"===n(r)?r:String(r)}(r))in t?Object.defineProperty(t,r,{value:e,enumerable:!0,configurable:!0,writable:!0}):t[r]=e,t}var c=e(330).rE,u=e(491);t.exports=i(i({},u),{},{workerPath:"https://cdn.jsdelivr.net/npm/tesseract.js@v".concat(c,"/dist/worker.min.js")});},250:(t,r,e)=>{var n=e(989),o=e(423),i=e(399),a=e(278),c=e(782),u=e(383);t.exports={defaultOptions:n,spawnWorker:o,terminateWorker:i,onMessage:a,send:c,loadImage:u};},383:t=>{function r(t){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},r(t)}function e(){e=function(){return t};var t={},n=Object.prototype,o=n.hasOwnProperty,i=Object.defineProperty||function(t,r,e){t[r]=e.value;},a="function"==typeof Symbol?Symbol:{},c=a.iterator||"@@iterator",u=a.asyncIterator||"@@asyncIterator",f=a.toStringTag||"@@toStringTag";function l(t,r,e){return Object.defineProperty(t,r,{value:e,enumerable:!0,configurable:!0,writable:!0}),t[r]}try{l({},"");}catch(t){l=function(t,r,e){return t[r]=e};}function s(t,r,e,n){var o=r&&r.prototype instanceof y?r:y,a=Object.create(o.prototype),c=new P(n||[]);return i(a,"_invoke",{value:O(t,e,c)}),a}function h(t,r,e){try{return {type:"normal",arg:t.call(r,e)}}catch(t){return {type:"throw",arg:t}}}t.wrap=s;var p={};function y(){}function v(){}function d(){}var g={};l(g,c,(function(){return this}));var m=Object.getPrototypeOf,b=m&&m(m(_([])));b&&b!==n&&o.call(b,c)&&(g=b);var w=d.prototype=y.prototype=Object.create(g);function x(t){["next","throw","return"].forEach((function(r){l(t,r,(function(t){return this._invoke(r,t)}));}));}function L(t,e){function n(i,a,c,u){var f=h(t[i],t,a);if("throw"!==f.type){var l=f.arg,s=l.value;return s&&"object"==r(s)&&o.call(s,"__await")?e.resolve(s.__await).then((function(t){n("next",t,c,u);}),(function(t){n("throw",t,c,u);})):e.resolve(s).then((function(t){l.value=t,c(l);}),(function(t){return n("throw",t,c,u)}))}u(f.arg);}var a;i(this,"_invoke",{value:function(t,r){function o(){return new e((function(e,o){n(t,r,e,o);}))}return a=a?a.then(o,o):o()}});}function O(t,r,e){var n="suspendedStart";return function(o,i){if("executing"===n)throw new Error("Generator is already running");if("completed"===n){if("throw"===o)throw i;return {value:void 0,done:!0}}for(e.method=o,e.arg=i;;){var a=e.delegate;if(a){var c=E(a,e);if(c){if(c===p)continue;return c}}if("next"===e.method)e.sent=e._sent=e.arg;else if("throw"===e.method){if("suspendedStart"===n)throw n="completed",e.arg;e.dispatchException(e.arg);}else "return"===e.method&&e.abrupt("return",e.arg);n="executing";var u=h(t,r,e);if("normal"===u.type){if(n=e.done?"completed":"suspendedYield",u.arg===p)continue;return {value:u.arg,done:e.done}}"throw"===u.type&&(n="completed",e.method="throw",e.arg=u.arg);}}}function E(t,r){var e=r.method,n=t.iterator[e];if(void 0===n)return r.delegate=null,"throw"===e&&t.iterator.return&&(r.method="return",r.arg=void 0,E(t,r),"throw"===r.method)||"return"!==e&&(r.method="throw",r.arg=new TypeError("The iterator does not provide a '"+e+"' method")),p;var o=h(n,t.iterator,r.arg);if("throw"===o.type)return r.method="throw",r.arg=o.arg,r.delegate=null,p;var i=o.arg;return i?i.done?(r[t.resultName]=i.value,r.next=t.nextLoc,"return"!==r.method&&(r.method="next",r.arg=void 0),r.delegate=null,p):i:(r.method="throw",r.arg=new TypeError("iterator result is not an object"),r.delegate=null,p)}function S(t){var r={tryLoc:t[0]};1 in t&&(r.catchLoc=t[1]),2 in t&&(r.finallyLoc=t[2],r.afterLoc=t[3]),this.tryEntries.push(r);}function j(t){var r=t.completion||{};r.type="normal",delete r.arg,t.completion=r;}function P(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(S,this),this.reset(!0);}function _(t){if(t){var r=t[c];if(r)return r.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var e=-1,n=function r(){for(;++e<t.length;)if(o.call(t,e))return r.value=t[e],r.done=!1,r;return r.value=void 0,r.done=!0,r};return n.next=n}}return {next:k}}function k(){return {value:void 0,done:!0}}return v.prototype=d,i(w,"constructor",{value:d,configurable:!0}),i(d,"constructor",{value:v,configurable:!0}),v.displayName=l(d,f,"GeneratorFunction"),t.isGeneratorFunction=function(t){var r="function"==typeof t&&t.constructor;return !!r&&(r===v||"GeneratorFunction"===(r.displayName||r.name))},t.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,d):(t.__proto__=d,l(t,f,"GeneratorFunction")),t.prototype=Object.create(w),t},t.awrap=function(t){return {__await:t}},x(L.prototype),l(L.prototype,u,(function(){return this})),t.AsyncIterator=L,t.async=function(r,e,n,o,i){void 0===i&&(i=Promise);var a=new L(s(r,e,n,o),i);return t.isGeneratorFunction(e)?a:a.next().then((function(t){return t.done?t.value:a.next()}))},x(w),l(w,f,"Generator"),l(w,c,(function(){return this})),l(w,"toString",(function(){return "[object Generator]"})),t.keys=function(t){var r=Object(t),e=[];for(var n in r)e.push(n);return e.reverse(),function t(){for(;e.length;){var n=e.pop();if(n in r)return t.value=n,t.done=!1,t}return t.done=!0,t}},t.values=_,P.prototype={constructor:P,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=void 0,this.done=!1,this.delegate=null,this.method="next",this.arg=void 0,this.tryEntries.forEach(j),!t)for(var r in this)"t"===r.charAt(0)&&o.call(this,r)&&!isNaN(+r.slice(1))&&(this[r]=void 0);},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var r=this;function e(e,n){return a.type="throw",a.arg=t,r.next=e,n&&(r.method="next",r.arg=void 0),!!n}for(var n=this.tryEntries.length-1;n>=0;--n){var i=this.tryEntries[n],a=i.completion;if("root"===i.tryLoc)return e("end");if(i.tryLoc<=this.prev){var c=o.call(i,"catchLoc"),u=o.call(i,"finallyLoc");if(c&&u){if(this.prev<i.catchLoc)return e(i.catchLoc,!0);if(this.prev<i.finallyLoc)return e(i.finallyLoc)}else if(c){if(this.prev<i.catchLoc)return e(i.catchLoc,!0)}else {if(!u)throw new Error("try statement without catch or finally");if(this.prev<i.finallyLoc)return e(i.finallyLoc)}}}},abrupt:function(t,r){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc<=this.prev&&o.call(n,"finallyLoc")&&this.prev<n.finallyLoc){var i=n;break}}i&&("break"===t||"continue"===t)&&i.tryLoc<=r&&r<=i.finallyLoc&&(i=null);var a=i?i.completion:{};return a.type=t,a.arg=r,i?(this.method="next",this.next=i.finallyLoc,p):this.complete(a)},complete:function(t,r){if("throw"===t.type)throw t.arg;return "break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&r&&(this.next=r),p},finish:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.finallyLoc===t)return this.complete(e.completion,e.afterLoc),j(e),p}},catch:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.tryLoc===t){var n=e.completion;if("throw"===n.type){var o=n.arg;j(e);}return o}}throw new Error("illegal catch attempt")},delegateYield:function(t,r,e){return this.delegate={iterator:_(t),resultName:r,nextLoc:e},"next"===this.method&&(this.arg=void 0),p}},t}function n(t,r,e,n,o,i,a){try{var c=t[i](a),u=c.value;}catch(t){return void e(t)}c.done?r(u):Promise.resolve(u).then(n,o);}function o(t){return function(){var r=this,e=arguments;return new Promise((function(o,i){var a=t.apply(r,e);function c(t){n(a,o,i,c,u,"next",t);}function u(t){n(a,o,i,c,u,"throw",t);}c(void 0);}))}}var i=function(t){return new Promise((function(r,e){var n=new FileReader;n.onload=function(){r(n.result);},n.onerror=function(t){var r=t.target.error.code;e(Error("File could not be read! Code=".concat(r)));},n.readAsArrayBuffer(t);}))},a=function(){var t=o(e().mark((function t(r){var n,c,u;return e().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if(n=r,void 0!==r){t.next=3;break}return t.abrupt("return","undefined");case 3:if("string"!=typeof r){t.next=16;break}if(!/data:image\/([a-zA-Z]*);base64,([^"]*)/.test(r)){t.next=8;break}n=atob(r.split(",")[1]).split("").map((function(t){return t.charCodeAt(0)})),t.next=14;break;case 8:return t.next=10,fetch(r);case 10:return c=t.sent,t.next=13,c.arrayBuffer();case 13:n=t.sent;case 14:t.next=43;break;case 16:if(!("undefined"!=typeof HTMLElement&&r instanceof HTMLElement)){t.next=30;break}if("IMG"!==r.tagName){t.next=21;break}return t.next=20,a(r.src);case 20:n=t.sent;case 21:if("VIDEO"!==r.tagName){t.next=25;break}return t.next=24,a(r.poster);case 24:n=t.sent;case 25:if("CANVAS"!==r.tagName){t.next=28;break}return t.next=28,new Promise((function(t){r.toBlob(function(){var r=o(e().mark((function r(o){return e().wrap((function(r){for(;;)switch(r.prev=r.next){case 0:return r.next=2,i(o);case 2:n=r.sent,t();case 4:case"end":return r.stop()}}),r)})));return function(t){return r.apply(this,arguments)}}());}));case 28:t.next=43;break;case 30:if(!("undefined"!=typeof OffscreenCanvas&&r instanceof OffscreenCanvas)){t.next=39;break}return t.next=33,r.convertToBlob();case 33:return u=t.sent,t.next=36,i(u);case 36:n=t.sent,t.next=43;break;case 39:if(!(r instanceof File||r instanceof Blob)){t.next=43;break}return t.next=42,i(r);case 42:n=t.sent;case 43:return t.abrupt("return",new Uint8Array(n));case 44:case"end":return t.stop()}}),t)})));return function(r){return t.apply(this,arguments)}}();t.exports=a;},278:t=>{t.exports=function(t,r){t.onmessage=function(t){var e=t.data;r(e);};};},782:t=>{function r(t){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},r(t)}function e(){e=function(){return t};var t={},n=Object.prototype,o=n.hasOwnProperty,i=Object.defineProperty||function(t,r,e){t[r]=e.value;},a="function"==typeof Symbol?Symbol:{},c=a.iterator||"@@iterator",u=a.asyncIterator||"@@asyncIterator",f=a.toStringTag||"@@toStringTag";function l(t,r,e){return Object.defineProperty(t,r,{value:e,enumerable:!0,configurable:!0,writable:!0}),t[r]}try{l({},"");}catch(t){l=function(t,r,e){return t[r]=e};}function s(t,r,e,n){var o=r&&r.prototype instanceof y?r:y,a=Object.create(o.prototype),c=new P(n||[]);return i(a,"_invoke",{value:O(t,e,c)}),a}function h(t,r,e){try{return {type:"normal",arg:t.call(r,e)}}catch(t){return {type:"throw",arg:t}}}t.wrap=s;var p={};function y(){}function v(){}function d(){}var g={};l(g,c,(function(){return this}));var m=Object.getPrototypeOf,b=m&&m(m(_([])));b&&b!==n&&o.call(b,c)&&(g=b);var w=d.prototype=y.prototype=Object.create(g);function x(t){["next","throw","return"].forEach((function(r){l(t,r,(function(t){return this._invoke(r,t)}));}));}function L(t,e){function n(i,a,c,u){var f=h(t[i],t,a);if("throw"!==f.type){var l=f.arg,s=l.value;return s&&"object"==r(s)&&o.call(s,"__await")?e.resolve(s.__await).then((function(t){n("next",t,c,u);}),(function(t){n("throw",t,c,u);})):e.resolve(s).then((function(t){l.value=t,c(l);}),(function(t){return n("throw",t,c,u)}))}u(f.arg);}var a;i(this,"_invoke",{value:function(t,r){function o(){return new e((function(e,o){n(t,r,e,o);}))}return a=a?a.then(o,o):o()}});}function O(t,r,e){var n="suspendedStart";return function(o,i){if("executing"===n)throw new Error("Generator is already running");if("completed"===n){if("throw"===o)throw i;return {value:void 0,done:!0}}for(e.method=o,e.arg=i;;){var a=e.delegate;if(a){var c=E(a,e);if(c){if(c===p)continue;return c}}if("next"===e.method)e.sent=e._sent=e.arg;else if("throw"===e.method){if("suspendedStart"===n)throw n="completed",e.arg;e.dispatchException(e.arg);}else "return"===e.method&&e.abrupt("return",e.arg);n="executing";var u=h(t,r,e);if("normal"===u.type){if(n=e.done?"completed":"suspendedYield",u.arg===p)continue;return {value:u.arg,done:e.done}}"throw"===u.type&&(n="completed",e.method="throw",e.arg=u.arg);}}}function E(t,r){var e=r.method,n=t.iterator[e];if(void 0===n)return r.delegate=null,"throw"===e&&t.iterator.return&&(r.method="return",r.arg=void 0,E(t,r),"throw"===r.method)||"return"!==e&&(r.method="throw",r.arg=new TypeError("The iterator does not provide a '"+e+"' method")),p;var o=h(n,t.iterator,r.arg);if("throw"===o.type)return r.method="throw",r.arg=o.arg,r.delegate=null,p;var i=o.arg;return i?i.done?(r[t.resultName]=i.value,r.next=t.nextLoc,"return"!==r.method&&(r.method="next",r.arg=void 0),r.delegate=null,p):i:(r.method="throw",r.arg=new TypeError("iterator result is not an object"),r.delegate=null,p)}function S(t){var r={tryLoc:t[0]};1 in t&&(r.catchLoc=t[1]),2 in t&&(r.finallyLoc=t[2],r.afterLoc=t[3]),this.tryEntries.push(r);}function j(t){var r=t.completion||{};r.type="normal",delete r.arg,t.completion=r;}function P(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(S,this),this.reset(!0);}function _(t){if(t){var r=t[c];if(r)return r.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var e=-1,n=function r(){for(;++e<t.length;)if(o.call(t,e))return r.value=t[e],r.done=!1,r;return r.value=void 0,r.done=!0,r};return n.next=n}}return {next:k}}function k(){return {value:void 0,done:!0}}return v.prototype=d,i(w,"constructor",{value:d,configurable:!0}),i(d,"constructor",{value:v,configurable:!0}),v.displayName=l(d,f,"GeneratorFunction"),t.isGeneratorFunction=function(t){var r="function"==typeof t&&t.constructor;return !!r&&(r===v||"GeneratorFunction"===(r.displayName||r.name))},t.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,d):(t.__proto__=d,l(t,f,"GeneratorFunction")),t.prototype=Object.create(w),t},t.awrap=function(t){return {__await:t}},x(L.prototype),l(L.prototype,u,(function(){return this})),t.AsyncIterator=L,t.async=function(r,e,n,o,i){void 0===i&&(i=Promise);var a=new L(s(r,e,n,o),i);return t.isGeneratorFunction(e)?a:a.next().then((function(t){return t.done?t.value:a.next()}))},x(w),l(w,f,"Generator"),l(w,c,(function(){return this})),l(w,"toString",(function(){return "[object Generator]"})),t.keys=function(t){var r=Object(t),e=[];for(var n in r)e.push(n);return e.reverse(),function t(){for(;e.length;){var n=e.pop();if(n in r)return t.value=n,t.done=!1,t}return t.done=!0,t}},t.values=_,P.prototype={constructor:P,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=void 0,this.done=!1,this.delegate=null,this.method="next",this.arg=void 0,this.tryEntries.forEach(j),!t)for(var r in this)"t"===r.charAt(0)&&o.call(this,r)&&!isNaN(+r.slice(1))&&(this[r]=void 0);},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var r=this;function e(e,n){return a.type="throw",a.arg=t,r.next=e,n&&(r.method="next",r.arg=void 0),!!n}for(var n=this.tryEntries.length-1;n>=0;--n){var i=this.tryEntries[n],a=i.completion;if("root"===i.tryLoc)return e("end");if(i.tryLoc<=this.prev){var c=o.call(i,"catchLoc"),u=o.call(i,"finallyLoc");if(c&&u){if(this.prev<i.catchLoc)return e(i.catchLoc,!0);if(this.prev<i.finallyLoc)return e(i.finallyLoc)}else if(c){if(this.prev<i.catchLoc)return e(i.catchLoc,!0)}else {if(!u)throw new Error("try statement without catch or finally");if(this.prev<i.finallyLoc)return e(i.finallyLoc)}}}},abrupt:function(t,r){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc<=this.prev&&o.call(n,"finallyLoc")&&this.prev<n.finallyLoc){var i=n;break}}i&&("break"===t||"continue"===t)&&i.tryLoc<=r&&r<=i.finallyLoc&&(i=null);var a=i?i.completion:{};return a.type=t,a.arg=r,i?(this.method="next",this.next=i.finallyLoc,p):this.complete(a)},complete:function(t,r){if("throw"===t.type)throw t.arg;return "break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&r&&(this.next=r),p},finish:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.finallyLoc===t)return this.complete(e.completion,e.afterLoc),j(e),p}},catch:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.tryLoc===t){var n=e.completion;if("throw"===n.type){var o=n.arg;j(e);}return o}}throw new Error("illegal catch attempt")},delegateYield:function(t,r,e){return this.delegate={iterator:_(t),resultName:r,nextLoc:e},"next"===this.method&&(this.arg=void 0),p}},t}function n(t,r,e,n,o,i,a){try{var c=t[i](a),u=c.value;}catch(t){return void e(t)}c.done?r(u):Promise.resolve(u).then(n,o);}t.exports=function(){var t,r=(t=e().mark((function t(r,n){return e().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:r.postMessage(n);case 1:case"end":return t.stop()}}),t)})),function(){var r=this,e=arguments;return new Promise((function(o,i){var a=t.apply(r,e);function c(t){n(a,o,i,c,u,"next",t);}function u(t){n(a,o,i,c,u,"throw",t);}c(void 0);}))});return function(t,e){return r.apply(this,arguments)}}();},423:t=>{t.exports=function(t){var r,e=t.workerPath,n=t.workerBlobURL;if(Blob&&URL&&n){var o=new Blob(['importScripts("'.concat(e,'");')],{type:"application/javascript"});r=new Worker(URL.createObjectURL(o));}else r=new Worker(e);return r};},399:t=>{t.exports=function(t){t.terminate();};},330:t=>{t.exports={rE:"6.0.0"};}},r={};function e(n){var o=r[n];if(void 0!==o)return o.exports;var i=r[n]={id:n,loaded:!1,exports:{}};return t[n].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}return e.nmd=t=>(t.paths=[],t.children||(t.children=[]),t),e(954)})())); - + } (tesseract_min$1)); var tesseract_minExports = tesseract_min$1.exports; diff --git a/src/scripts.json b/src/scripts.json index 4517408..fb6a0ee 100644 --- a/src/scripts.json +++ b/src/scripts.json @@ -1,13 +1,13 @@ { "injected": { - "stop-blocking.ts": "*", - "functionality/mutation-application.ts": "MuteApplication.action", - "functionality/view-khatian/index.ts": "KnowYourProperty.action", - "captcha/know-your-property.ts": "KnowYourProperty.action", - "captcha/application-receipt.ts": "Apprecrep.action", - "functionality/sheet-map/index.ts": "SheetMapViewAction.action" + "common/stop-blocking.ts": "*", + "pages/know-your-property/index.ts": "KnowYourProperty.action", + "pages/application-receipt/index.ts": "Apprecrep.action", + "pages/mutation-application/index.ts": "MuteApplication.action", + "pages/view-khatian/index.ts": "KnowYourProperty.action", + "pages/sheet-map/index.ts": "SheetMapViewAction.action" }, "after": { - "login/index.ts": "*" + "common/login/index.ts": "*" } } diff --git a/src/scripts/captcha/application-receipt.ts b/src/scripts/captcha/application-receipt.ts deleted file mode 100644 index 595195e..0000000 --- a/src/scripts/captcha/application-receipt.ts +++ /dev/null @@ -1,4 +0,0 @@ -document.addEventListener("DOMContentLoaded", () => { - $("#werter > div > form > div:nth-child(4)").hide(); - (window as any).validateForm = () => true; -}); diff --git a/src/scripts/captcha/know-your-property.ts b/src/scripts/captcha/know-your-property.ts deleted file mode 100644 index 6e11a3f..0000000 --- a/src/scripts/captcha/know-your-property.ts +++ /dev/null @@ -1,4 +0,0 @@ -document.addEventListener("DOMContentLoaded", () => { - $("#khatianPlotDiv > div:nth-child(6) > div").hide(); - (window as any).validateCaptcha = () => true; -}); diff --git a/src/scripts/common/login/captcha.ts b/src/scripts/common/login/captcha.ts new file mode 100644 index 0000000..a63aa24 --- /dev/null +++ b/src/scripts/common/login/captcha.ts @@ -0,0 +1,128 @@ +import { observeDOM } from "@/shared/observe-dom"; +import { OCRRequest, OCRResponse } from "@/shared/ocr-request"; + +/** + * Pre-processes a CAPTCHA image on a canvas by removing grayish + * background noise while preserving dark pixels, producing a clean + * binary image suitable for OCR. + * + * @param ctx - The 2D rendering context of the canvas. + * @param width - Canvas width in pixels. + * @param height - Canvas height in pixels. + */ +export function prepareCaptcha(ctx: CanvasRenderingContext2D, width: number, height: number): void { + const imgData = ctx.getImageData(0, 0, width, height); + const data = imgData.data; + const radius = 1; + + /** Returns true when all three channels are below 50 (very dark). */ + function isBlack(r: number, g: number, b: number): boolean { + return r < 50 && g < 50 && b < 50; + } + + /** Returns true when the colour is a mid-range grey (no strong hue). */ + function isGrayish(r: number, g: number, b: number): boolean { + return Math.abs(r - g) < 15 && Math.abs(g - b) < 15 && r > 100 && r < 200; + } + + /** + * Checks whether a black pixel exists within `radius` pixels of (x, y). + * Used to preserve dark structures when removing grey noise. + */ + function hasNearbyBlack(x: number, y: number): boolean { + for (let dx = -radius; dx <= radius; dx++) { + for (let dy = -radius; dy <= radius; dy++) { + const nx = x + dx; + const ny = y + dy; + if (nx >= 0 && nx < width && ny >= 0 && ny < height) { + const i = (ny * width + nx) * 4; + if (isBlack(data[i], data[i + 1], data[i + 2])) return true; + } + } + } + return false; + } + + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const i = (y * width + x) * 4; + const [r, g, b] = [data[i], data[i + 1], data[i + 2]]; + if (isGrayish(r, g, b) && !hasNearbyBlack(x, y)) { + data[i] = data[i + 1] = data[i + 2] = 255; + } + } + } + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const i = (y * width + x) * 4; + const [r, g, b] = [data[i], data[i + 1], data[i + 2]]; + + if (isGrayish(r, g, b)) { + data[i] = data[i + 1] = data[i + 2] = 0; // make black + } + } + } + ctx.putImageData(imgData, 0, 0); +} + +observeDOM(() => { + const loginFormElement = document.querySelector<HTMLFormElement>("#loginform"); + + if (loginFormElement) { + const captchaImg = loginFormElement.querySelector<HTMLImageElement>("#captchaImg"); + const captchaInput = loginFormElement.querySelector<HTMLInputElement>("#txtInput"); + + if (!captchaImg || !captchaInput) + return false; + + // Wait for image to load to get correct dimensions + captchaImg.addEventListener("load", function(): void { + const { width, height } = captchaImg; + + // 1. Create canvas + const canvas = document.createElement("canvas"); + canvas.width = width; + canvas.height = height; + canvas.style.display = "block"; + + // 2. Copy styles (optional) + canvas.style.cssText = getComputedStyle(captchaImg).cssText; + canvas.style.display = "none"; + + // 3. Insert canvas before image + captchaImg.parentNode?.querySelectorAll("canvas") + .forEach((c) => { c.remove(); }); + captchaImg.parentNode?.insertBefore(canvas, captchaImg); + + // 4. Hide image + captchaImg.style.display = "none"; + + // 5. Draw the image onto the canvas + const ctx = canvas.getContext("2d"); + if (!ctx) + return; + ctx.drawImage(captchaImg, 0, 0); + prepareCaptcha(ctx, canvas.width, canvas.height); + canvas.style.display = ""; + const dataURL = canvas.toDataURL("image/png"); + + // Perform OCR + chrome.runtime.sendMessage<OCRRequest, OCRResponse>( + { type: "OCR", dataURL }, + function(ocrResponse): void { + if (ocrResponse.success) { + const textResult = ocrResponse.text.trim(); + if (ocrResponse.confidence < 80 || textResult.length !== 6) + // Reset the captcha if confidence is low + captchaImg.src = `generateCaptcha?${new Date().getTime().toString()}`; + else + captchaInput.value = textResult; + } + } + ); + }); + } + + // This runs forever + return false; +}); diff --git a/src/scripts/common/login/index.ts b/src/scripts/common/login/index.ts new file mode 100644 index 0000000..95b9c5b --- /dev/null +++ b/src/scripts/common/login/index.ts @@ -0,0 +1 @@ +import "@/scripts/common/login/captcha"; diff --git a/src/scripts/common/stop-blocking.ts b/src/scripts/common/stop-blocking.ts new file mode 100644 index 0000000..8588834 --- /dev/null +++ b/src/scripts/common/stop-blocking.ts @@ -0,0 +1,52 @@ +/** + * Proxies jQuery's `.bind()` (for the `"cut copy paste"` event) and + * `.keydown()` so that the website's copy/paste/right-click blocking + * is disabled. Reverts the prototypes after patching to avoid + * interfering with other code. + */ + +type JQueryBindFn = ( + eventName: string, + handler: (event: JQuery.Event) => unknown +) => JQuery; + +type JQueryKeydownFn = ( + handler: (event: JQuery.Event) => unknown +) => JQuery; + +type JQueryPrototypeShape = { + bind: JQueryBindFn; + keydown: JQueryKeydownFn +}; + +const jQueryPrototype = $.prototype as unknown as JQueryPrototypeShape; + +document.addEventListener("DOMContentLoaded", () => { + const proxiedBind = jQueryPrototype.bind; + /** Proxies jQuery `.bind()` to no-op the `"cut copy paste"` event. */ + jQueryPrototype.bind = function( + this: JQuery, + ...args: Parameters<JQueryBindFn> + ): JQuery { + const [eventName, handler] = args; + const noop = (): undefined => undefined; + return proxiedBind.call( + this, + eventName, + eventName.trim() === "cut copy paste" ? noop : handler + ); + }; + + const proxiedKeydown = jQueryPrototype.keydown; + /** Proxies jQuery `.keydown()` so all key presses are allowed. */ + jQueryPrototype.keydown = function( + this: JQuery, + ..._args: Parameters<JQueryKeydownFn> + ): JQuery { + return proxiedKeydown.call(this, () => true); + }; + + jQueryPrototype.bind = proxiedBind; + jQueryPrototype.keydown = proxiedKeydown; + document.oncontextmenu = (): boolean => true; +}); diff --git a/src/scripts/functionality/mutation-application.ts b/src/scripts/functionality/mutation-application.ts deleted file mode 100644 index 96aec8a..0000000 --- a/src/scripts/functionality/mutation-application.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { PDFDocument, StandardFonts } from "pdf-lib"; -import { observeDOM } from "@/shared/observe-dom"; - -const sanghaFacilitationCentreBannerUrl = "$l{ /assets/sangha-facilitation-centre-banner.jpg }l$"; - -document.addEventListener("DOMContentLoaded", () => { - observeDOM(() => { - const formElement = $("#form_MutationApplication > div > div:nth-child(14) > div.col-sm-2.btreset > form"); - const submitButtonElement = $("#btnDeclareForm"); - if (formElement.length > 0 && submitButtonElement.length > 0) { - formElement.removeAttr("action"); - submitButtonElement.click(e => { - e.preventDefault(); - - (async () => { - const pdfDoc = await PDFDocument.load(await fetch("/BanglarBhumi/MutationDeclarationForm.action", { - method: "post", - credentials: "same-origin", - headers: { - "Content-Type": "application/x-www-form-urlencoded" - }, - body: "hdnAppNo=" - }).then(res => res.arrayBuffer())); - const pages = pdfDoc.getPages(); - const lastPage = pages[pages.length - 1]; - const { width, height } = lastPage.getSize(); - const bannerImage = await pdfDoc.embedJpg(await fetch(sanghaFacilitationCentreBannerUrl).then(res => res.arrayBuffer())); - const bannerImageHeight = width * (bannerImage.height / bannerImage.width); - - lastPage.drawImage(bannerImage, { - x: 0, - y: 0, - width: width, - height: bannerImageHeight - }); - - lastPage.drawText(pdfDoc.getCreationDate()!.toLocaleString(), { - x: 10, - y: bannerImageHeight, - size: 12, - font: await pdfDoc.embedFont(StandardFonts.TimesRoman) - }); - - const link = document.createElement("a"); - link.href = window.URL.createObjectURL(new Blob([new Uint8Array(await pdfDoc.save())], {type: "application/pdf"})); - link.download = "Declaration.pdf"; - link.click(); - })(); - }); - - return true; - } else { - return false; - } - }); -}); diff --git a/src/scripts/functionality/sheet-map/index.ts b/src/scripts/functionality/sheet-map/index.ts deleted file mode 100644 index 71228fe..0000000 --- a/src/scripts/functionality/sheet-map/index.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { generateWebPage } from "@/shared/generate-web-page"; -import getDownloadMapPDFPageContent from "@/scripts/functionality/sheet-map/download-map-pdf-page-content.html"; -import getMapPlotPolygonPathElement from "@/scripts/functionality/sheet-map/map-plot-polygon-path-element.html"; -import getMapPlotNumberLabelTextElement from "@/scripts/functionality/sheet-map/map-plot-number-label-text-element.html"; -import getPlotInformationElement from "@/scripts/functionality/sheet-map/plot-information-element.html"; - -interface PlotPolygon { - plotArea: number; - plotno: string; - polygon: string; -}; - -interface PlotNumberLabel { - plotno: string; - point: string; -} - -const headerElement = document.querySelector("#headerTable > tbody > tr")!; -const plotNumberInput = document.querySelector<HTMLInputElement>("#txtPlotNo")!; -const plotInformation = document.createElement("div") as HTMLDivElement; -let plotPolygonPathElements = ""; -let plotNumberLabelTextElements = ""; - -document.body.appendChild(plotInformation); - -const createHeaderButton = (text: string) => { - const buttonContainer = document.createElement("td"); - const button = document.createElement("button"); - button.innerHTML = text; - button.style.display = "none"; - buttonContainer.appendChild(button); - headerElement.appendChild(buttonContainer); - return button; -}; - -const setPlotInformation = (plotPolygon: PlotPolygon | null | undefined = null) => { - plotInformation.innerHTML = plotPolygon ? getPlotInformationElement({ - area: (plotPolygon.plotArea/1000).toFixed(3), - plotNumber: plotPolygon.plotno - }) : getPlotInformationElement({ - area: "0.000", - plotNumber: "" - }); -}; - -const downloadPDF = (labelPoints: boolean = true) => { - const _getMapDetail = (i: number) => { - const detail = document.querySelector(`#headerTable > tbody > tr > td:nth-child(${i})`)! - .innerHTML - .split("[")[1] - .trim(); - return detail.substr(0, detail.length - 1); - }; - generateWebPage( - getDownloadMapPDFPageContent({ - district: _getMapDetail(1), - block: _getMapDetail(2), - mouza: _getMapDetail(3), - mapContent: plotPolygonPathElements + (labelPoints ? plotNumberLabelTextElements : "") - }), - "map" - ); -}; - -const downloadPDFButton = createHeaderButton("SAVE PDF"); -const downloadPDFNoLabelButton = createHeaderButton("SAVE PDF (NO LABEL)"); - -downloadPDFButton.addEventListener("click", e => { - e.preventDefault(); - downloadPDF(); -}); - -downloadPDFNoLabelButton.addEventListener("click", e => { - e.preventDefault(); - downloadPDF(false); -}); - -setPlotInformation(); - -(async () => { - const searchParams = new URLSearchParams(window.location.search); - const response1 = await fetch( - "/BanglarBhumi/sheetMap_populateLayerData?lstSheetNo=" + searchParams.get("lstSheetNo"), - { - method: "POST" - }); - const plotPolygonList: PlotPolygon[] = (await response1.json()).features; - const response2 = await fetch( - "/BanglarBhumi/sheetMap_populateCentroidData?lstSheetNo=" + searchParams.get("lstSheetNo"), - { - method: "POST" - }); - const plotNumberLabelList: PlotNumberLabel[] = (await response2.json()).features; - let plotPolygons: { [key: string]: PlotPolygon } = {}; - - for (const plotPolygon of plotPolygonList) { - const plotPolygonPoints = plotPolygon.polygon.split("(((")[1].split(")))")[0]; - plotPolygonPathElements += getMapPlotPolygonPathElement({ - polygonVertices: plotPolygonPoints - }); - } - - for (const plotNumberLabel of plotNumberLabelList) { - const plotNumberLabelPoint = plotNumberLabel.point.split("(")[1].split(")")[0].split(" "); - plotNumberLabelTextElements += getMapPlotNumberLabelTextElement({ - x: plotNumberLabelPoint[0], - y: plotNumberLabelPoint[1], - plotNumber: plotNumberLabel.plotno - }); - } - - downloadPDFButton.style.display = "inherit"; - downloadPDFNoLabelButton.style.display = "inherit"; - - document.querySelector("#btnSearch")!.addEventListener("click", () => { - let plotPolygon; - for (const p of plotPolygonList) { - if (p.plotno === plotNumberInput.value) { - plotPolygon = p; - break; - } - } - setPlotInformation(plotPolygon); - }); - - await new Promise<void>((resolve, reject) => { - const plotElementIdsControl = setInterval(() => { - let i = 0; - let plotElements = document.querySelector("#OpenLayers_Layer_Vector_25_vroot")?.children || []; - if (plotElements.length) { - clearInterval(plotElementIdsControl); - for (let i = 0; i < plotElements.length; i++) { - plotPolygons[plotElements[i].id] = plotPolygonList[i]; - } - resolve(); - } - }, 50); - }); - - setInterval(() => { - for (const plotElementId in plotPolygons) { - const e = document.getElementById(plotElementId); - if (e) { - e.removeEventListener("click", handlePlotClick); - e.addEventListener("click", handlePlotClick); - } - } - }, 300); - - const handlePlotClick = (e: MouseEvent) => { - document.querySelectorAll("path").forEach(e => { - e.setAttribute("fill", "#ffcc66"); - }); - - const target = e.target as SVGPathElement; - - target.setAttribute("fill", "#8aeeef"); - setPlotInformation(plotPolygons[target.id]); - }; -})(); diff --git a/src/scripts/login/index.ts b/src/scripts/login/index.ts deleted file mode 100644 index bed05f9..0000000 --- a/src/scripts/login/index.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { interceptPost, interceptGet } from "@/shared/intercept-jquery-ajax"; - -function prepareCaptcha(ctx: CanvasRenderingContext2D, width: number, height: number) { - const imgData = ctx.getImageData(0, 0, width, height); - const data = imgData.data; - const radius = 1; - - function isBlack(r: number, g: number, b: number) { - return r < 50 && g < 50 && b < 50; - } - - function isGrayish(r: number, g: number, b: number) { - return Math.abs(r - g) < 15 && Math.abs(g - b) < 15 && r > 100 && r < 200; - } - - function hasNearbyBlack(x: number, y: number) { - for (let dx = -radius; dx <= radius; dx++) { - for (let dy = -radius; dy <= radius; dy++) { - const nx = x + dx; - const ny = y + dy; - if (nx >= 0 && nx < width && ny >= 0 && ny < height) { - const i = (ny * width + nx) * 4; - if (isBlack(data[i], data[i + 1], data[i + 2])) return true; - } - } - } - return false; - } - - for (let y = 0; y < height; y++) { - for (let x = 0; x < width; x++) { - const i = (y * width + x) * 4; - const [r, g, b] = [data[i], data[i + 1], data[i + 2]]; - if (isGrayish(r, g, b) && !hasNearbyBlack(x, y)) { - data[i] = data[i + 1] = data[i + 2] = 255; - } - } - } - for (let y = 0; y < height; y++) { - for (let x = 0; x < width; x++) { - const i = (y * width + x) * 4; - const [r, g, b] = [data[i], data[i + 1], data[i + 2]]; - - if (isGrayish(r, g, b)) { - data[i] = data[i + 1] = data[i + 2] = 0; // make black - } - } - } - ctx.putImageData(imgData, 0, 0); -} - -const observer = new MutationObserver((mutationsList, obs) => { - for (const mutation of mutationsList) { - for (const node of mutation.addedNodes) { - if ((node as any).nodeType === 1 && (node as any).id === "loginform") { - const img = (node as HTMLFormElement).querySelector("#captchaImg") as HTMLImageElement; - const captchaInput = (node as HTMLFormElement).querySelector("#txtInput") as HTMLInputElement; - - // Wait for image to load to get correct dimensions - img.addEventListener("load", async () => { - const { width, height } = img; - - // 1. Create canvas - const canvas = document.createElement("canvas"); - canvas.width = width; - canvas.height = height; - canvas.style.display = "block"; - - // 2. Copy styles (optional) - canvas.style.cssText = getComputedStyle(img).cssText; - canvas.style.display = "none"; - - // 3. Insert canvas before image - img.parentNode!.querySelectorAll("canvas").forEach(c => c.remove()); - img.parentNode!.insertBefore(canvas, img); - - // 4. Hide image - img.style.display = "none"; - - // 5. Draw the image onto the canvas - const ctx = canvas.getContext("2d")!; - ctx.drawImage(img, 0, 0); - prepareCaptcha(ctx, canvas.width, canvas.height); - canvas.style.display = ""; - const dataURL = canvas.toDataURL("image/png"); - - // Perform OCR - chrome.runtime.sendMessage( - { type: "OCR", dataURL }, - ({ success, text, confidence }) => { - if (success) { - const textResult = text.trim(); - if (confidence < 80 || textResult.length !== 6) { - // Reset the captcha if confidence is low - img.src = "generateCaptcha?" + new Date().getTime(); - } else { - captchaInput.value = textResult; - } - } - }, - ); - }); - } - } - } -}); - -// Start observing the body -observer.observe(document.body, { childList: true, subtree: true }); diff --git a/src/scripts/pages/application-receipt/captcha.ts b/src/scripts/pages/application-receipt/captcha.ts new file mode 100644 index 0000000..94e6b0e --- /dev/null +++ b/src/scripts/pages/application-receipt/captcha.ts @@ -0,0 +1,13 @@ +/** + * Hides the CAPTCHA section on the application-receipt page and + * stubs the form validation so the user can proceed without + * solving a CAPTCHA. + */ +type WindowApplicationReceipt = { + validateForm?: () => boolean +} & Window; + +document.addEventListener("DOMContentLoaded", () => { + $("#werter > div > form > div:nth-child(4)").hide(); + (window as WindowApplicationReceipt).validateForm = () => true; +}); diff --git a/src/scripts/pages/application-receipt/index.ts b/src/scripts/pages/application-receipt/index.ts new file mode 100644 index 0000000..5a8d0a6 --- /dev/null +++ b/src/scripts/pages/application-receipt/index.ts @@ -0,0 +1 @@ +import "@/scripts/pages/application-receipt/captcha"; diff --git a/src/scripts/pages/know-your-property/captcha.ts b/src/scripts/pages/know-your-property/captcha.ts new file mode 100644 index 0000000..e304342 --- /dev/null +++ b/src/scripts/pages/know-your-property/captcha.ts @@ -0,0 +1,13 @@ +/** + * Hides the CAPTCHA section on the Know-Your-Property page and + * stubs the captcha validation so the user can proceed without + * solving a CAPTCHA. + */ +type WindowKnowYourProperty = { + validateCaptcha?: () => boolean +} & Window; + +document.addEventListener("DOMContentLoaded", () => { + $("#khatianPlotDiv > div:nth-child(6) > div").hide(); + (window as WindowKnowYourProperty).validateCaptcha = () => true; +}); diff --git a/src/scripts/pages/know-your-property/index.ts b/src/scripts/pages/know-your-property/index.ts new file mode 100644 index 0000000..d4d7f63 --- /dev/null +++ b/src/scripts/pages/know-your-property/index.ts @@ -0,0 +1 @@ +import "@/scripts/pages/know-your-property/captcha"; diff --git a/src/scripts/pages/mutation-application/download-button.ts b/src/scripts/pages/mutation-application/download-button.ts new file mode 100644 index 0000000..6463079 --- /dev/null +++ b/src/scripts/pages/mutation-application/download-button.ts @@ -0,0 +1,63 @@ +import { PDFDocument, StandardFonts } from "pdf-lib"; + +import { observeDOM } from "@/shared/observe-dom"; + +const sanghaFacilitationCentreBannerUrl = "$l{ /assets/sangha-facilitation-centre-banner.jpg }l$"; + +/** + * On the Mutation Application form, removes the form action (to prevent + * the default server-side submit) and attaches a custom click handler + * that fetches the declaration PDF, overlays a banner image and date + * stamp on the last page, then triggers a download. + */ +observeDOM(() => { + const formElement = $("#form_MutationApplication > div > div:nth-child(14) > div.col-sm-2.btreset > form"); + const submitButtonElement = $("#btnDeclareForm"); + if (formElement.length > 0 && submitButtonElement.length > 0) { + formElement.removeAttr("action"); + submitButtonElement.on("click", (submitButtonClickEvent) => { + submitButtonClickEvent.preventDefault(); + + void (async function(): Promise<void> { + const pdfDoc = await PDFDocument.load(await fetch("/BanglarBhumi/MutationDeclarationForm.action", { + method: "post", + credentials: "same-origin", + headers: { + "Content-Type": "application/x-www-form-urlencoded" + }, + body: "hdnAppNo=" + }).then((res) => res.arrayBuffer())); + const pages = pdfDoc.getPages(); + const lastPage = pages[pages.length - 1]; + const { width } = lastPage.getSize(); + const bannerImage + = await pdfDoc.embedJpg(await fetch(sanghaFacilitationCentreBannerUrl) + .then((res) => res.arrayBuffer())); + const bannerImageHeight = width * (bannerImage.height / bannerImage.width); + + lastPage.drawImage(bannerImage, { + x: 0, + y: 0, + width: width, + height: bannerImageHeight + }); + + lastPage.drawText(pdfDoc.getCreationDate()?.toLocaleString() ?? "", { + x: 10, + y: bannerImageHeight, + size: 12, + font: await pdfDoc.embedFont(StandardFonts.TimesRoman) + }); + + const link = document.createElement("a"); + link.href = window.URL.createObjectURL(new Blob([new Uint8Array(await pdfDoc.save())], { type: "application/pdf" })); + link.download = "Declaration.pdf"; + link.click(); + })(); + }); + + return true; + } else { + return false; + } +}); diff --git a/src/scripts/pages/mutation-application/index.ts b/src/scripts/pages/mutation-application/index.ts new file mode 100644 index 0000000..93e07ad --- /dev/null +++ b/src/scripts/pages/mutation-application/index.ts @@ -0,0 +1 @@ +import "@/scripts/pages/mutation-application/download-button"; diff --git a/src/scripts/functionality/sheet-map/download-map-pdf-page-content.html b/src/scripts/pages/sheet-map/download-map-pdf-page-content.html index da765ec..da765ec 100644 --- a/src/scripts/functionality/sheet-map/download-map-pdf-page-content.html +++ b/src/scripts/pages/sheet-map/download-map-pdf-page-content.html diff --git a/src/scripts/pages/sheet-map/index.ts b/src/scripts/pages/sheet-map/index.ts new file mode 100644 index 0000000..c16a2ae --- /dev/null +++ b/src/scripts/pages/sheet-map/index.ts @@ -0,0 +1,197 @@ +import getDownloadMapPDFPageContent from "@/scripts/pages/sheet-map/download-map-pdf-page-content.html"; +import getMapPlotNumberLabelTextElement from "@/scripts/pages/sheet-map/map-plot-number-label-text-element.html"; +import getMapPlotPolygonPathElement from "@/scripts/pages/sheet-map/map-plot-polygon-path-element.html"; +import getPlotInformationElement from "@/scripts/pages/sheet-map/plot-information-element.html"; +import { generateWebPage } from "@/shared/generate-web-page"; + +type PlotPolygon = { + plotArea: number; + plotno: string; + polygon: string +}; + +type PlotNumberLabel = { + plotno: string; + point: string +}; + +const headerElement = document.querySelector<HTMLTableRowElement>("#headerTable > tbody > tr"); +const plotNumberInput = document.querySelector<HTMLInputElement>("#txtPlotNo"); +const plotInformation = document.createElement("div"); +let plotPolygonPathElements = ""; +let plotNumberLabelTextElements = ""; + +document.body.appendChild(plotInformation); + +/** + * Creates a header toolbar button and appends it to the page header. + * The button starts hidden and is shown when data is ready. + * + * @param text - The button label text. + * @returns The created button element. + */ +function createHeaderButton(text: string): HTMLButtonElement { + const buttonContainer = document.createElement("td"); + const button = document.createElement("button"); + button.innerHTML = text; + button.style.display = "none"; + buttonContainer.appendChild(button); + if (headerElement) + headerElement.appendChild(buttonContainer); + return button; +}; + +/** + * Displays the area and plot number for the given polygon in a floating + * info panel, or shows "0.000" / empty if no polygon is selected. + * + * @param plotPolygon - The selected plot's data, or `null`/`undefined` to clear. + */ +function setPlotInformation(plotPolygon: PlotPolygon | null | undefined = null): void { + plotInformation.innerHTML = plotPolygon + ? getPlotInformationElement({ + area: (plotPolygon.plotArea / 1000).toFixed(3), + plotNumber: plotPolygon.plotno + }) + : getPlotInformationElement({ + area: "0.000", + plotNumber: "" + }); +}; + +/** + * Opens a new window with a printable PDF view of the map, optionally + * including plot-number labels. + * + * @param labelPoints - Whether to include plot number text labels. + */ +function downloadPDF(labelPoints = true): void { + /** Extracts a detail value (district/block/mouza) from the header table by column index. */ + function _getMapDetail(i: number): string { + const detail = (document.querySelector<HTMLTableCellElement>(`#headerTable > tbody > tr > td:nth-child(${i.toString()})`)?.innerHTML ?? "") + .split("[")[1] + .trim(); + return detail.substring(0, detail.length - 1); + }; + generateWebPage( + getDownloadMapPDFPageContent({ + district: _getMapDetail(1), + block: _getMapDetail(2), + mouza: _getMapDetail(3), + mapContent: plotPolygonPathElements + (labelPoints ? plotNumberLabelTextElements : "") + }), + "map" + ); +}; + +const downloadPDFButton = createHeaderButton("SAVE PDF"); +const downloadPDFNoLabelButton = createHeaderButton("SAVE PDF (NO LABEL)"); + +downloadPDFButton.addEventListener("click", (e) => { + e.preventDefault(); + downloadPDF(); +}); + +downloadPDFNoLabelButton.addEventListener("click", (e) => { + e.preventDefault(); + downloadPDF(false); +}); + +setPlotInformation(); + +void (async function(): Promise<void> { + const searchParams = new URLSearchParams(window.location.search); + const sheetMapLayerDataResponse = await fetch( + `/BanglarBhumi/sheetMap_populateLayerData?lstSheetNo=${searchParams.get("lstSheetNo")?.toString() ?? ""}`, + { + method: "POST" + }); + type SheetMapLayerDataResponseType = { + features: PlotPolygon[] + }; + const sheetMapLayerDataResponseJson + = await sheetMapLayerDataResponse.json() as SheetMapLayerDataResponseType; + const plotPolygonList: PlotPolygon[] = sheetMapLayerDataResponseJson.features; + const sheetMapCentroidDataResponse = await fetch( + `/BanglarBhumi/sheetMap_populateCentroidData?lstSheetNo=${searchParams.get("lstSheetNo")?.toString() ?? ""}`, + { + method: "POST" + }); + type SheetMapCentroidDataResponseType = { + features: PlotNumberLabel[] + }; + const sheetMapCentroidDataResponseJson + = await sheetMapCentroidDataResponse.json() as SheetMapCentroidDataResponseType; + const plotNumberLabelList: PlotNumberLabel[] = sheetMapCentroidDataResponseJson.features; + const plotPolygons: Record<string, PlotPolygon> = {}; + + for (const plotPolygon of plotPolygonList) { + const plotPolygonPoints = plotPolygon.polygon.split("(((")[1].split(")))")[0]; + plotPolygonPathElements += getMapPlotPolygonPathElement({ + polygonVertices: plotPolygonPoints + }); + } + + for (const plotNumberLabel of plotNumberLabelList) { + const plotNumberLabelPoint = plotNumberLabel.point.split("(")[1].split(")")[0].split(" "); + plotNumberLabelTextElements += getMapPlotNumberLabelTextElement({ + x: plotNumberLabelPoint[0], + y: plotNumberLabelPoint[1], + plotNumber: plotNumberLabel.plotno + }); + } + + downloadPDFButton.style.display = "inherit"; + downloadPDFNoLabelButton.style.display = "inherit"; + + document.querySelector<HTMLButtonElement>("#btnSearch")?.addEventListener("click", () => { + let plotPolygon; + for (const p of plotPolygonList) { + if (p.plotno === plotNumberInput?.value) { + plotPolygon = p; + break; + } + } + setPlotInformation(plotPolygon); + }); + + await new Promise<void>((resolve, _reject) => { + const plotElementIdsControl = setInterval(() => { + const plotElements = document.querySelector("#OpenLayers_Layer_Vector_25_vroot")?.children ?? []; + if (plotElements.length) { + clearInterval(plotElementIdsControl); + for (let i = 0; i < plotElements.length; i++) { + plotPolygons[plotElements[i].id] = plotPolygonList[i]; + } + resolve(); + } + }, 50); + }); + + setInterval(() => { + for (const plotElementId in plotPolygons) { + const e = document.getElementById(plotElementId); + if (e) { + e.removeEventListener("click", handlePlotClick); + e.addEventListener("click", handlePlotClick); + } + } + }, 300); + + /** + * Highlights the clicked plot on the SVG map and shows its + * information in the info panel. + * + * @param e - The mouse click event. + */ + function handlePlotClick(e: MouseEvent): void { + document.querySelectorAll("path").forEach((e) => { + e.setAttribute("fill", "#ffcc66"); + }); + + const target = e.target as SVGPathElement; + + target.setAttribute("fill", "#8aeeef"); + setPlotInformation(plotPolygons[target.id]); + }; +})(); diff --git a/src/scripts/functionality/sheet-map/map-plot-number-label-text-element.html b/src/scripts/pages/sheet-map/map-plot-number-label-text-element.html index d220367..d220367 100644 --- a/src/scripts/functionality/sheet-map/map-plot-number-label-text-element.html +++ b/src/scripts/pages/sheet-map/map-plot-number-label-text-element.html diff --git a/src/scripts/functionality/sheet-map/map-plot-polygon-path-element.html b/src/scripts/pages/sheet-map/map-plot-polygon-path-element.html index d4d38a6..d4d38a6 100644 --- a/src/scripts/functionality/sheet-map/map-plot-polygon-path-element.html +++ b/src/scripts/pages/sheet-map/map-plot-polygon-path-element.html diff --git a/src/scripts/functionality/sheet-map/plot-information-element.html b/src/scripts/pages/sheet-map/plot-information-element.html index fd740a8..fd740a8 100644 --- a/src/scripts/functionality/sheet-map/plot-information-element.html +++ b/src/scripts/pages/sheet-map/plot-information-element.html diff --git a/src/scripts/functionality/view-khatian/download-information-pdf-page-content.html b/src/scripts/pages/view-khatian/download-information-pdf-page-content.html index 129608e..129608e 100644 --- a/src/scripts/functionality/view-khatian/download-information-pdf-page-content.html +++ b/src/scripts/pages/view-khatian/download-information-pdf-page-content.html diff --git a/src/scripts/functionality/view-khatian/index.ts b/src/scripts/pages/view-khatian/index.ts index 93d03cf..bb44a38 100644 --- a/src/scripts/functionality/view-khatian/index.ts +++ b/src/scripts/pages/view-khatian/index.ts @@ -1,6 +1,6 @@ +import getDownloadInformationPDFPageContent from "@/scripts/pages/view-khatian/download-information-pdf-page-content.html"; import { generateWebPage } from "@/shared/generate-web-page"; -import { interceptPost } from "@/shared/intercept-jquery-ajax"; -import getDownloadInformationPDFPageContent from "@/scripts/functionality/view-khatian/download-information-pdf-page-content.html"; +import { addPostInterceptor, JQueryAjaxArgs } from "@/shared/intercept-jquery-ajax"; const submitButtonElement = $("#khbutton"); const separatorElement = $("#bodycover > div > form > hr:nth-child(2)"); @@ -14,18 +14,28 @@ const styles = Array.from(submitButtonElementComputedStyles) "" ); -const getValueOfSelectElement = (selector: string) => { - const element = document.querySelector<HTMLSelectElement>(selector)!; - return element.options[element.selectedIndex].text; +/** + * Reads the currently selected text from a `<select>` element. + * + * @param selector - CSS selector for the select element. + * @returns The text of the selected option. + */ +function getValueOfSelectElement(selector: string): string { + const element = document.querySelector<HTMLSelectElement>(selector); + return element?.options[element.selectedIndex].text ?? ""; }; let isPlotInformation: boolean | null = null; -const downloadInformationPDF = () => { +/** + * Opens a new window with a printable PDF view of the current khatian + * or plot details, including district/block/mouza info. + */ +function downloadInformationPDF(): void { generateWebPage( getDownloadInformationPDFPageContent({ isPlotInformation: !!isPlotInformation, - details: $(isPlotInformation ? "#plotdetails" : "#khdetails").html(), + details: $(isPlotInformation ? "#plotdetails" : "#khdetails").html() || "", district: getValueOfSelectElement("#lstDistrictCode1"), block: getValueOfSelectElement("#lstBlockCode1"), mouza: getValueOfSelectElement("#lstMouzaList") @@ -36,11 +46,18 @@ const downloadInformationPDF = () => { ); }; -const showDownloadButton = (args: any) => { +/** + * Intercepts the success callback of a jQuery AJAX call. When a valid + * details table is returned, it inserts a "Download PDF" button; + * otherwise it removes an existing button. + * + * @param args - The `arguments` object from the intercepted `$.post` call. + */ +function showDownloadButton(args: JQueryAjaxArgs): void { if (isPlotInformation !== null) { const callback = args[2]; - args[2] = (data: any) => { - callback(data); + args[2] = (...data) => { + callback(...data); const tableElement = $(isPlotInformation ? "#plotdetails > div:nth-child(1) > div:nth-child(4) > table > tbody" : "#khdetails > table > tbody > tr > td:nth-child(1) > div:nth-child(5) > table > tbody" @@ -56,23 +73,23 @@ const showDownloadButton = (args: any) => { downloadPDFButton[0].style.cssText = styles; downloadPDFButton.css("width", "auto"); downloadPDFButton.css("margin-bottom", "1rem"); - downloadPDFButton.click(downloadInformationPDF); + downloadPDFButton.on("click", downloadInformationPDF); formElement[0].insertBefore(downloadPDFButton[0], separatorElement[0]); } } else if (downloadPDFButton) { - ($(downloadPDFButton as any) as any).remove(); + ($(downloadPDFButton)).remove(); isPlotInformation = null; downloadPDFButton = null; } - } + }; } }; -interceptPost("plotDetailsAction_LandInfo.action", args => { +addPostInterceptor("plotDetailsAction_LandInfo.action", (args: JQueryAjaxArgs) => { isPlotInformation = true; showDownloadButton(args); }); -interceptPost("khDetailsAction_LandInfo.action", args => { +addPostInterceptor("khDetailsAction_LandInfo.action", (args: JQueryAjaxArgs) => { isPlotInformation = false; showDownloadButton(args); }); diff --git a/src/scripts/stop-blocking.ts b/src/scripts/stop-blocking.ts deleted file mode 100644 index b8f4783..0000000 --- a/src/scripts/stop-blocking.ts +++ /dev/null @@ -1,21 +0,0 @@ -document.addEventListener("DOMContentLoaded", () => { - const proxiedBind = $.prototype.bind; - $.prototype.bind = function() { - if (arguments[0].trim() === "cut copy paste") { - arguments[1] = (_: any) => {}; - } - - return proxiedBind.apply(this, Array.from(arguments) as any); - } - - const proxiedKeydown = $.prototype.keydown; - $.prototype.keydown = function() { - arguments[0] = (_: any) => true; - - return proxiedKeydown.apply(this, Array.from(arguments) as any); - } - - $.prototype.bind = proxiedBind; - $.prototype.keydown = proxiedKeydown; - document.oncontextmenu = () => true; -}); diff --git a/src/shared/generate-web-page.ts b/src/shared/generate-web-page.ts index a07575f..a93e2e2 100644 --- a/src/shared/generate-web-page.ts +++ b/src/shared/generate-web-page.ts @@ -1,11 +1,20 @@ -export function generateWebPage(content: string, title: string = "Banglar Bhumi") { +/** + * Opens a new browser tab and writes the given HTML content into it. + * Used to display dynamically-generated pages (e.g. PDF-printable views). + * + * @param content - The full HTML string to write. + * @param title - The document title (default: `"Banglar Bhumi"`). + */ +export function generateWebPage(content: string, title = "Banglar Bhumi"): void { const tab = window.open("about:blank", "_blank"); if (!tab) { return; } - tab.document.write(content); - tab.document.close(); - tab.document.title = title; + tab.addEventListener("DOMContentLoaded", () => { + tab.document.body.innerHTML = content; + tab.document.title = title; + tab.document.close(); + }); tab.focus(); }; diff --git a/src/shared/intercept-jquery-ajax.ts b/src/shared/intercept-jquery-ajax.ts index a77dd44..b627d0e 100644 --- a/src/shared/intercept-jquery-ajax.ts +++ b/src/shared/intercept-jquery-ajax.ts @@ -1,41 +1,86 @@ -type InterceptJqueryAjaxCallback = (args: any) => void; +export type JQueryAjaxArgs = [ + url: string, + data: string | Record<string, unknown>, + callback: (data: unknown, textStatus: string, jqXHR: JQuery.jqXHR) => void, + dataType?: string +]; -interface InterceptJqueryEntry { - url: string; - callback: InterceptJqueryAjaxCallback; +type JQueryAjaxInterceptor = (args: JQueryAjaxArgs) => void; + +type InterceptorRegistration = { + urlSuffix: string; + interceptor: JQueryAjaxInterceptor }; -const postIntercepts: InterceptJqueryEntry[] = []; -const getIntercepts: InterceptJqueryEntry[] = []; +const postInterceptors: InterceptorRegistration[] = []; +const getInterceptors: InterceptorRegistration[] = []; + +// Define a strict signature to replace the unsafe `Function` type +type OriginalJQueryAjaxMethod = (...args: unknown[]) => JQuery.jqXHR; -document.addEventListener("DOMContentLoaded", () => { - const proxiedPost = $.post; - const proxiedGet = $.get; +/** + * On DOMContentLoaded, proxies jQuery's `$.post` and `$.get` so that + * registered interceptors are called before the real request. + */ +document.addEventListener("DOMContentLoaded", function() { + // 1. Keep the original methods bound to the jQuery ($) object + const originalPost = $.post.bind($); + const originalGet = $.get.bind($); - $.post = function() { - for (const { url, callback } of postIntercepts) { - if (arguments[0].endsWith(url)) { - callback(arguments); + /** Proxied `$.post` that invokes registered interceptors before the real call. */ + $.post = function(this: typeof $, ...args: unknown[]): JQuery.jqXHR { + for (const { urlSuffix, interceptor } of postInterceptors) { + // Safely inspect jQuery settings objects without using "any" + const firstArg = args[0]; + const requestUrl = typeof firstArg === "string" + ? firstArg + : (firstArg && typeof firstArg === "object" && "url" in firstArg && typeof firstArg.url === "string" ? firstArg.url : null); + + if (typeof requestUrl === "string" && requestUrl.endsWith(urlSuffix)) { + // Cast the unknown array to the expected tuple type + interceptor(args as unknown as JQueryAjaxArgs); } } - return proxiedPost.apply(this, Array.from(arguments) as any); - }; - $.get = function() { - for (const { url, callback } of getIntercepts) { - if (arguments[0].endsWith(url)) { - callback(arguments); + // Use our strict signature instead of `Function` to satisfy ESLint + return (originalPost as unknown as OriginalJQueryAjaxMethod)(...args); + } as typeof $.post; // Reassert the original type so external consumers see the normal signature + + /** Proxied `$.get` that invokes registered interceptors before the real call. */ + $.get = function(this: typeof $, ...args: unknown[]): JQuery.jqXHR { + for (const { urlSuffix, interceptor } of getInterceptors) { + const firstArg = args[0]; + const requestUrl = typeof firstArg === "string" + ? firstArg + : (firstArg && typeof firstArg === "object" && "url" in firstArg && typeof firstArg.url === "string" ? firstArg.url : null); + + if (typeof requestUrl === "string" && requestUrl.endsWith(urlSuffix)) { + interceptor(args as unknown as JQueryAjaxArgs); } } - return proxiedGet.apply(this, Array.from(arguments) as any); - }; + return (originalGet as unknown as OriginalJQueryAjaxMethod)(...args); + } as typeof $.get; }); -export function interceptPost(url: string, callback: InterceptJqueryAjaxCallback) { - postIntercepts.push({ url, callback }); -}; +/** + * Registers a callback that fires whenever a jQuery POST request matches + * the given URL suffix. + * + * @param urlSuffix - The URL suffix to match (checked via `endsWith`). + * @param interceptor - Receives the original `arguments` from `$.post`. + */ +export function addPostInterceptor(urlSuffix: string, interceptor: JQueryAjaxInterceptor): void { + postInterceptors.push({ urlSuffix, interceptor }); +} -export function interceptGet(url: string, callback: InterceptJqueryAjaxCallback) { - getIntercepts.push({ url, callback }); -}; +/** + * Registers a callback that fires whenever a jQuery GET request matches + * the given URL suffix. + * + * @param urlSuffix - The URL suffix to match (checked via `endsWith`). + * @param interceptor - Receives the original `arguments` from `$.get`. + */ +export function addGetInterceptor(urlSuffix: string, interceptor: JQueryAjaxInterceptor): void { + getInterceptors.push({ urlSuffix, interceptor }); +} diff --git a/src/shared/modify-dom.ts b/src/shared/modify-dom.ts index 22b8e8e..41e8730 100644 --- a/src/shared/modify-dom.ts +++ b/src/shared/modify-dom.ts @@ -2,7 +2,7 @@ import { observeDOM } from "@/shared/observe-dom"; type DOMReplacements = { innerHTML?: string; - [key: string]: string | undefined | null; + [key: string]: string | undefined | null }; type DOMModificaitonRule = readonly [string, DOMReplacements]; type DOMModificationRules = (DOMModificaitonRule | null)[]; @@ -10,25 +10,32 @@ type DOMModificationRules = (DOMModificaitonRule | null)[]; let domModificationRules: DOMModificationRules = []; let domModificationFinishedCount = 0; +/** + * Runs whenever the DOM mutates. Iterates over pending modification + * rules; when the selector matches, the element's innerHTML and + * attributes are updated and the rule is marked as complete. + */ observeDOM(() => { for (let i = 0; i < domModificationRules.length; i++) { - if (domModificationRules[i]) { - const element = document.querySelector(domModificationRules[i]![0]) as HTMLElement | null; + const rule = domModificationRules[i]; + if (rule?.[0]) { + const element = document.querySelector(rule[0]); if (element) { - const attributes = domModificationRules[i]![1]; + const attributes = rule[1]; if (attributes.innerHTML) { - element.innerHTML = attributes.innerHTML as string; + element.innerHTML = attributes.innerHTML; } delete attributes.innerHTML; - for (const attribute in attributes) { - if (attributes[attribute] === null) { - element.removeAttribute(attribute); + for (const attributeName in attributes) { + const attribute = attributes[attributeName]; + if (attribute) { + element.setAttribute(attributeName, attribute); } else { - element.setAttribute(attribute, attributes[attribute] as string); + element.removeAttribute(attributeName); } } @@ -45,6 +52,15 @@ observeDOM(() => { return false; }); -export function modifyDOM(modificationRules: DOMModificationRules) { +/** + * Registers one or more DOM modification rules. Each rule is a tuple of + * `[selector, attributeMap]`. When an element matching the selector is + * found, its `innerHTML` is replaced (if `attributeMap.innerHTML` is set) + * and all other entries in the map are applied as `setAttribute` calls + * (or `removeAttribute` when the value is `null`). + * + * @param modificationRules - Array of `[selector, attributes]` rules. + */ +export function modifyDOM(modificationRules: DOMModificationRules): void { domModificationRules = domModificationRules.concat(modificationRules); }; diff --git a/src/shared/observe-dom.ts b/src/shared/observe-dom.ts index e82ce1e..ee6a51f 100644 --- a/src/shared/observe-dom.ts +++ b/src/shared/observe-dom.ts @@ -1,17 +1,20 @@ type ObserveDOMCallback = () => boolean; -let callbacks: (ObserveDOMCallback | null)[] = []; -let callbacksCalledCount = 0; +const callbacks: ObserveDOMCallback[] = []; +/** + * Starts a MutationObserver on the document that invokes each + * registered callback. A callback should return `true` when it + * has completed its work; once all callbacks are done the observer + * disconnects. + */ const observer = new MutationObserver(() => { for (let i = 0; i < callbacks.length; i++) { const callback = callbacks[i]; - if (callback && callback()) { - callbacksCalledCount++; - callbacks[i] = null; - } + if (callback()) + callbacks.splice(i, 1); - if (callbacksCalledCount >= callbacks.length) { + if (callbacks.length <= 0) { observer.disconnect(); break; @@ -24,6 +27,14 @@ observer.observe(document, { subtree: true }); -export function observeDOM(callback: ObserveDOMCallback) { +/** + * Registers a callback to run on DOM mutations. + * The callback is invoked on each mutation tick and should return `true` + * when its work is finished. When all callbacks have completed the + * observer stops. + * + * @param callback - Function that returns `true` when done. + */ +export function observeDOM(callback: ObserveDOMCallback): void { callbacks.push(callback); }; diff --git a/src/shared/ocr-request.ts b/src/shared/ocr-request.ts new file mode 100644 index 0000000..3109771 --- /dev/null +++ b/src/shared/ocr-request.ts @@ -0,0 +1,13 @@ +export type OCRRequest = { + type: "OFFSCREEN_OCR_REQUEST" | "OCR"; + dataURL: string +}; + +export type OCRResponse = { + success: true; + text: string; + confidence: number +} | { + success: false; + error: string +}; diff --git a/src/shared/script-injector.ts b/src/shared/script-injector.ts index 697c8d6..3422bab 100644 --- a/src/shared/script-injector.ts +++ b/src/shared/script-injector.ts @@ -1,12 +1,19 @@ -type DataType = { - [key: string]: string -}; +type DataType = Record<string, string>; -export function injectScriptHead(src: string, data: DataType = {}) { - const s = document.createElement("script") as HTMLScriptElement; +/** + * Injects a `<script>` element into the document head (or `<html>`) with + * the given `src` pointing to an extension resource. Optional key/value + * data is attached as `data-*` attributes so the injected script can + * read them via `document.currentScript`. + * + * @param src - The extension-relative script path. + * @param data - Optional key/value pairs to set as `data-*` attributes. + */ +export function injectScriptHead(src: string, data: DataType = {}): void { + const s = document.createElement("script"); s.src = chrome.runtime.getURL(src); for (const i in data) { s.setAttribute(`data-${i}`, data[i]); } - (document.head || document.documentElement).append(s); + document.head.append(s); }; diff --git a/src/shared/styling.ts b/src/shared/styling.ts index 759fecb..57a39f6 100644 --- a/src/shared/styling.ts +++ b/src/shared/styling.ts @@ -1,9 +1,16 @@ -export function styles(selector: string, styles: Record<string, string>) { - const elements = Array.from(document.querySelectorAll(selector)) as HTMLElement[]; +/** + * Applies a set of inline CSS styles to every element matching the + * given CSS selector. + * + * @param selector - CSS selector string. + * @param styles - A map of CSS property names to values. + */ +export function styles(selector: string, styles: Record<string, string>): void { + const elements = Array.from(document.querySelectorAll(selector)); for (const element of elements) { for (const styleType in styles) { - element.style[styleType as any] = styles[styleType]; + (element as HTMLElement).style.setProperty(styleType, styles[styleType]); } } }; |
