From 6131fd8fc6cb1245ccfbc5d03d33ffd1498e83f4 Mon Sep 17 00:00:00 2001
From: alyssaf16 <alyssa_feinberg@brown.edu>
Date: Mon, 8 Jul 2024 15:12:16 -0400
Subject: Speech to phonemes progress

---
 src/client/views/nodes/AudioBox.tsx | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

(limited to 'src/client/views/nodes/AudioBox.tsx')

diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 9deed4de4..5d0ed7eab 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -10,7 +10,7 @@ import { DateField } from '../../../fields/DateField';
 import { Doc } from '../../../fields/Doc';
 import { DocData } from '../../../fields/DocSymbols';
 import { ComputedField } from '../../../fields/ScriptField';
-import { Cast, DateCast, NumCast } from '../../../fields/Types';
+import { Cast, DateCast, DocCast, NumCast } from '../../../fields/Types';
 import { AudioField, nullAudio } from '../../../fields/URLField';
 import { formatTime } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
@@ -29,6 +29,7 @@ import './AudioBox.scss';
 import { DocumentView } from './DocumentView';
 import { FieldView, FieldViewProps } from './FieldView';
 import { OpenWhere } from './OpenWhere';
+import axios from 'axios';
 
 /**
  * AudioBox
@@ -257,6 +258,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             const [{ result }] = await Networking.UploadFilesToServer({ file: e.data });
             if (!(result instanceof Error)) {
                 this.Document[this.fieldKey] = new AudioField(result.accessPaths.agnostic.client);
+                this.Document.url = result.accessPaths.agnostic.client;
+                await this.pushInfo();
             }
         };
         this._recordStart = new Date().getTime();
@@ -284,9 +287,23 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         }
     };
 
+    pushInfo = async () => {
+        const audio = {
+            file: this.path,
+        };
+        const response = await axios.post('http://localhost:105/recognize/', audio, {
+            headers: {
+                'Content-Type': 'application/json',
+            },
+        });
+        this.Document[DocData].phoneticTranscription = response.data['transcription'];
+        console.log('RESPONSE: ' + response.data['transcription']);
+    };
+
     // context menu
     specificContextMenu = (): void => {
         const funcs: ContextMenuProps[] = [];
+        // funcs.push({ description: 'Push info', event: this.pushInfo, icon: 'redo-alt' });
         funcs.push({
             description: (this.layoutDoc.hideAnchors ? "Don't hide" : 'Hide') + ' anchors',
             event: () => { this.layoutDoc.hideAnchors = !this.layoutDoc.hideAnchors; }, // prettier-ignore
-- 
cgit v1.2.3-70-g09d2


From ef2a1037a418ad9fa35d6c60feba914d828d5b84 Mon Sep 17 00:00:00 2001
From: alyssaf16 <alyssa_feinberg@brown.edu>
Date: Sun, 29 Sep 2024 15:54:49 -0400
Subject: clean up

---
 dash-speech-to-text-101b507c5e39.json              | 13 +++++
 .../views/collections/CollectionCarouselView.tsx   | 16 +------
 src/client/views/nodes/AudioBox.tsx                | 19 ++++++++
 src/client/views/nodes/ComparisonBox.tsx           | 55 +++++++++++++++-------
 src/client/views/nodes/ImageBox.tsx                | 49 ++++++-------------
 5 files changed, 86 insertions(+), 66 deletions(-)
 create mode 100644 dash-speech-to-text-101b507c5e39.json

(limited to 'src/client/views/nodes/AudioBox.tsx')

diff --git a/dash-speech-to-text-101b507c5e39.json b/dash-speech-to-text-101b507c5e39.json
new file mode 100644
index 000000000..62a7c7eb0
--- /dev/null
+++ b/dash-speech-to-text-101b507c5e39.json
@@ -0,0 +1,13 @@
+{
+  "type": "service_account",
+  "project_id": "dash-speech-to-text",
+  "private_key_id": "101b507c5e394ec62f075d9416890bef0f597f7f",
+  "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC1BQ4iu7RNbiVF\nuIk/7+Zby4mMy0fde/WaCc4VxEQELK8ys2UtLU92L0npSLOyLACtLcNexdihoPMs\nHcQV7jxj9KRlk7tx3CPuVj8mn52WNIxX5ds5BszQqrfNQGObfdeFsROFzcA2ysbz\nEyfkqoFSQU5OUYANwEaF9oXc5nEkZaz5Zjjy34g8USAlySbB2sKI4o372Xi0slJo\nuPYWn93k/IA7HAmCOeooc2LTi+gu2KCnkXKevXdJCcK9Lntbm9RjoSUQiR/6R0Ls\nCTXY/g3G2FMJiraqxeI4HeAU2Pyw0sl86nHYTHh3/wNRxQkpLXROAc5qlPbMbTzp\nEu7kLI7PAgMBAAECggEADQyQk00SrKOXCOqfl5NUo3i4XATqE6ZJndFny3E63KOC\npwCq93xqW6usWVEbWxRe9seeFik5pOp0Unwm1CnjV+qdJea7aXQkHEdCsCcWIMDS\n/nccZtpS+MEwahm31Hqthv6tLe/CE8ZpscDHbG16Jb19cUSLcEepuHh9TTTzd7Bu\n9iaQGNC4Kpfvnl4zxr5RlooQFBXI/izSnHqlKW6yz/j3ntpabDFp7U3ZDe7cRpJa\nsDXwOXSULrg7LRcV9sPyC4UwfEVNFdJJg7QxWcmJe4QYdDCNnZ7JnKvMcBgZmvyH\nbJZosZGMB3QW/BdPHugk5dmT2Zm7j/0axwNdIflFwQKBgQDddrnGLQMqZwQU+Ag6\nTFjXdSXaGDKRvK4W+PvsNla8kin1TU3NHd+GUGPnBbR+bOF5Y1m0IYEHOOtgVB6E\ni+RzytKPM6ghMDAkzLTrB1R9a1Aj0b2OWQrdPjDgDw2BHcGVmwHsy3i2v97e+1hn\nduEFHZOawg2LALlXqxXb+TyYrwKBgQDRP7k9wcnju1JOcfMFcUH1gcG6CmKoZwVK\nl7cGcKYaTAZZl4W8cZVuC+l/LPH4xXQYg9FqGQ3R6NQQFQV3g83ym2nQeALluuXJ\n7vlFtViu89uiiBtg9DL1wsbYnbUjOd4CYoW9GWv5Jy99SSHp4XIIcy6MNYwuRZaq\nObx5dViz4QKBgBWqBpRPVO7x8uFGPi/NxicVi6VhFplRFsqigqphymxZ9AbOEB1P\nnc0a0hsIYNa5OflQ8baATInzVHsw32dh8/Ar2BswF3NfrmX7LHuNVQOL2uQWIW/q\nX/iym79fWZfW3FgROMf8Q4vFCz1O4yAD7hE9CnJqJz8AzCC6WMITCI17AoGANMv3\nWXXEEwn4woJN51mkYuXSk7Z7HjKgSynsrFtQDeKQ15o7zEh8g7/NsqEMjNCFcooQ\nFM0th4FPwJ8NOhKvrD86e7dMQ9rckA8UJlqTfdFZ4bCl99il4wy6T327bp/zPHbP\nd98qNzuD6ADD5ddUhn1JiWcZb7NvSJQ40gyhzQECgYB7rMpNCq46NNozGktHRhuo\nGJjHiGgSM6vVPkC7DVJbU4jU2RjI7IUL2wfFEWDKOovkts7Ugp/KEFVcff4neeuz\nMomaVWaaT3xIKENUIAzSpqcqshkqDJ/2kAknD30IJXAvGuaK49rql5Vab/Rh6zVW\nWH5hqTQk5IXR02zFSIXwXg==\n-----END PRIVATE KEY-----\n",
+  "client_email": "af010101@dash-speech-to-text.iam.gserviceaccount.com",
+  "client_id": "110674669436677368261",
+  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+  "token_uri": "https://oauth2.googleapis.com/token",
+  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/af010101%40dash-speech-to-text.iam.gserviceaccount.com",
+  "universe_domain": "googleapis.com"
+}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 91a7c6514..04a0320fc 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -254,15 +254,6 @@ export class CollectionCarouselView extends CollectionSubView() {
     addFlashcard() {
         const newDoc = Docs.Create.ComparisonDocument('', { _layout_isFlashcard: true, _width: 300, _height: 300 });
         this.addDocument?.(newDoc);
-        // DocUtils.copyDragFactory(newDoc);
-        // this._props.addDocument?.();
-        // newDoc.layout = this.layoutDoc;
-        // newDoc.data = this.dataDoc;
-        // Doc.AddDocToList()
-        // this._props.parent._props.addDocument();
-        // this.childLayoutPairs.push({ newDoc.layout, newDoc.data});
-        // this._props.addDocument?.(newDoc);
-        // console.log('HERE');
     }
 
     @computed get buttons() {
@@ -275,11 +266,6 @@ export class CollectionCarouselView extends CollectionSubView() {
                             <FontAwesomeIcon icon="star" color={this.carouselItems[this.carouselIndex]?.[this.starField] ? 'yellow' : 'gray'} size="1x" />
                         </div>
                     </Tooltip>
-                    {/* <Tooltip title="add new flashcard to pile">
-                        <div key="add" className="carouselView-add" onClick={this.addFlashcard}>
-                            <FontAwesomeIcon icon="plus" color={this.carouselItems?.[NumCast(this.layoutDoc._carousel_index)].layout[this.starField] ? 'yellow' : 'gray'} size="1x" />
-                        </div>
-                    </Tooltip> */}
                 </div>
                 <div key="back" className="carouselView-back" onClick={this.goback}>
                     <FontAwesomeIcon icon="chevron-left" size="2x" />
@@ -287,7 +273,7 @@ export class CollectionCarouselView extends CollectionSubView() {
                 <div key="fwd" className="carouselView-fwd" onClick={this.advance}>
                     <FontAwesomeIcon icon="chevron-right" size="2x" />
                 </div>
-                {this.practiceMode ? (
+                {this.practiceMode == practiceMode.PRACTICE ? (
                     <div>
                         <Tooltip title="Incorrect. View again later.">
                             <div key="remove" className="carouselView-remove" onClick={e => this.setPracticeVal(e, practiceVal.MISSED)}>
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 63a126aec..8056ced1e 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -300,10 +300,29 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         console.log('RESPONSE: ' + response.data['transcription']);
     };
 
+    youtubeUpload = async () => {
+        console.log('Here');
+        const audio = {
+            file: 'Cd2ch4XV84s&t=373s',
+        };
+        const response = await axios.post('http://localhost:105/youtube/', audio, {
+            headers: {
+                'Content-Type': 'application/json',
+            },
+        });
+        console.log('RESPONSE: ' + response.data['transcription']);
+    };
+
     // context menu
     specificContextMenu = (): void => {
         const funcs: ContextMenuProps[] = [];
         // funcs.push({ description: 'Push info', event: this.pushInfo, icon: 'redo-alt' });
+
+        funcs.push({
+            description: 'Youtube',
+            event: this.youtubeUpload, // prettier-ignore
+            icon: 'expand-arrows-alt',
+        });
         funcs.push({
             description: (this.layoutDoc.hideAnchors ? "Don't hide" : 'Hide') + ' anchors',
             event: () => { this.layoutDoc.hideAnchors = !this.layoutDoc.hideAnchors; }, // prettier-ignore
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index a410f4994..df127f0d5 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -246,8 +246,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
     remDoc = (doc: Doc, which: string) => {
         if (this.dataDoc[which] === doc) {
             this._isEmpty = true;
-            // this.dataDoc[which] = 'empty';
-            console.log('HEREEEE');
             this.dataDoc[which] = undefined;
             return true;
         }
@@ -302,7 +300,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                     this._animating = 'all 200ms';
                     // on click, animate slider movement to the targetWidth
                     this.layoutDoc[this.clipWidthKey] = (targetWidth * 100) / this._props.PanelWidth();
-                    // this.layoutDoc[this.clipHeightKey] = (targetWidth * 100) / this._props.PanelHeight();
 
                     setTimeout(
                         action(() => {
@@ -384,6 +381,24 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         console.log('RESPONSE: ' + response.data['transcription']);
     };
 
+    getYouTubeVideoId = (url: string) => {
+        const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/;
+        const match = url.match(regExp);
+        return match && match[2].length === 11 ? match[2] : null;
+    };
+
+    youtubeUpload = async () => {
+        const audio = {
+            file: this.getYouTubeVideoId(StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text)),
+        };
+        const response = await axios.post('http://localhost:105/youtube/', audio, {
+            headers: {
+                'Content-Type': 'application/json',
+            },
+        });
+        return response.data['transcription'];
+    };
+
     createFlashcardPile(collectionArr: Doc[], gpt: boolean) {
         const newCol = Docs.Create.CarouselDocument(collectionArr, {
             _width: NumCast(this.layoutDoc['_' + this._props.fieldKey + '_width'], 250) + 50,
@@ -394,6 +409,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         newCol['x'] = this.layoutDoc['x'];
         newCol['y'] = NumCast(this.layoutDoc['y']) + 50;
         newCol.type_collection = 'carousel';
+        for (var i = 0; i < collectionArr.length; i++) {
+            DocCast(collectionArr[i])[DocData].embedContainer = newCol;
+        }
 
         if (gpt) {
             this._props.DocumentView?.()._props.addDocument?.(newCol);
@@ -405,6 +423,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         }
     }
 
+    /**
+     * Transfers the content of flashcards into a flashcard pile.
+     */
     gptFlashcardPile = async () => {
         var text = await this.askGPT(GPTCallType.STACK);
         var senArr = text?.split('Question: ');
@@ -441,17 +462,28 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                 DocCast(newDoc)[DocData][this.fieldKey + '_1'] = textDoc1;
                 DocCast(newDoc)[DocData][this.fieldKey + '_0'] = Docs.Create.TextDocument(question[0].includes('Answer: ') ? question[0].split('Answer: ')[1] : question[1]);
             }
+
             collectionArr.push(newDoc);
         }
         this.createFlashcardPile(collectionArr, true);
     };
 
+    /**
+     * Calls GPT for each flashcard type.
+     */
     askGPT = async (callType: GPTCallType): Promise<string | undefined> => {
-        const questionText = 'Question: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text);
+        let questionText = 'Question: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text);
         const rubricText = ' Rubric: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text);
         const queryText = questionText + ' UserAnswer: ' + this._inputValue + '. ' + rubricText;
         this._loading = true;
         const doc = DocCast(this.dataDoc[this.props.fieldKey + '_0']);
+
+        // if (true) {
+        //     const s = await this.youtubeUpload();
+
+        //     questionText = 'Question: ' + s;
+        // }
+
         if (callType == GPTCallType.CHATCARD) {
             if (StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text) === '') {
                 this._loading = false;
@@ -461,7 +493,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         }
         try {
             console.log(queryText);
-            const res = await gptAPICall(callType == GPTCallType.QUIZ ? queryText : questionText, callType);
+            const res = await gptAPICall(questionText, GPTCallType.FLASHCARD);
             if (!res) {
                 console.error('GPT call failed');
                 return;
@@ -647,7 +679,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         const clearButton = (which: string) => (
             <Tooltip title={<div className="dash-tooltip">remove</div>}>
                 <div
-                    // style={{ position: 'relative', top: '0px', left: '10px' }}
                     ref={this._closeRef}
                     className={`clear-button ${which}`}
                     onPointerDown={e => this.closeDown(e, which)} // prevent triggering slider movement in registerSliding
@@ -660,18 +691,13 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
             const whichDoc = DocCast(this.dataDoc[whichSlot]);
             const targetDoc = DocCast(whichDoc?.annotationOn, whichDoc);
             const layoutString = targetDoc ? '' : this.testForTextFields(whichSlot);
-            // whichDoc['backgroundColor'] = this.layoutDoc['backgroundColor'];
 
             return targetDoc || layoutString ? (
-                // <MathJaxContext config={this.mathJaxConfig}>
-                //     <MathJax>
                 <>
                     <DocumentView
                         // eslint-disable-next-line react/jsx-props-no-spreading
                         {...this._props}
                         fitWidth={undefined}
-                        NativeHeight={returnZero}
-                        NativeWidth={returnZero}
                         ignoreUsePath={layoutString ? true : undefined}
                         renderDepth={this.props.renderDepth + 1}
                         LayoutTemplateString={layoutString}
@@ -679,6 +705,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                         containerViewPath={this._props.docViewPath}
                         moveDocument={whichSlot.endsWith('1') ? this.moveDoc1 : this.moveDoc2}
                         removeDocument={whichSlot.endsWith('1') ? this.remDoc1 : this.remDoc2}
+                        NativeWidth={this.layoutWidth}
+                        NativeHeight={this.layoutHeight}
                         isContentActive={() => this.childActive}
                         isDocumentActive={returnFalse}
                         dontSelect={returnTrue}
@@ -687,9 +715,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                         hideLinkButton
                         pointerEvents={this.childActive ? undefined : returnNone}
                     />
-                    {/* </MathJax> */}
-                    {/* <div style={{ position: 'absolute', top: '-5px', left: '2px' }}>{layoutString ? null : clearButton(whichSlot)}</div> */}
-                    {/* </MathJaxContext> // placeholder image if doc is missingleft: `${NumCast(this.layoutDoc.width, 200) - 33}px` */}
                 </>
             ) : (
                 <div className="placeholder">
@@ -708,7 +733,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
                 }}
                 ref={ele => this.createDropTarget(ele, which, index)}>
                 {!this._isEmpty ? displayDoc(which) : null}
-                {/* {this.dataDoc[this.fieldKey + '_0'] !== 'empty' ? displayDoc(which) : null} */}
             </div>
         );
 
@@ -716,7 +740,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
             const side = this.frontSide ? 1 : 0;
 
             // add text box to each side when comparison box is first created
-            // (!this.dataDoc[this.fieldKey + '_0'] && this.dataDoc[this._props.fieldKey + '_0'] !== 'empty')
             if (!this.dataDoc[this.fieldKey + '_0'] && !this._isEmpty) {
                 const dataSplit = StrCast(this.dataDoc.data).includes('Keyword: ') ? StrCast(this.dataDoc.data).split('Keyword: ') : StrCast(this.dataDoc.data).split('Answer: ');
                 const newDoc = Docs.Create.TextDocument(dataSplit[1]);
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index ed79888ae..45301247b 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -168,11 +168,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         Object.values(this._disposers).forEach(disposer => disposer?.());
     }
 
+    /**
+     * Find images from the unsplash api to add to flashcards.
+     */
     fetchImages = async () => {
         try {
             const { data } = await axios.get(`${API_URL}?query=${this._searchInput}&page=1&per_page=${1}&client_id=${process.env.VITE_API_KEY}`);
-            console.log('data', data);
-            console.log(data.results);
             const imageSnapshot = Docs.Create.ImageDocument(data.results[0].urls.small, {
                 _nativeWidth: Doc.NativeWidth(this.layoutDoc),
                 _nativeHeight: Doc.NativeHeight(this.layoutDoc),
@@ -326,8 +327,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         if (ctx) {
             this._imageRef && ctx.drawImage(this._imageRef, NumCast(this._marqueeref.current?.left) * scaling, NumCast(this._marqueeref.current?.top) * scaling, w, h, 0, 0, w, h);
         }
-        // canvas.style.zIndex = '2000000';
-        // document.body.appendChild(canvas);
         const blob = await ImageUtility.canvasToBlob(canvas);
         return ImageBox.selectUrlToBase64(blob);
     };
@@ -350,7 +349,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         Doc.SetNativeHeight(imageSnapshot[DocData], Doc.NativeHeight(this.layoutDoc));
         this._props.addDocument?.(imageSnapshot);
         DocUtils.MakeLink(imageSnapshot, this.getAnchor(true), { link_relationship: 'video snapshot' });
-        // link && (DocCast(link.link_anchor_2)[DocData].timecodeToHide = NumCast(DocCast(link.link_anchor_2).timecodeToShow) + 3);  // do we need to set an end time? should default to +0.1
         setTimeout(() => downX !== undefined && downY !== undefined && DocumentView.getFirstDocumentView(imageSnapshot)?.startDragging(downX, downY, dropActionType.move, true));
     };
 
@@ -371,7 +369,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     pushInfo = async (quiz: quizMode, i?: string) => {
         this._quizMode = quiz;
         this._loading = true;
-        console.log('JHSDKFJHKSDJFHKSJDHFKJSDHFKJHSDKF');
 
         const img = {
             file: i ? i : this.paths[0],
@@ -383,10 +380,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 'Content-Type': 'application/json',
             },
         });
-
-        console.log('RESPONSE:');
-        console.log(response.data['boxes']);
-        console.log(response.data['text']);
         if (response.data['boxes'].length != 0) {
             this.createBoxes(response.data['boxes'], response.data['text']);
         } else {
@@ -394,6 +387,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         }
     };
 
+    /**
+     * Creates label boxes over text on the image to be filled in.
+     * @param boxes
+     * @param texts
+     */
     createBoxes = (boxes: [[[number, number]]], texts: [string]) => {
         const nscale = NumCast(this._props.PanelWidth()) * NumCast(this.layoutDoc._freeform_scale, 1);
         const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
@@ -405,17 +403,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
             const newCol = Docs.Create.LabelDocument({
                 _width: width,
-                //width * NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']),
                 _height: height,
-                //height * NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']),
                 _layout_fitWidth: true,
                 title: '',
-                // _layout_autoHeight: true,
             });
             const scaling = 1 / (this._props.NativeDimScaling?.() || 1);
             newCol.x = coords[0][0] + NumCast(this._marqueeref.current?.left) * scaling;
             newCol.y = coords[0][1] + NumCast(this._marqueeref.current?.top) * scaling;
-            // newCol[DocData].text_fontSize = height + 'px';
 
             newCol.zIndex = 1000;
             newCol.forceActive = true;
@@ -428,12 +422,14 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         }
     };
 
+    /**
+     * Create flashcards from an image.
+     */
     getImageDesc = async () => {
         this._loading = true;
         try {
             const hrefBase64 = await this.createCanvas();
             const response = await gptImageLabel(hrefBase64, 'Make flashcards out of this image with each question and answer labeled as "question" and "answer". Do not label each flashcard and do not include asterisks: ');
-            console.log(response);
             AnchorMenu.Instance.transferToFlashcard(response, NumCast(this.layoutDoc['x']), NumCast(this.layoutDoc['y']));
         } catch (error) {
             console.log('Error');
@@ -535,15 +531,16 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         }
     };
 
+    /**
+     * Check whether the contents of the label boxes on an image are correct.
+     */
     check = () => {
         this._loading = true;
         this._quizBoxes.forEach(async doc => {
             const input = StrCast(doc[DocData].title);
-            console.log('INP: ' + StrCast(input) + '; DOC: ' + StrCast(doc.quiz));
             if (this._quizMode == quizMode.SMART && input) {
                 const questionText = 'Question: What was labeled in this image?';
                 const rubricText = ' Rubric: ' + StrCast(doc.quiz);
-                // const queryText = 'RealAnswer: ' + StrCast(doc.quiz) + '. UserAnswer: ' + input + '.';
                 const queryText =
                     questionText +
                     ' UserAnswer: ' +
@@ -553,7 +550,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                     '. One sentence and evaluate based on meaning, not wording. Provide a hex color at the beginning with a period after it on a scale of green (minor details missed) to red (big error) for how correct the answer is. Example: "#FFFFFF. Pasta is delicious."';
                 const response = await gptAPICall(queryText, GPTCallType.QUIZ);
                 const hexSent = this.extractHexAndSentences(response);
-                console.log(hexSent.hexNumber);
                 doc.quiz = hexSent.sentences?.replace(/UserAnswer/g, "user's answer").replace(/Rubric/g, 'rubric');
                 doc.backgroundColor = '#' + hexSent.hexNumber;
             } else {
@@ -561,7 +557,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 doc.backgroundColor = match ? '#11c249' : '#eb2d2d';
             }
             doc.showQuiz = true;
-            // console.log(this.compareWords(input, StrCast(doc.quiz)) ? 'Match' : 'No Match');
         });
         this._loading = false;
     };
@@ -577,8 +572,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     exitQuizMode = () => {
         this._quizMode = quizMode.NONE;
         this._quizBoxes.forEach(doc => {
-            // this._props.removeDocument?.(DocCast(doc));
-            // this._props.DocumentView?.()._props.removeDocument?.(doc);
             this.removeDocument?.(doc);
         });
         this._quizBoxes = [];
@@ -595,7 +588,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         if (field) {
             const funcs: ContextMenuProps[] = [];
             const quizes: ContextMenuProps[] = [];
-            // funcs.push({ description: 'Create ai flashcards', event: () => this.getImageDesc(), icon: 'id-card' });
             quizes.push({
                 description: 'Smart Check',
                 event: this._quizMode == quizMode.NONE ? () => this.pushInfo(quizMode.SMART) : this.exitQuizMode,
@@ -606,19 +598,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 event: this._quizMode == quizMode.NONE ? () => this.pushInfo(quizMode.NORMAL) : this.exitQuizMode,
                 icon: 'pencil',
             });
-            // funcs.push({ description: 'Quiz Mode', subitems: optionItems, icon: 'eye' });
-            // funcs.push({
-            //     description: 'Quiz Mode',
-            //     event: !this._quizMode
-            //         ? () => this.pushInfo(false)
-            //         : () => {
-            //               this._quizMode = false;
-            //           },
-            //     icon: 'redo-alt',
-            // });
-            // funcs.push({ description: 'Get Text', event: this.check, icon: 'redo-alt' });
-            // funcs.push({ description: 'Get Labels2', event: this.getImageLabels2, icon: 'redo-alt' });
-            // funcs.push({ description: 'Get Labels', event: this.getImageLabels, icon: 'redo-alt' });
             funcs.push({ description: 'Rotate Clockwise 90', event: this.rotate, icon: 'redo-alt' });
             funcs.push({ description: `Show ${this.layoutDoc._showFullRes ? 'Dynamic Res' : 'Full Res'}`, event: this.resolution, icon: 'expand' });
             funcs.push({ description: 'Set Native Pixel Size', event: this.setNativeSize, icon: 'expand-arrows-alt' });
-- 
cgit v1.2.3-70-g09d2


From 07f525dc8eef3fdedc476af1a98b5bb35314b6c6 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 30 Sep 2024 15:03:57 -0400
Subject: cleaned up some lint errors.

---
 src/client/views/ContextMenu.tsx                         |  3 ---
 src/client/views/nodes/AudioBox.tsx                      |  3 +--
 src/client/views/nodes/ImageBox.tsx                      | 11 ++++-------
 src/client/views/nodes/PDFBox.tsx                        |  5 +----
 .../views/nodes/formattedText/FormattedTextBox.tsx       | 16 +++++-----------
 src/client/views/pdf/AnchorMenu.tsx                      |  5 ++---
 src/client/views/pdf/PDFViewer.tsx                       |  2 --
 src/fields/Doc.ts                                        |  4 ----
 8 files changed, 13 insertions(+), 36 deletions(-)

(limited to 'src/client/views/nodes/AudioBox.tsx')

diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 0e98d2e35..e0eeb3f53 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -1,6 +1,3 @@
-/* eslint-disable react/no-array-index-key */
-/* eslint-disable react/jsx-props-no-spreading */
-/* eslint-disable default-param-last */
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, IReactionDisposer, makeObservable, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 8056ced1e..aaeb1eb31 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -8,7 +8,7 @@ import { DateField } from '../../../fields/DateField';
 import { Doc, Opt } from '../../../fields/Doc';
 import { DocData } from '../../../fields/DocSymbols';
 import { ComputedField } from '../../../fields/ScriptField';
-import { Cast, DateCast, DocCast, NumCast } from '../../../fields/Types';
+import { Cast, DateCast, NumCast } from '../../../fields/Types';
 import { AudioField, nullAudio } from '../../../fields/URLField';
 import { formatTime } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
@@ -741,7 +741,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 ref={action((r: CollectionStackedTimeline | null) => {
                     this._stackedTimeline = r;
                 })}
-                // eslint-disable-next-line react/jsx-props-no-spreading
                 {...this._props}
                 dataFieldKey={this.fieldKey}
                 fieldKey={this.annotationKey}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 91e51d24e..ae9e70e8d 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -316,7 +316,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         return cropping;
     };
 
-    createCanvas = async (downX?: number, downY?: number, cb?: (filename: string, x: number | undefined, y: number | undefined) => void) => {
+    createCanvas = async () => {
         const canvas = document.createElement('canvas');
         const scaling = 1 / (this._props.NativeDimScaling?.() || 1);
         const w = AnchorMenu.Instance.marqueeWidth * scaling;
@@ -393,9 +393,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
      * @param texts
      */
     createBoxes = (boxes: [[[number, number]]], texts: [string]) => {
-        const nscale = NumCast(this._props.PanelWidth()) * NumCast(this.layoutDoc._freeform_scale, 1);
-        const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
-        for (var i = 0; i < boxes.length; i++) {
+        for (let i = 0; i < boxes.length; i++) {
             const coords = boxes[i] ? boxes[i] : [];
             const width = coords[1][0] - coords[0][0];
             const height = coords[2][1] - coords[0][1];
@@ -432,7 +430,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             const response = await gptImageLabel(hrefBase64, 'Make flashcards out of this image with each question and answer labeled as "question" and "answer". Do not label each flashcard and do not include asterisks: ');
             AnchorMenu.Instance.transferToFlashcard(response, NumCast(this.layoutDoc['x']), NumCast(this.layoutDoc['y']));
         } catch (error) {
-            console.log('Error');
+            console.log('Error', error);
         }
         this._loading = false;
     };
@@ -442,7 +440,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             const hrefBase64 = await this.createCanvas();
             this.pushInfo(quizMode.NORMAL, hrefBase64);
         } catch (error) {
-            console.log('Error');
+            console.log('Error', error);
         }
     };
 
@@ -824,7 +822,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 }}>
                 <CollectionFreeFormView
                     ref={this._ffref}
-                    // eslint-disable-next-line react/jsx-props-no-spreading
                     {...this._props}
                     setContentViewBox={emptyFunction}
                     NativeWidth={returnZero}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index cb0b0d71f..596975062 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -10,7 +10,7 @@ import { DocData } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
 import { ComputedField } from '../../../fields/ScriptField';
-import { Cast, FieldValue, ImageCast, NumCast, StrCast, toList } from '../../../fields/Types';
+import { Cast, FieldValue, NumCast, StrCast, toList } from '../../../fields/Types';
 import { ImageField, PdfField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
 import { emptyFunction } from '../../../Utils';
@@ -540,7 +540,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             return ComponentTag === CollectionStackingView ? (
                 <SidebarAnnos
                     ref={this._sidebarRef}
-                    // eslint-disable-next-line react/jsx-props-no-spreading
                     {...this._props}
                     Document={this.Document}
                     layoutDoc={this.layoutDoc}
@@ -556,7 +555,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             ) : (
                 <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this._props.select(false), true)}>
                     <ComponentTag
-                        // eslint-disable-next-line react/jsx-props-no-spreading
                         {...this._props}
                         setContentViewBox={emptyFunction} // override setContentView to do nothing
                         NativeWidth={this.sidebarNativeWidthFunc}
@@ -610,7 +608,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         top: 0,
                     }}>
                     <PDFViewer
-                        // eslint-disable-next-line react/jsx-props-no-spreading
                         {...this._props}
                         pdfBox={this}
                         sidebarAddDoc={this.sidebarAddDocument}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 07a4d1093..9b3e1ca39 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -141,6 +141,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
     set _recordingDictation(value) {
         !this.dataDoc[`${this.fieldKey}_recordingSource`] && (this.dataDoc.mediaState = value ? mediaState.Recording : undefined);
     }
+
+    // eslint-disable-next-line no-return-assign
+    @computed get config()                     { return FormattedTextBox.MakeConfig(this._rules = new RichTextRules(this.Document, this), this._props); } // prettier-ignore
     @computed get _recordingDictation()        { return this.dataDoc?.mediaState === mediaState.Recording; } // prettier-ignore
     @computed get SidebarShown()               {  return !!(this._showSidebar || this.layoutDoc._layout_showSidebar);  } // prettier-ignore
     @computed get allSidebarDocs()             { return DocListCast(this.dataDoc[this.sidebarKey]); } // prettier-ignore
@@ -153,7 +156,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
     @computed get sidebarHeight()              { return !this.sidebarWidth() ? 0 : NumCast(this.dataDoc[this.sidebarKey + '_height']); } // prettier-ignore
     @computed get titleHeight()                { return this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.HeaderMargin) as number || 0; } // prettier-ignore
     @computed get layout_autoHeightMargins()   { return this.titleHeight + NumCast(this.layoutDoc._layout_autoHeightMargins); } // prettier-ignore
-    @computed get config()                     { return FormattedTextBox.MakeConfig(this._rules = new RichTextRules(this.Document, this), this._props); } // prettier-ignore
     @computed get sidebarKey()                 { return this.fieldKey + '_sidebar'; } // prettier-ignore
 
     constructor(props: FormattedTextBoxProps) {
@@ -663,7 +665,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
                         textContent += node.child(i).textContent;
                         i++;
                     }
-                    // eslint-disable-next-line no-cond-assign
                     while (ep && (foundAt = textContent.slice(index).search(regexp)) > -1) {
                         const sel = new TextSelection(pm.state.doc.resolve(ep.from + index + blockOffset + foundAt + 1), pm.state.doc.resolve(ep.from + index + blockOffset + foundAt + find.length + 1));
                         ret.push(sel);
@@ -722,7 +723,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
             const hr = Math.round(Date.now() / 1000 / 60 / 60);
             numberRange(10).map(i => addStyleSheetRule(FormattedTextBox._userStyleSheet, 'UM-hr-' + (hr - i), { opacity: ((10 - i - 1) / 10).toString() }));
         }
-        // eslint-disable-next-line operator-assignment
         this.layoutDoc[DocCss] = this.layoutDoc[DocCss] + 1; // css changes happen outside of react/mobx.  so we need to set a flag that will notify anyone interested in layout changes triggered by css changes (eg., CollectionLinkView)
     };
 
@@ -987,7 +987,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
     findImageTags = async () => {
         const c = this.ProseRef?.getElementsByTagName('img');
         if (c) {
-            for (let i of c) {
+            for (const i of c) {
                 console.log(i);
 
                 // console.log(canvas.toDataURL());
@@ -1034,7 +1034,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
             // this.Document[DocData].description = response.trim();
             // return response; // Return the response
         } catch (error) {
-            console.log('Error');
+            console.log('Error', error);
         }
         // return '';
     };
@@ -1195,7 +1195,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
             const nodes: Node[] = [];
             let hadStart = start !== 0;
             frag.forEach((node, index) => {
-                // eslint-disable-next-line no-use-before-define
                 const examinedNode = findAnchorNode(node, editor);
                 if (examinedNode?.node && (examinedNode.node.textContent || examinedNode.node.type === this._editorView?.state.schema.nodes.dashDoc || examinedNode.node.type === this._editorView?.state.schema.nodes.audiotag)) {
                     nodes.push(examinedNode.node);
@@ -1349,7 +1348,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
             action(selected => {
                 this.prepareForTyping();
                 if (FormattedTextBox._globalHighlights.has('Bold Text')) {
-                    // eslint-disable-next-line operator-assignment
                     this.layoutDoc[DocCss] = this.layoutDoc[DocCss] + 1; // css change happens outside of mobx/react, so this will notify anyone interested in the layout that it has changed
                 }
                 if (RichTextMenu.Instance?.view === this._editorView && !selected) {
@@ -1800,7 +1798,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
         const match = RTFCast(this.Document[this.fieldKey])?.Text.match(/^(@[a-zA-Z][a-zA-Z_0-9 -]*[a-zA-Z_0-9-]+)/);
         if (match) {
             this.dataDoc.title_custom = true;
-            // eslint-disable-next-line prefer-destructuring
             this.dataDoc.title = match[1]; // this triggers the collectionDockingView to publish this Doc
             this.EditorView?.dispatch(this.EditorView?.state.tr.deleteRange(0, match[1].length + 1));
         }
@@ -1882,7 +1879,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
         const margins = 2 * NumCast(this.layoutDoc._yMargin, this._props.yPadding || 0);
         const children = this.ProseRef?.children.length ? Array.from(this.ProseRef.children[0].children) : undefined;
         if (children && !SnappingManager.IsDragging) {
-            // eslint-disable-next-line no-use-before-define
             const getChildrenHeights = (kids: Element[] | undefined) => kids?.reduce((p, child) => p + toHgt(child), margins) ?? 0;
             const toNum = (val: string) => Number(val.replace('px', ''));
             const toHgt = (node: Element): number => {
@@ -1969,7 +1965,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
             return ComponentTag === CollectionStackingView ? (
                 <SidebarAnnos
                     ref={this._sidebarRef}
-                    // eslint-disable-next-line react/jsx-props-no-spreading
                     {...this._props}
                     Document={this.Document}
                     layoutDoc={this.layoutDoc}
@@ -1989,7 +1984,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
             ) : (
                 <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => DocumentView.SelectView(this.DocumentView?.(), false), true)}>
                     <ComponentTag
-                        // eslint-disable-next-line react/jsx-props-no-spreading
                         {...this._props}
                         ref={this._sidebarTagRef}
                         setContentView={emptyFunction}
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index 6dd036cf6..a212cbd91 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -15,7 +15,6 @@ import { LinkPopup } from '../linking/LinkPopup';
 import { DocumentView } from '../nodes/DocumentView';
 import './AnchorMenu.scss';
 import { GPTPopup, GPTPopupMode } from './GPTPopup/GPTPopup';
-import ReactLoading from 'react-loading';
 
 @observer
 export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -137,8 +136,8 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
 
     transferToFlashcard = (text: string, x: number, y: number) => {
         // put each question generated by GPT on the front of the flashcard
-        var senArr = text.trim().split('Question: ');
-        var collectionArr: Doc[] = [];
+        const senArr = text.trim().split('Question: ');
+        const collectionArr: Doc[] = [];
         for (let i = 1; i < senArr.length; i++) {
             console.log('Arr ' + i + ': ' + senArr[i]);
             const newDoc = Docs.Create.ComparisonDocument(senArr[i], { _layout_isFlashcard: true, _width: 300, _height: 300 });
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 02d310f7d..477157cce 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -660,7 +660,6 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
         return (
             <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this._props.Document), transform: `scale(${NumCast(this._props.layoutDoc._freeform_scale, 1)})` }} ref={this._annotationLayer}>
                 {inlineAnnos.map(anno => (
-                    // eslint-disable-next-line react/jsx-props-no-spreading
                     <Annotation {...this._props} fieldKey={this._props.fieldKey + '_annotations'} pointerEvents={this.pointerEvents} containerDataDoc={this._props.dataDoc} annoDoc={anno} key={`${anno[Id]}-annotation`} />
                 ))}
             </div>
@@ -694,7 +693,6 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
                 pointerEvents: Doc.ActiveTool !== InkTool.None ? 'all' : undefined,
             }}>
             <CollectionFreeFormView
-                // eslint-disable-next-line react/jsx-props-no-spreading
                 {...this._props}
                 NativeWidth={returnZero}
                 NativeHeight={returnZero}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index b8025cac4..90ecc7f56 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -335,7 +335,6 @@ export class Doc extends RefField {
         if (!id || forceSave) {
             DocServer.CreateDocField(docProxy);
         }
-        // eslint-disable-next-line no-constructor-return
         return docProxy; // need to return the proxy from the constructor so that all our added fields will get called
     }
 
@@ -463,7 +462,6 @@ export class Doc extends RefField {
     }
 }
 
-// eslint-disable-next-line no-redeclare
 export namespace Doc {
     export let SelectOnLoad: Doc | undefined;
     export function SetSelectOnLoad(doc: Doc | undefined) {
@@ -659,7 +657,6 @@ export namespace Doc {
                     if (reversed) list.splice(0, 0, doc);
                     else list.push(doc);
                 } else {
-                    // eslint-disable-next-line no-lonely-if
                     if (reversed) list.splice(before ? list.length - ind + 1 : list.length - ind, 0, doc);
                     else list.splice(before ? ind : ind + 1, 0, doc);
                 }
@@ -1191,7 +1188,6 @@ export namespace Doc {
         return Cast(Doc.UserDoc().myLinkDatabase, Doc, null);
     }
     export function SetUserDoc(doc: Doc) {
-        // eslint-disable-next-line no-return-assign
         return (manager._user_doc = doc);
     }
 
-- 
cgit v1.2.3-70-g09d2


From fa54fdf2bf9bf8523da393a81ec1ac1cd4fa0f4c Mon Sep 17 00:00:00 2001
From: alyssaf16 <alyssa_feinberg@brown.edu>
Date: Sun, 6 Oct 2024 15:11:20 -0400
Subject: comments

---
 src/client/views/nodes/AudioBox.tsx       |  3 --
 src/client/views/nodes/ComparisonBox.scss | 44 ------------------------
 src/client/views/nodes/ComparisonBox.tsx  | 13 ++++++-
 src/client/views/nodes/ImageBox.tsx       | 57 +++++++++++++++++++++++++++++--
 src/client/views/nodes/LabelBox.tsx       |  8 +----
 src/client/views/nodes/PDFBox.tsx         |  5 +--
 src/client/views/pdf/PDFViewer.tsx        | 43 -----------------------
 7 files changed, 69 insertions(+), 104 deletions(-)

(limited to 'src/client/views/nodes/AudioBox.tsx')

diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 8056ced1e..6a918664c 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -297,7 +297,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             },
         });
         this.Document[DocData].phoneticTranscription = response.data['transcription'];
-        console.log('RESPONSE: ' + response.data['transcription']);
     };
 
     youtubeUpload = async () => {
@@ -310,13 +309,11 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 'Content-Type': 'application/json',
             },
         });
-        console.log('RESPONSE: ' + response.data['transcription']);
     };
 
     // context menu
     specificContextMenu = (): void => {
         const funcs: ContextMenuProps[] = [];
-        // funcs.push({ description: 'Push info', event: this.pushInfo, icon: 'redo-alt' });
 
         funcs.push({
             description: 'Youtube',
diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss
index da1d352f2..b7307f3a3 100644
--- a/src/client/views/nodes/ComparisonBox.scss
+++ b/src/client/views/nodes/ComparisonBox.scss
@@ -30,12 +30,10 @@
         padding-top: 5px;
         padding-left: 5px;
         padding-right: 5px;
-        // width: 80%;
         border-radius: 2px;
         height: 17%;
         display: inline-block;
         bottom: 0;
-        // right: 0;
 
         &.schema-header-button {
             color: gray;
@@ -57,28 +55,11 @@
         }
         &.submit {
             width: 40%;
-            // float: right;
-
-            // position: absolute;
-            // position: 10px;
-            // padding-left: 35%;
-            // padding-right: 80%;
-            // // width: 80px;
-            // // right: 0;
-            // right: 0;
-            // bottom: 0;
         }
         &.record {
             width: 20%;
             float: left;
             border-radius: 2px;
-            // right: 0;
-            // height: 30%;
-        }
-
-        button {
-            // flex: 1;
-            // position: relative;
         }
     }
 
@@ -128,7 +109,6 @@
     textarea {
         flex: 1;
         padding: 10px;
-        // position: relative;
         resize: none;
         position: 'absolute';
         width: '91%';
@@ -235,7 +215,6 @@
     top: 10px;
     left: 10px;
     z-index: 200;
-    // padding: 5px;
     background: #dfdfdf;
     pointer-events: none;
 }
@@ -249,29 +228,8 @@
             display: flex;
         }
     }
-
-    // .input-box {
-    //     position: absolute;
-    //     padding: 10px;
-    // }
-    // input[type='text'] {
-    //     flex: 1;
-    //     position: relative;
-    //     margin-right: 10px;
-    //     width: 100px;
-    // }
 }
 
-// .quiz-card {
-//     position: relative;
-
-//     input[type='text'] {
-//         flex: 1;
-//         position: relative;
-//         margin-right: 10px;
-//         width: 100px;
-//     }
-// }
 .QuizCard {
     width: 100%;
     height: 100%;
@@ -288,8 +246,6 @@
         align-items: center;
         justify-content: center;
         .QuizCardBox {
-            /* existing code */
-
             .DIYNodeBox-iframe {
                 height: 100%;
                 width: 100%;
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 9ac8d7c52..461a65c27 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -340,6 +340,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         ContextMenu.Instance.setLangIndex(ind);
     };
 
+    /**
+     * Determine which language the speech to text tool is in.
+     * @returns
+     */
     convertAbr = () => {
         switch (this.recognition.lang) {
             case 'en-US': return 'English'; //prettier-ignore
@@ -364,6 +368,9 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         ContextMenu.Instance.displayMenu(x, y);
     };
 
+    /**
+     * Creates an AudioBox to record a user's audio.
+     */
     evaluatePronunciation = () => {
         const newAudio = Docs.Create.AudioDocument(nullAudio, { _width: 200, _height: 100 });
         this.Document.audio = newAudio[DocData];
@@ -386,6 +393,11 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         this.Document.phoneticTranscription = response.data['transcription'];
     };
 
+    /**
+     * Extracts the id of the youtube video url.
+     * @param url
+     * @returns
+     */
     getYouTubeVideoId = (url: string) => {
         const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=|\?v=)([^#\&\?]*).*/;
         const match = url.match(regExp);
@@ -510,7 +522,6 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
             } else if (callType === GPTCallType.FLASHCARD) {
                 this._loading = false;
                 return res;
-            } else if (callType === GPTCallType.STACK) {
             }
             this._loading = false;
             return res;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 91e51d24e..32d1e471e 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -316,6 +316,14 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         return cropping;
     };
 
+    /**
+     * Draw image to a canvas so it can be converted to base64 and be passed into
+     * GPT to be analyzed.
+     * @param downX
+     * @param downY
+     * @param cb
+     * @returns
+     */
     createCanvas = async (downX?: number, downY?: number, cb?: (filename: string, x: number | undefined, y: number | undefined) => void) => {
         const canvas = document.createElement('canvas');
         const scaling = 1 / (this._props.NativeDimScaling?.() || 1);
@@ -366,6 +374,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         }
     };
 
+    /**
+     * Calls backend to find any text on an image. Gets the text and the
+     * coordinates of the text and creates label boxes at those locations.
+     * @param quiz
+     * @param i
+     */
     pushInfo = async (quiz: quizMode, i?: string) => {
         this._quizMode = quiz;
         this._loading = true;
@@ -437,6 +451,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         this._loading = false;
     };
 
+    /**
+     * Calls the createCanvas and pushInfo methods to convert the
+     * image to a form that can be passed to GPT and find the locations
+     * of the text.
+     */
     makeLabels = async () => {
         try {
             const hrefBase64 = await this.createCanvas();
@@ -446,6 +465,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         }
     };
 
+    /**
+     * Determines whether two words should be considered
+     * the same, allowing minor typos.
+     * @param str1
+     * @param str2
+     * @returns
+     */
     levenshteinDistance = (str1: string, str2: string) => {
         const len1 = str1.length;
         const len2 = str2.length;
@@ -471,6 +497,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         return dp[len1][len2];
     };
 
+    /**
+     * Different algorithm for determining string similarity.
+     * @param str1
+     * @param str2
+     * @returns
+     */
     jaccardSimilarity = (str1: string, str2: string) => {
         const set1 = new Set(str1.split(' '));
         const set2 = new Set(str2.split(' '));
@@ -481,6 +513,14 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         return intersection.size / union.size;
     };
 
+    /**
+     * Averages the jaccardSimilarity and levenshteinDistance scores
+     * to determine string similarity for the labelboxes answers and
+     * the users response.
+     * @param str1
+     * @param str2
+     * @returns
+     */
     stringSimilarity(str1: string, str2: string) {
         const levenshteinDist = this.levenshteinDistance(str1, str2);
         const levenshteinScore = 1 - levenshteinDist / Math.max(str1.length, str2.length);
@@ -511,12 +551,23 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         );
     }
 
+    /**
+     * Returns whether two strings are similar
+     * @param input
+     * @param target
+     * @returns
+     */
     compareWords = (input: string, target: string) => {
         const distance = this.stringSimilarity(input.toLowerCase(), target.toLowerCase());
-        // const threshold = Math.max(input.length, target.length) * 0.2; // Allow up to 20% of the length as difference
         return distance >= 0.7;
     };
 
+    /**
+     * GPT returns a hex color for what color the label box should be based on
+     * the correctness of the users answer.
+     * @param inputString
+     * @returns
+     */
     extractHexAndSentences = (inputString: string) => {
         // Regular expression to match a hexadecimal number at the beginning followed by a period and sentences
         const regex = /^#([0-9A-Fa-f]+)\.\s*(.+)$/s;
@@ -569,13 +620,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         });
     };
 
+    /**
+     * Get rid of all the label boxes on the images.
+     */
     exitQuizMode = () => {
         this._quizMode = quizMode.NONE;
         this._quizBoxes.forEach(doc => {
             this.removeDocument?.(doc);
         });
         this._quizBoxes = [];
-        console.log('remove');
     };
 
     @action
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index bcf55fbe8..79366f76f 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -169,11 +169,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         width: this._props.PanelWidth(),
                         height: this._props.PanelHeight(),
                         whiteSpace: 'multiLine' in boxParams && boxParams.multiLine ? 'pre-wrap' : 'pre',
-                    }}
-                    // onMouseLeave={() => {
-                    //     this.hoverFlip(undefined);
-                    // }}
-                >
+                    }}>
                     <div
                         style={{
                             width: this._props.PanelWidth() - 2 * NumCast(this.layoutDoc._xPadding),
@@ -185,10 +181,8 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         })}
                         onKeyUp={action(e => {
                             e.stopPropagation();
-                            // if (e.key === 'Enter') {
                             this.dataDoc[this.fieldKey] = this._divRef?.innerText ?? '';
                             setTimeout(() => this._props.select(false));
-                            // }
                         })}
                         onBlur={() => {
                             this.dataDoc[this.fieldKey] = this._divRef?.innerText ?? '';
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index cb0b0d71f..e7470c74c 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -120,11 +120,9 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         this.replaceCanvases(docViewContent, newDiv);
         const htmlString = this._pdfViewer?._mainCont.current && new XMLSerializer().serializeToString(newDiv);
 
-        // const anchx = NumCast(cropping.x);
-        // const anchy = NumCast(cropping.y);
         const anchw = NumCast(cropping._width) * (this._props.NativeDimScaling?.() || 1);
         const anchh = NumCast(cropping._height) * (this._props.NativeDimScaling?.() || 1);
-        // const viewScale = 1;
+
         cropping.title = 'crop: ' + this.Document.title;
         cropping.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width);
         cropping.y = NumCast(this.Document.y);
@@ -473,7 +471,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
         !Doc.noviceMode && optionItems.push({ description: 'Toggle Sidebar Type', event: this.toggleSidebarType, icon: 'expand-arrows-alt' });
         !Doc.noviceMode && optionItems.push({ description: 'update icon', event: () => this.pdfUrl && this.updateIcon(), icon: 'expand-arrows-alt' });
-        // optionItems.push({ description: "Toggle Sidebar ", event: () => this.toggleSidebar(), icon: "expand-arrows-alt" });
         !options && ContextMenu.Instance.addItem({ description: 'Options...', subitems: optionItems, icon: 'asterisk' });
         const help = cm.findByDescription('Help...');
         const helpItems = help?.subitems ?? [];
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 02d310f7d..1d7f269fb 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -30,12 +30,6 @@ import { GPTPopup } from './GPTPopup/GPTPopup';
 import './PDFViewer.scss';
 import { GPTCallType, gptAPICall } from '../../apis/gpt/GPT';
 import ReactLoading from 'react-loading';
-// import html2canvas from 'html2canvas';
-// import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition';
-
-// pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`;
-// The workerSrc property shall be specified.
-// Pdfjs.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@4.4.168/build/pdf.worker.mjs';
 
 interface IViewerProps extends FieldViewProps {
     pdfBox: PDFBox;
@@ -64,43 +58,6 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
         super(props);
         makeObservable(this);
     }
-    // @observable transcriptRef = React.createRef();
-    // @observable startBtnRef = React.createRef();
-    // @observable stopBtnRef = React.createRef();
-    // @observable transcriptElement = '';
-
-    // handleResult = (e: SpeechRecognitionEvent) => {
-    //     let interimTranscript = '';
-    //     let finalTranscript = '';
-    //     console.log('H');
-    //     for (let i = e.resultIndex; i < e.results.length; i++) {
-    //         const transcript = e.results[i][0].transcript;
-    //         if (e.results[i].isFinal) {
-    //             finalTranscript += transcript;
-    //         } else {
-    //             interimTranscript += transcript;
-    //         }
-    //     }
-    //     console.log(interimTranscript);
-    //     this.transcriptElement = finalTranscript || interimTranscript;
-    // };
-
-    // startListening = () => {
-    //     const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
-    //     if (SpeechRecognition) {
-    //         console.log('here');
-    //         const recognition = new SpeechRecognition();
-    //         recognition.continuous = true; // Continue listening even if the user pauses
-    //         recognition.interimResults = true; // Show interim results
-    //         recognition.lang = 'en-US'; // Set language (optional)
-    //         recognition.onresult = this.handleResult.bind(this);
-    //         // recognition.onend = this.handleEnd.bind(this);
-
-    //         recognition.start();
-    //         // this.handleResult;
-    //         // recognition.stop();
-    //     }
-    // };
 
     @observable _pageSizes: { width: number; height: number }[] = [];
     @observable _savedAnnotations = new ObservableMap<number, (HTMLDivElement & { marqueeing?: boolean })[]>();
-- 
cgit v1.2.3-70-g09d2


From 66950dca6e7add542aba3c6caa8115ce7f1ecd73 Mon Sep 17 00:00:00 2001
From: alyssaf16 <alyssa_feinberg@brown.edu>
Date: Mon, 7 Oct 2024 22:48:54 -0400
Subject: comments and clean up

---
 eslint.config.mjs                        |  65 ++-------
 package-lock.json                        | 239 ++++++++++++++++++-------------
 package.json                             |  10 +-
 src/client/views/nodes/AudioBox.tsx      |  19 +--
 src/client/views/nodes/ComparisonBox.tsx |   7 -
 src/client/views/nodes/ImageBox.tsx      |   1 -
 6 files changed, 151 insertions(+), 190 deletions(-)

(limited to 'src/client/views/nodes/AudioBox.tsx')

diff --git a/eslint.config.mjs b/eslint.config.mjs
index f7063caa5..4f03c066a 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -1,58 +1,11 @@
-import pluginJs from '@eslint/js';
-import pluginReactConfig from 'eslint-plugin-react/configs/recommended.js';
-import globals from 'globals';
-import tseslint from 'typescript-eslint';
+import globals from "globals";
+import tseslint from "typescript-eslint";
+import pluginReact from "eslint-plugin-react";
 
-export default [
-    {
-        languageOptions: { globals: { ...globals.browser, ...globals.node } },
-    },
-    pluginJs.configs.recommended,
-    ...tseslint.configs.recommended,
-    {
-        rules: {
-            'node/no-missing-import': 0,
-            'no-console': 'off',
-            'func-names': 'off',
-            'no-process-exit': 'off',
-            'object-shorthand': 'off',
-            'class-methods-use-this': 'off',
-            'single-quote': 'off',
-            'max-classes-per-file': 0,
-
-            'react/jsx-filename-extension': [
-                2,
-                {
-                    extensions: ['.js', '.jsx', '.ts', '.tsx'],
-                },
-            ],
 
-            'import/prefer-default-export': 'off',
-            'no-unused-expressions': 'off',
-            '@typescript-eslint/no-unused-expressions': 'off',
-            'prefer-template': 'off',
-            'no-inner-declarations': 'off',
-            'no-plusplus': 'off',
-            'no-multi-assign': 'off',
-            'no-underscore-dangle': 'off',
-            'no-nested-ternary': 'off',
-            'no-param-reassign': 'error',
-            'lines-between-class-members': 'off',
-            'no-shadow': 'off',
-            '@typescript-eslint/no-shadow': 'warn',
-            'no-unused-vars': 'off',
-            '@typescript-eslint/no-unused-vars': 'error',
-            '@typescript-eslint/no-namespace': 'off',
-            'react/destructuring-assignment': 0,
-            'prefer-arrow-callback': 'error',
-            'no-return-assign': 'error',
-            'no-await-in-loop': 'error',
-            'no-loop-func': 'error',
-            'no-cond-assign': 'error',
-            'no-use-before-define': 'error',
-            '@typescript-eslint/no-explicit-any': 'error',
-            'no-restricted-globals': ['error', 'event'],
-        },
-    },
-    pluginReactConfig,
-];
+export default [
+  {files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"]},
+  {languageOptions: { globals: globals.browser }},
+  ...tseslint.configs.recommended,
+  pluginReact.configs.flat.recommended,
+];
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 276a516df..25ffaf22b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -308,9 +308,9 @@
                 "@types/youtube": "^0.1.0",
                 "chai": "^5.0.0",
                 "cross-env": "^7.0.3",
-                "eslint": "^9.10.0",
-                "eslint-plugin-react": "^7.36.1",
-                "globals": "^15.9.0",
+                "eslint": "^9.12.0",
+                "eslint-plugin-react": "^7.37.1",
+                "globals": "^15.10.0",
                 "jsdom": "^25.0.0",
                 "mocha": "^10.2.0",
                 "prettier": "^3.1.0",
@@ -319,7 +319,7 @@
                 "ts-loader": "^9.5.1",
                 "ts-node": "^10.9.1",
                 "ts-node-dev": "^2.0.0",
-                "typescript-eslint": "^8.6.0",
+                "typescript-eslint": "^8.8.0",
                 "webpack-dev-server": "^5.0.4"
             },
             "engines": {
@@ -2638,6 +2638,14 @@
                 "node": "*"
             }
         },
+        "node_modules/@eslint/core": {
+            "version": "0.6.0",
+            "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz",
+            "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==",
+            "engines": {
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+            }
+        },
         "node_modules/@eslint/eslintrc": {
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz",
@@ -2708,10 +2716,9 @@
             }
         },
         "node_modules/@eslint/js": {
-            "version": "9.10.0",
-            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.10.0.tgz",
-            "integrity": "sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==",
-            "license": "MIT",
+            "version": "9.12.0",
+            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz",
+            "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==",
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             }
@@ -2725,10 +2732,9 @@
             }
         },
         "node_modules/@eslint/plugin-kit": {
-            "version": "0.1.0",
-            "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.1.0.tgz",
-            "integrity": "sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ==",
-            "license": "Apache-2.0",
+            "version": "0.2.0",
+            "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz",
+            "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==",
             "dependencies": {
                 "levn": "^0.4.1"
             },
@@ -2990,6 +2996,26 @@
                 "supercluster": "^8.0.1"
             }
         },
+        "node_modules/@humanfs/core": {
+            "version": "0.19.0",
+            "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz",
+            "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==",
+            "engines": {
+                "node": ">=18.18.0"
+            }
+        },
+        "node_modules/@humanfs/node": {
+            "version": "0.16.5",
+            "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz",
+            "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==",
+            "dependencies": {
+                "@humanfs/core": "^0.19.0",
+                "@humanwhocodes/retry": "^0.3.0"
+            },
+            "engines": {
+                "node": ">=18.18.0"
+            }
+        },
         "node_modules/@humanwhocodes/module-importer": {
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
@@ -3003,9 +3029,9 @@
             }
         },
         "node_modules/@humanwhocodes/retry": {
-            "version": "0.3.0",
-            "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz",
-            "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==",
+            "version": "0.3.1",
+            "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
+            "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
             "engines": {
                 "node": ">=18.18"
             },
@@ -4154,6 +4180,8 @@
             "version": "2.1.5",
             "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
             "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@nodelib/fs.stat": "2.0.5",
                 "run-parallel": "^1.1.9"
@@ -4166,6 +4194,8 @@
             "version": "2.0.5",
             "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
             "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+            "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 8"
             }
@@ -4174,6 +4204,8 @@
             "version": "1.2.8",
             "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
             "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@nodelib/fs.scandir": "2.1.5",
                 "fastq": "^1.6.0"
@@ -9435,9 +9467,9 @@
             }
         },
         "node_modules/@types/estree": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
-            "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
+            "version": "1.0.6",
+            "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+            "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="
         },
         "node_modules/@types/estree-jsx": {
             "version": "1.0.5",
@@ -10202,17 +10234,17 @@
             "dev": true
         },
         "node_modules/@typescript-eslint/eslint-plugin": {
-            "version": "8.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.6.0.tgz",
-            "integrity": "sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==",
+            "version": "8.8.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.0.tgz",
+            "integrity": "sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
                 "@eslint-community/regexpp": "^4.10.0",
-                "@typescript-eslint/scope-manager": "8.6.0",
-                "@typescript-eslint/type-utils": "8.6.0",
-                "@typescript-eslint/utils": "8.6.0",
-                "@typescript-eslint/visitor-keys": "8.6.0",
+                "@typescript-eslint/scope-manager": "8.8.0",
+                "@typescript-eslint/type-utils": "8.8.0",
+                "@typescript-eslint/utils": "8.8.0",
+                "@typescript-eslint/visitor-keys": "8.8.0",
                 "graphemer": "^1.4.0",
                 "ignore": "^5.3.1",
                 "natural-compare": "^1.4.0",
@@ -10236,16 +10268,16 @@
             }
         },
         "node_modules/@typescript-eslint/parser": {
-            "version": "8.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.6.0.tgz",
-            "integrity": "sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==",
+            "version": "8.8.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.8.0.tgz",
+            "integrity": "sha512-uEFUsgR+tl8GmzmLjRqz+VrDv4eoaMqMXW7ruXfgThaAShO9JTciKpEsB+TvnfFfbg5IpujgMXVV36gOJRLtZg==",
             "dev": true,
             "license": "BSD-2-Clause",
             "dependencies": {
-                "@typescript-eslint/scope-manager": "8.6.0",
-                "@typescript-eslint/types": "8.6.0",
-                "@typescript-eslint/typescript-estree": "8.6.0",
-                "@typescript-eslint/visitor-keys": "8.6.0",
+                "@typescript-eslint/scope-manager": "8.8.0",
+                "@typescript-eslint/types": "8.8.0",
+                "@typescript-eslint/typescript-estree": "8.8.0",
+                "@typescript-eslint/visitor-keys": "8.8.0",
                 "debug": "^4.3.4"
             },
             "engines": {
@@ -10265,14 +10297,14 @@
             }
         },
         "node_modules/@typescript-eslint/scope-manager": {
-            "version": "8.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.6.0.tgz",
-            "integrity": "sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==",
+            "version": "8.8.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.8.0.tgz",
+            "integrity": "sha512-EL8eaGC6gx3jDd8GwEFEV091210U97J0jeEHrAYvIYosmEGet4wJ+g0SYmLu+oRiAwbSA5AVrt6DxLHfdd+bUg==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/types": "8.6.0",
-                "@typescript-eslint/visitor-keys": "8.6.0"
+                "@typescript-eslint/types": "8.8.0",
+                "@typescript-eslint/visitor-keys": "8.8.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -10283,14 +10315,14 @@
             }
         },
         "node_modules/@typescript-eslint/type-utils": {
-            "version": "8.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.6.0.tgz",
-            "integrity": "sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==",
+            "version": "8.8.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.8.0.tgz",
+            "integrity": "sha512-IKwJSS7bCqyCeG4NVGxnOP6lLT9Okc3Zj8hLO96bpMkJab+10HIfJbMouLrlpyOr3yrQ1cA413YPFiGd1mW9/Q==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/typescript-estree": "8.6.0",
-                "@typescript-eslint/utils": "8.6.0",
+                "@typescript-eslint/typescript-estree": "8.8.0",
+                "@typescript-eslint/utils": "8.8.0",
                 "debug": "^4.3.4",
                 "ts-api-utils": "^1.3.0"
             },
@@ -10308,9 +10340,9 @@
             }
         },
         "node_modules/@typescript-eslint/types": {
-            "version": "8.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.6.0.tgz",
-            "integrity": "sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==",
+            "version": "8.8.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.8.0.tgz",
+            "integrity": "sha512-QJwc50hRCgBd/k12sTykOJbESe1RrzmX6COk8Y525C9l7oweZ+1lw9JiU56im7Amm8swlz00DRIlxMYLizr2Vw==",
             "dev": true,
             "license": "MIT",
             "engines": {
@@ -10322,14 +10354,14 @@
             }
         },
         "node_modules/@typescript-eslint/typescript-estree": {
-            "version": "8.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.6.0.tgz",
-            "integrity": "sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==",
+            "version": "8.8.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.0.tgz",
+            "integrity": "sha512-ZaMJwc/0ckLz5DaAZ+pNLmHv8AMVGtfWxZe/x2JVEkD5LnmhWiQMMcYT7IY7gkdJuzJ9P14fRy28lUrlDSWYdw==",
             "dev": true,
             "license": "BSD-2-Clause",
             "dependencies": {
-                "@typescript-eslint/types": "8.6.0",
-                "@typescript-eslint/visitor-keys": "8.6.0",
+                "@typescript-eslint/types": "8.8.0",
+                "@typescript-eslint/visitor-keys": "8.8.0",
                 "debug": "^4.3.4",
                 "fast-glob": "^3.3.2",
                 "is-glob": "^4.0.3",
@@ -10380,16 +10412,16 @@
             }
         },
         "node_modules/@typescript-eslint/utils": {
-            "version": "8.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.6.0.tgz",
-            "integrity": "sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==",
+            "version": "8.8.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.8.0.tgz",
+            "integrity": "sha512-QE2MgfOTem00qrlPgyByaCHay9yb1+9BjnMFnSFkUKQfu7adBXDTnCAivURnuPPAG/qiB+kzKkZKmKfaMT0zVg==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
                 "@eslint-community/eslint-utils": "^4.4.0",
-                "@typescript-eslint/scope-manager": "8.6.0",
-                "@typescript-eslint/types": "8.6.0",
-                "@typescript-eslint/typescript-estree": "8.6.0"
+                "@typescript-eslint/scope-manager": "8.8.0",
+                "@typescript-eslint/types": "8.8.0",
+                "@typescript-eslint/typescript-estree": "8.8.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -10403,13 +10435,13 @@
             }
         },
         "node_modules/@typescript-eslint/visitor-keys": {
-            "version": "8.6.0",
-            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.6.0.tgz",
-            "integrity": "sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==",
+            "version": "8.8.0",
+            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.0.tgz",
+            "integrity": "sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/types": "8.6.0",
+                "@typescript-eslint/types": "8.8.0",
                 "eslint-visitor-keys": "^3.4.3"
             },
             "engines": {
@@ -17888,28 +17920,31 @@
             }
         },
         "node_modules/eslint": {
-            "version": "9.10.0",
-            "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.10.0.tgz",
-            "integrity": "sha512-Y4D0IgtBZfOcOUAIQTSXBKoNGfY0REGqHJG6+Q81vNippW5YlKjHFj4soMxamKK1NXHUWuBZTLdU3Km+L/pcHw==",
+            "version": "9.12.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz",
+            "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==",
             "license": "MIT",
             "dependencies": {
                 "@eslint-community/eslint-utils": "^4.2.0",
                 "@eslint-community/regexpp": "^4.11.0",
                 "@eslint/config-array": "^0.18.0",
+                "@eslint/core": "^0.6.0",
                 "@eslint/eslintrc": "^3.1.0",
-                "@eslint/js": "9.10.0",
-                "@eslint/plugin-kit": "^0.1.0",
+                "@eslint/js": "9.12.0",
+                "@eslint/plugin-kit": "^0.2.0",
+                "@humanfs/node": "^0.16.5",
                 "@humanwhocodes/module-importer": "^1.0.1",
-                "@humanwhocodes/retry": "^0.3.0",
-                "@nodelib/fs.walk": "^1.2.8",
+                "@humanwhocodes/retry": "^0.3.1",
+                "@types/estree": "^1.0.6",
+                "@types/json-schema": "^7.0.15",
                 "ajv": "^6.12.4",
                 "chalk": "^4.0.0",
                 "cross-spawn": "^7.0.2",
                 "debug": "^4.3.2",
                 "escape-string-regexp": "^4.0.0",
-                "eslint-scope": "^8.0.2",
-                "eslint-visitor-keys": "^4.0.0",
-                "espree": "^10.1.0",
+                "eslint-scope": "^8.1.0",
+                "eslint-visitor-keys": "^4.1.0",
+                "espree": "^10.2.0",
                 "esquery": "^1.5.0",
                 "esutils": "^2.0.2",
                 "fast-deep-equal": "^3.1.3",
@@ -17919,13 +17954,11 @@
                 "ignore": "^5.2.0",
                 "imurmurhash": "^0.1.4",
                 "is-glob": "^4.0.0",
-                "is-path-inside": "^3.0.3",
                 "json-stable-stringify-without-jsonify": "^1.0.1",
                 "lodash.merge": "^4.6.2",
                 "minimatch": "^3.1.2",
                 "natural-compare": "^1.4.0",
                 "optionator": "^0.9.3",
-                "strip-ansi": "^6.0.1",
                 "text-table": "^0.2.0"
             },
             "bin": {
@@ -17947,9 +17980,9 @@
             }
         },
         "node_modules/eslint-plugin-react": {
-            "version": "7.36.1",
-            "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz",
-            "integrity": "sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA==",
+            "version": "7.37.1",
+            "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.1.tgz",
+            "integrity": "sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
@@ -18019,9 +18052,9 @@
             }
         },
         "node_modules/eslint-scope": {
-            "version": "8.0.2",
-            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz",
-            "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==",
+            "version": "8.1.0",
+            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz",
+            "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==",
             "dependencies": {
                 "esrecurse": "^4.3.0",
                 "estraverse": "^5.2.0"
@@ -18034,9 +18067,9 @@
             }
         },
         "node_modules/eslint-visitor-keys": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
-            "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz",
+            "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==",
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             },
@@ -18160,13 +18193,13 @@
             }
         },
         "node_modules/espree": {
-            "version": "10.1.0",
-            "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz",
-            "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==",
+            "version": "10.2.0",
+            "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz",
+            "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==",
             "dependencies": {
                 "acorn": "^8.12.0",
                 "acorn-jsx": "^5.3.2",
-                "eslint-visitor-keys": "^4.0.0"
+                "eslint-visitor-keys": "^4.1.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -18575,6 +18608,8 @@
             "version": "1.17.1",
             "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
             "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+            "dev": true,
+            "license": "ISC",
             "dependencies": {
                 "reusify": "^1.0.4"
             }
@@ -19708,9 +19743,9 @@
             }
         },
         "node_modules/globals": {
-            "version": "15.9.0",
-            "resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz",
-            "integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==",
+            "version": "15.10.0",
+            "resolved": "https://registry.npmjs.org/globals/-/globals-15.10.0.tgz",
+            "integrity": "sha512-tqFIbz83w4Y5TCbtgjZjApohbuh7K9BxGYFm7ifwDR240tvdb7P9x+/9VvUKlmkPoiknoJtanI8UOrqxS3a7lQ==",
             "dev": true,
             "license": "MIT",
             "engines": {
@@ -21554,14 +21589,6 @@
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
-        "node_modules/is-path-inside": {
-            "version": "3.0.3",
-            "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
-            "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
-            "engines": {
-                "node": ">=8"
-            }
-        },
         "node_modules/is-plain-obj": {
             "version": "4.1.0",
             "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
@@ -28775,6 +28802,7 @@
             "version": "1.2.3",
             "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
             "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+            "dev": true,
             "funding": [
                 {
                     "type": "github",
@@ -28788,7 +28816,8 @@
                     "type": "consulting",
                     "url": "https://feross.org/support"
                 }
-            ]
+            ],
+            "license": "MIT"
         },
         "node_modules/queue-tick": {
             "version": "1.0.1",
@@ -30168,6 +30197,8 @@
             "version": "1.0.4",
             "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
             "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+            "dev": true,
+            "license": "MIT",
             "engines": {
                 "iojs": ">=1.0.0",
                 "node": ">=0.10.0"
@@ -30318,6 +30349,7 @@
             "version": "1.2.0",
             "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
             "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+            "dev": true,
             "funding": [
                 {
                     "type": "github",
@@ -30332,6 +30364,7 @@
                     "url": "https://feross.org/support"
                 }
             ],
+            "license": "MIT",
             "dependencies": {
                 "queue-microtask": "^1.2.2"
             }
@@ -33100,15 +33133,15 @@
             "integrity": "sha512-7sI4e/bZijOzyURng88oOFZCISQPTHozfE2sUu5AviFYk5QV7fYGb6YiDl+vKjF/pICA354JImBImL9XJWUvdQ=="
         },
         "node_modules/typescript-eslint": {
-            "version": "8.6.0",
-            "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.6.0.tgz",
-            "integrity": "sha512-eEhhlxCEpCd4helh3AO1hk0UP2MvbRi9CtIAJTVPQjuSXOOO2jsEacNi4UdcJzZJbeuVg1gMhtZ8UYb+NFYPrA==",
+            "version": "8.8.0",
+            "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.8.0.tgz",
+            "integrity": "sha512-BjIT/VwJ8+0rVO01ZQ2ZVnjE1svFBiRczcpr1t1Yxt7sT25VSbPfrJtDsQ8uQTy2pilX5nI9gwxhUyLULNentw==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
-                "@typescript-eslint/eslint-plugin": "8.6.0",
-                "@typescript-eslint/parser": "8.6.0",
-                "@typescript-eslint/utils": "8.6.0"
+                "@typescript-eslint/eslint-plugin": "8.8.0",
+                "@typescript-eslint/parser": "8.8.0",
+                "@typescript-eslint/utils": "8.8.0"
             },
             "engines": {
                 "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
diff --git a/package.json b/package.json
index 8646a1d7f..4f133e3d6 100644
--- a/package.json
+++ b/package.json
@@ -73,9 +73,9 @@
         "@types/youtube": "^0.1.0",
         "chai": "^5.0.0",
         "cross-env": "^7.0.3",
-        "eslint": "^9.10.0",
-        "eslint-plugin-react": "^7.36.1",
-        "globals": "^15.9.0",
+        "eslint": "^9.12.0",
+        "eslint-plugin-react": "^7.37.1",
+        "globals": "^15.10.0",
         "jsdom": "^25.0.0",
         "mocha": "^10.2.0",
         "prettier": "^3.1.0",
@@ -84,7 +84,7 @@
         "ts-loader": "^9.5.1",
         "ts-node": "^10.9.1",
         "ts-node-dev": "^2.0.0",
-        "typescript-eslint": "^8.6.0",
+        "typescript-eslint": "^8.8.0",
         "webpack-dev-server": "^5.0.4"
     },
     "dependencies": {
@@ -311,8 +311,8 @@
         "string-similarity": "^4.0.4",
         "styled-components": "^6.1.1",
         "supercluster": "^8.0.1",
-        "tesseract.js": "^5.1.0",
         "svgson": "^5.3.1",
+        "tesseract.js": "^5.1.0",
         "textarea-caret": "^3.1.0",
         "textfit": "^2.4.0",
         "tough-cookie": "^5.0.0",
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 2c0a102f5..25e76e2a6 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -299,32 +299,15 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         this.Document[DocData].phoneticTranscription = response.data['transcription'];
     };
 
-    youtubeUpload = async () => {
-        console.log('Here');
-        const audio = {
-            file: 'Cd2ch4XV84s&t=373s',
-        };
-        const response = await axios.post('http://localhost:105/youtube/', audio, {
-            headers: {
-                'Content-Type': 'application/json',
-            },
-        });
-    };
-
     // context menu
     specificContextMenu = (): void => {
         const funcs: ContextMenuProps[] = [];
 
-        funcs.push({
-            description: 'Youtube',
-            event: this.youtubeUpload, // prettier-ignore
-            icon: 'expand-arrows-alt',
-        });
         funcs.push({
             description: (this.layoutDoc.hideAnchors ? "Don't hide" : 'Hide') + ' anchors',
             event: () => { this.layoutDoc.hideAnchors = !this.layoutDoc.hideAnchors; }, // prettier-ignore
             icon: 'expand-arrows-alt',
-        });
+        }); //
         funcs.push({
             description: (this.layoutDoc.dontAutoFollowLinks ? '' : "Don't") + ' follow links when encountered',
             event: () => { this.layoutDoc.dontAutoFollowLinks = !this.layoutDoc.dontAutoFollowLinks}, // prettier-ignore
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 9fb8bc4d6..e686368e9 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -528,12 +528,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
      */
     askGPTPhonemes = async (phonemes: string) => {
         const sentence = StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text);
-        const phon = 'w ʌ ɪ z j ɔː ɹ n e ɪ m ';
-        const phon2 = 'h ʌ ɛ r j ʌ t ʌ d eɪ';
         const phon6 = 'huː ɑɹ juː tədeɪ';
-        const phon3 = 'ʃ eɪ oʊ s i ʃ oʊ z b aɪ ð ə s iː ʃ oʊ';
         const phon4 = 'kamo estas hɔi';
-        const phon5 = 'la s e n a l';
         const promptEng =
             'Consider all possible phonetic transcriptions of the intended sentence "' +
             sentence +
@@ -575,14 +571,11 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
      * @param e
      */
     handleResult = (e: SpeechRecognitionEvent) => {
-        let interimTranscript = '';
         let finalTranscript = '';
         for (let i = e.resultIndex; i < e.results.length; i++) {
             const transcript = e.results[i][0].transcript;
             if (e.results[i].isFinal) {
                 finalTranscript += transcript;
-            } else {
-                interimTranscript += transcript;
             }
         }
         this._inputValue += finalTranscript;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 31f6df2ea..0571351f0 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -192,7 +192,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
     handleSelection = async (selection: string) => {
         this._searchInput = selection;
-        const images = await this.fetchImages();
     };
 
     drop = undoable((e: Event, de: DragManager.DropEvent) => {
-- 
cgit v1.2.3-70-g09d2

